v2sim 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- v2sim-1.3.0/.gitignore +39 -0
- v2sim-1.3.0/LICENSE +29 -0
- v2sim-1.3.0/PKG-INFO +73 -0
- v2sim-1.3.0/README.md +48 -0
- v2sim-1.3.0/pyproject.toml +39 -0
- v2sim-1.3.0/v2sim/__init__.py +21 -0
- v2sim-1.3.0/v2sim/gui/cmpbox/__init__.py +152 -0
- v2sim-1.3.0/v2sim/gui/cmpbox/_lang/en_US.lang +14 -0
- v2sim-1.3.0/v2sim/gui/cmpbox/_lang/zh_CN.lang +14 -0
- v2sim-1.3.0/v2sim/gui/com_no_vx.py +33 -0
- v2sim-1.3.0/v2sim/gui/common.py +5 -0
- v2sim-1.3.0/v2sim/gui/evtq.py +100 -0
- v2sim-1.3.0/v2sim/gui/langhelper.py +34 -0
- v2sim-1.3.0/v2sim/gui/mainbox/__init__.py +991 -0
- v2sim-1.3.0/v2sim/gui/mainbox/_lang/en.lang +157 -0
- v2sim-1.3.0/v2sim/gui/mainbox/_lang/zh_CN.lang +157 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/__init__.py +9 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/_lang/en.lang +34 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/_lang/zh_CN.lang +34 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/lipad.py +57 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/network.py +710 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/pdfe.py +65 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/prope.py +82 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/rle.py +82 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/scrtv.py +290 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/sfe.py +79 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/sid.py +48 -0
- v2sim-1.3.0/v2sim/gui/mainbox/controls/utils.py +40 -0
- v2sim-1.3.0/v2sim/gui/mainbox/cscsveditor.py +80 -0
- v2sim-1.3.0/v2sim/gui/mainbox/cseditor.py +375 -0
- v2sim-1.3.0/v2sim/gui/mainbox/loadingbox.py +33 -0
- v2sim-1.3.0/v2sim/gui/mainbox/plugin.py +68 -0
- v2sim-1.3.0/v2sim/gui/mainbox/utils.py +42 -0
- v2sim-1.3.0/v2sim/gui/parabox/__init__.py +172 -0
- v2sim-1.3.0/v2sim/gui/parabox/_lang/en.lang +51 -0
- v2sim-1.3.0/v2sim/gui/parabox/_lang/zh_CN.lang +51 -0
- v2sim-1.3.0/v2sim/gui/parabox/lgb.py +78 -0
- v2sim-1.3.0/v2sim/gui/parabox/pareditor.py +53 -0
- v2sim-1.3.0/v2sim/gui/parabox/utils.py +33 -0
- v2sim-1.3.0/v2sim/gui/plgbox/__init__.py +150 -0
- v2sim-1.3.0/v2sim/gui/plgbox/_lang/en_US.lang +19 -0
- v2sim-1.3.0/v2sim/gui/plgbox/_lang/zh_CN.lang +19 -0
- v2sim-1.3.0/v2sim/gui/progbox/__init__.py +45 -0
- v2sim-1.3.0/v2sim/gui/v2sim.png +0 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/__init__.py +465 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/_lang/en_US.lang +95 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/_lang/zh_CN.lang +95 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/gridpage.py +89 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/optbox.py +46 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/plotpad.py +45 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/plotpage.py +225 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/srd.py +39 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/statepage.py +104 -0
- v2sim-1.3.0/v2sim/gui/viewerbox/trips.py +284 -0
- v2sim-1.3.0/v2sim/gui/welcomebox/__init__.py +225 -0
- v2sim-1.3.0/v2sim/gui/welcomebox/_lang/en_US.lang +22 -0
- v2sim-1.3.0/v2sim/gui/welcomebox/_lang/zh_CN.lang +22 -0
- v2sim-1.3.0/v2sim/gui/welcomebox/v2sim.png +0 -0
- v2sim-1.3.0/v2sim/locale/__init__.py +1 -0
- v2sim-1.3.0/v2sim/locale/lang.py +264 -0
- v2sim-1.3.0/v2sim/locale/zh_CN.py +207 -0
- v2sim-1.3.0/v2sim/osmhelper/__init__.py +1 -0
- v2sim-1.3.0/v2sim/osmhelper/osmBuild.py +140 -0
- v2sim-1.3.0/v2sim/osmhelper/osmGet.py +324 -0
- v2sim-1.3.0/v2sim/osmhelper/osmWebWizard.py +551 -0
- v2sim-1.3.0/v2sim/osmhelper/ptlines2flows.py +610 -0
- v2sim-1.3.0/v2sim/osmhelper/readme.md +2 -0
- v2sim-1.3.0/v2sim/osmhelper/tileGet.py +283 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/navteqPolyconvert.typ.xml +9 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/opendriveNetconvert.typ.xml +35 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/opendriveNetconvertBicycle.typ.xml +3 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/opendriveNetconvertPedestrians.typ.xml +3 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvert.typ.xml +45 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertAerialway.typ.xml +5 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertAirport.typ.xml +9 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertBicycle.typ.xml +6 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertBidiRail.typ.xml +7 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertExtraRail.typ.xml +5 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertPedestrians.typ.xml +10 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertPedestriansNES.typ.xml +11 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertRailUsage.typ.xml +17 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertShips.typ.xml +5 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmNetconvertUrbanDe.typ.xml +13 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmPolyconvert.typ.xml +66 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/osmPolyconvertRail.typ.xml +50 -0
- v2sim-1.3.0/v2sim/osmhelper/typemap/visumPolyconvert.typ.xml +8 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/SimpleWebSocketServer.py +716 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/__init__.py +17 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/bicycle.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/bus.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/favicon.ico +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/generate.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/map.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/motorcycle.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/passenger.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/pedestrian.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/rail.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/rail_urban.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/road.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/ship.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/tram.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/images/truck.png +0 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/index.html +138 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/jquery-3.5.1.min.js +2 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/lib.js +62 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/script.js +540 -0
- v2sim-1.3.0/v2sim/osmhelper/webWizard/style.css +214 -0
- v2sim-1.3.0/v2sim/plotkit/__init__.py +2 -0
- v2sim-1.3.0/v2sim/plotkit/example.txt +16 -0
- v2sim-1.3.0/v2sim/plotkit/plot.py +728 -0
- v2sim-1.3.0/v2sim/plotkit/reader.py +251 -0
- v2sim-1.3.0/v2sim/plugins/__init__.py +9 -0
- v2sim-1.3.0/v2sim/plugins/base.py +278 -0
- v2sim-1.3.0/v2sim/plugins/ocur.py +94 -0
- v2sim-1.3.0/v2sim/plugins/pdn.py +182 -0
- v2sim-1.3.0/v2sim/plugins/pool.py +158 -0
- v2sim-1.3.0/v2sim/plugins/v2g.py +91 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/H.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/H_spr.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/H_spr_weekday.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/H_spr_weekend.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/O_spr.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/O_spr_weekday.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/O_spr_weekend.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/R_spr.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/R_spr_weekday.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/R_spr_weekend.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/W_spr.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/W_spr_weekday.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/duration_of_parking/W_spr_weekend.csv +96 -0
- v2sim-1.3.0/v2sim/probtable/ev_types.csv +7 -0
- v2sim-1.3.0/v2sim/probtable/soc_dist.csv +101 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/H_spr_weekday.csv +5 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/H_spr_weekend.csv +5 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/O_spr_weekday.csv +5 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/O_spr_weekend.csv +5 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/R_spr_weekday.csv +5 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/R_spr_weekend.csv +5 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/W_spr_weekday.csv +5 -0
- v2sim-1.3.0/v2sim/probtable/space_transfer_probability/W_spr_weekend.csv +5 -0
- v2sim-1.3.0/v2sim/sim_core.py +744 -0
- v2sim-1.3.0/v2sim/statistics/__init__.py +10 -0
- v2sim-1.3.0/v2sim/statistics/base.py +81 -0
- v2sim-1.3.0/v2sim/statistics/logcs.py +75 -0
- v2sim-1.3.0/v2sim/statistics/logev.py +45 -0
- v2sim-1.3.0/v2sim/statistics/loggr.py +174 -0
- v2sim-1.3.0/v2sim/statistics/manager.py +210 -0
- v2sim-1.3.0/v2sim/tools/cmd_advplot.py +24 -0
- v2sim-1.3.0/v2sim/tools/cmd_csquery.py +24 -0
- v2sim-1.3.0/v2sim/tools/cmd_gen_cs.py +27 -0
- v2sim-1.3.0/v2sim/tools/cmd_gen_trip.py +29 -0
- v2sim-1.3.0/v2sim/tools/cmd_plot.py +198 -0
- v2sim-1.3.0/v2sim/tools/gui_cmp.py +6 -0
- v2sim-1.3.0/v2sim/tools/gui_main.py +44 -0
- v2sim-1.3.0/v2sim/tools/gui_osm.py +7 -0
- v2sim-1.3.0/v2sim/tools/gui_para.py +5 -0
- v2sim-1.3.0/v2sim/tools/gui_plgman.py +10 -0
- v2sim-1.3.0/v2sim/tools/gui_viewer.py +5 -0
- v2sim-1.3.0/v2sim/tools/sim_para.py +278 -0
- v2sim-1.3.0/v2sim/tools/sim_single.py +122 -0
- v2sim-1.3.0/v2sim/traffic/__init__.py +9 -0
- v2sim-1.3.0/v2sim/traffic/cs.py +672 -0
- v2sim-1.3.0/v2sim/traffic/cslist.py +336 -0
- v2sim-1.3.0/v2sim/traffic/ev.py +460 -0
- v2sim-1.3.0/v2sim/traffic/evdict.py +85 -0
- v2sim-1.3.0/v2sim/traffic/inst.py +712 -0
- v2sim-1.3.0/v2sim/traffic/net.py +390 -0
- v2sim-1.3.0/v2sim/traffic/params.py +81 -0
- v2sim-1.3.0/v2sim/traffic/seg.py +231 -0
- v2sim-1.3.0/v2sim/traffic/trip.py +435 -0
- v2sim-1.3.0/v2sim/traffic/utils.py +345 -0
- v2sim-1.3.0/v2sim/traffic/win_vis.py +1 -0
- v2sim-1.3.0/v2sim/trafficgen/__init__.py +9 -0
- v2sim-1.3.0/v2sim/trafficgen/core.py +508 -0
- v2sim-1.3.0/v2sim/trafficgen/csquery.py +213 -0
- v2sim-1.3.0/v2sim/trafficgen/misc.py +214 -0
- v2sim-1.3.0/v2sim/trafficgen/poly.py +67 -0
- v2sim-1.3.0/v2sim/trafficgen/tripgen.py +440 -0
v2sim-1.3.0/.gitignore
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Compiled source
|
|
2
|
+
__pycache__
|
|
3
|
+
.idea
|
|
4
|
+
.vscode
|
|
5
|
+
.venv
|
|
6
|
+
|
|
7
|
+
# Temporary files
|
|
8
|
+
_sim_temp
|
|
9
|
+
temp
|
|
10
|
+
saved_state
|
|
11
|
+
*.old.*
|
|
12
|
+
buf.csv
|
|
13
|
+
|
|
14
|
+
# Sensitive files
|
|
15
|
+
amap_key.txt
|
|
16
|
+
v2sim/locale/lang.txt
|
|
17
|
+
*.json
|
|
18
|
+
preference.v2simcfg
|
|
19
|
+
recent_projects.txt
|
|
20
|
+
|
|
21
|
+
# Logs
|
|
22
|
+
*.log
|
|
23
|
+
*results*
|
|
24
|
+
profiling
|
|
25
|
+
perf*
|
|
26
|
+
|
|
27
|
+
# Cases
|
|
28
|
+
*.veh.xml*
|
|
29
|
+
*.bat
|
|
30
|
+
*.bak
|
|
31
|
+
deploy
|
|
32
|
+
cases/*
|
|
33
|
+
!cases/std_*
|
|
34
|
+
!cases/pwe_*
|
|
35
|
+
|
|
36
|
+
# Setup files
|
|
37
|
+
build
|
|
38
|
+
dist
|
|
39
|
+
*.egg-info
|
v2sim-1.3.0/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024, fmy-xfk
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
v2sim-1.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: v2sim
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: V2Sim: An Open-Source Microscopic V2G Simulation Platform in Urban Power and Transportation Network
|
|
5
|
+
Project-URL: Homepage, https://github.com/fmy-xfk/v2sim
|
|
6
|
+
Project-URL: Documentation, https://github.com/fmy-xfk/v2sim/wiki
|
|
7
|
+
Project-URL: Repository, https://github.com/fmy-xfk/v2sim.git
|
|
8
|
+
Project-URL: Issues, https://github.com/fmy-xfk/v2sim/issues
|
|
9
|
+
License-Expression: BSD-3-Clause
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Requires-Dist: feasytools>=0.1.4
|
|
13
|
+
Requires-Dist: fpowerkit>=0.3.4
|
|
14
|
+
Requires-Dist: libsumo
|
|
15
|
+
Requires-Dist: matplotlib
|
|
16
|
+
Requires-Dist: numba
|
|
17
|
+
Requires-Dist: numpy
|
|
18
|
+
Requires-Dist: pyproj
|
|
19
|
+
Requires-Dist: requests
|
|
20
|
+
Requires-Dist: scikit-learn
|
|
21
|
+
Provides-Extra: v2g
|
|
22
|
+
Requires-Dist: cvxpy; extra == 'v2g'
|
|
23
|
+
Requires-Dist: ecos; extra == 'v2g'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# V2Sim Family
|
|
27
|
+
|
|
28
|
+
> Open-Source V2G Simulation Platform in Urban Power and Transportation Network
|
|
29
|
+
|
|
30
|
+
**Documents:** http://v2sim.heslab.wiki (Backup links: [HTTPS Link](https://hesl-seu.github.io/v2sim-wiki) | [CN Mirror 中文镜像](https://v2sim.myfrank.cn/#/zh_hans/))
|
|
31
|
+
|
|
32
|
+
V2Sim family includes several open-source software for coupled urban power and transportation network. They are different in the transportation simulation part.
|
|
33
|
+
|
|
34
|
+
+ **V2Sim**: Use SUMO for **MICROSCOPIC** traffic simulation. It could identify the microscopic motion of a single vehicle, including its lane, speed, accerlation, etc. This version is suitable if your research concerns the implication of delicate motion of EVs on power grid. (Please scroll down to read instructions.)
|
|
35
|
+
|
|
36
|
+
+ **V2Sim-UX**: Use uxsim for **MESOCOPIC** traffic simulation. It runs very fast with free-threading Python (3.14+). This version is suitable if your research need fast iterations and focus on the overall implication of the traffic flow. (Link: [V2Sim-UX](https://github.com/hesl-seu/v2sim/tree/uxsim))
|
|
37
|
+
|
|
38
|
+
If you are using V2Sim family, please cite the paper:
|
|
39
|
+
```
|
|
40
|
+
@ARTICLE{10970754,
|
|
41
|
+
author={Qian, Tao and Fang, Mingyu and Hu, Qinran and Shao, Chengcheng and Zheng, Junyi},
|
|
42
|
+
journal={IEEE Transactions on Smart Grid},
|
|
43
|
+
title={V2Sim: An Open-Source Microscopic V2G Simulation Platform in Urban Power and Transportation Network},
|
|
44
|
+
year={2025},
|
|
45
|
+
volume={16},
|
|
46
|
+
number={4},
|
|
47
|
+
pages={3167-3178},
|
|
48
|
+
keywords={Vehicle-to-grid;Partial discharges;Microscopy;Batteries;Planning;Discharges (electric);Optimization;Vehicle dynamics;Transportation;Roads;EV charging load simulation;microscopic EV behavior;vehicle-to-grid;charging station fault sensing},
|
|
49
|
+
doi={10.1109/TSG.2025.3560976}}
|
|
50
|
+
```
|
|
51
|
+
Paper link for the microscopic version: https://ieeexplore.ieee.org/document/10970754
|
|
52
|
+
|
|
53
|
+
## V2Sim: The Microscopic Version
|
|
54
|
+
|
|
55
|
+
V2Sim is a microscopic V2G simulation platform in urban power and transportation network. It is open-source under BSD license.
|
|
56
|
+
|
|
57
|
+
+ **Note**: Current code of V2Sim is ahead of the paper described. The exact older code used in the paper is [here](https://github.com/fmy-xfk/v2sim/commit/940ebd5d988f53fde90f4d83d107f136334952f9). The code used in [arXiv](https://arxiv.org/abs/2412.09808) is the initial commit.
|
|
58
|
+
|
|
59
|
+
+ **Note 2**: Code of PDN part is not included in the repository, it is stored in another repository: [FPowerKit](https://gitee.com/fmy_xfk/fpowerkit).
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
This package has been uploaded to PyPI. It can be installed by:
|
|
63
|
+
```
|
|
64
|
+
pip install v2sim
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Then, input the following command to open the GUI:
|
|
68
|
+
```
|
|
69
|
+
v2sim-gui
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Visit our documents to see the quick start guide!
|
|
73
|
+
Link: https://hesl-seu.github.io/v2sim-wiki/#/v2sim/quick-start (English)
|
v2sim-1.3.0/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# V2Sim Family
|
|
2
|
+
|
|
3
|
+
> Open-Source V2G Simulation Platform in Urban Power and Transportation Network
|
|
4
|
+
|
|
5
|
+
**Documents:** http://v2sim.heslab.wiki (Backup links: [HTTPS Link](https://hesl-seu.github.io/v2sim-wiki) | [CN Mirror 中文镜像](https://v2sim.myfrank.cn/#/zh_hans/))
|
|
6
|
+
|
|
7
|
+
V2Sim family includes several open-source software for coupled urban power and transportation network. They are different in the transportation simulation part.
|
|
8
|
+
|
|
9
|
+
+ **V2Sim**: Use SUMO for **MICROSCOPIC** traffic simulation. It could identify the microscopic motion of a single vehicle, including its lane, speed, accerlation, etc. This version is suitable if your research concerns the implication of delicate motion of EVs on power grid. (Please scroll down to read instructions.)
|
|
10
|
+
|
|
11
|
+
+ **V2Sim-UX**: Use uxsim for **MESOCOPIC** traffic simulation. It runs very fast with free-threading Python (3.14+). This version is suitable if your research need fast iterations and focus on the overall implication of the traffic flow. (Link: [V2Sim-UX](https://github.com/hesl-seu/v2sim/tree/uxsim))
|
|
12
|
+
|
|
13
|
+
If you are using V2Sim family, please cite the paper:
|
|
14
|
+
```
|
|
15
|
+
@ARTICLE{10970754,
|
|
16
|
+
author={Qian, Tao and Fang, Mingyu and Hu, Qinran and Shao, Chengcheng and Zheng, Junyi},
|
|
17
|
+
journal={IEEE Transactions on Smart Grid},
|
|
18
|
+
title={V2Sim: An Open-Source Microscopic V2G Simulation Platform in Urban Power and Transportation Network},
|
|
19
|
+
year={2025},
|
|
20
|
+
volume={16},
|
|
21
|
+
number={4},
|
|
22
|
+
pages={3167-3178},
|
|
23
|
+
keywords={Vehicle-to-grid;Partial discharges;Microscopy;Batteries;Planning;Discharges (electric);Optimization;Vehicle dynamics;Transportation;Roads;EV charging load simulation;microscopic EV behavior;vehicle-to-grid;charging station fault sensing},
|
|
24
|
+
doi={10.1109/TSG.2025.3560976}}
|
|
25
|
+
```
|
|
26
|
+
Paper link for the microscopic version: https://ieeexplore.ieee.org/document/10970754
|
|
27
|
+
|
|
28
|
+
## V2Sim: The Microscopic Version
|
|
29
|
+
|
|
30
|
+
V2Sim is a microscopic V2G simulation platform in urban power and transportation network. It is open-source under BSD license.
|
|
31
|
+
|
|
32
|
+
+ **Note**: Current code of V2Sim is ahead of the paper described. The exact older code used in the paper is [here](https://github.com/fmy-xfk/v2sim/commit/940ebd5d988f53fde90f4d83d107f136334952f9). The code used in [arXiv](https://arxiv.org/abs/2412.09808) is the initial commit.
|
|
33
|
+
|
|
34
|
+
+ **Note 2**: Code of PDN part is not included in the repository, it is stored in another repository: [FPowerKit](https://gitee.com/fmy_xfk/fpowerkit).
|
|
35
|
+
|
|
36
|
+
## Quick start
|
|
37
|
+
This package has been uploaded to PyPI. It can be installed by:
|
|
38
|
+
```
|
|
39
|
+
pip install v2sim
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then, input the following command to open the GUI:
|
|
43
|
+
```
|
|
44
|
+
v2sim-gui
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Visit our documents to see the quick start guide!
|
|
48
|
+
Link: https://hesl-seu.github.io/v2sim-wiki/#/v2sim/quick-start (English)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [ "hatchling",]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "v2sim"
|
|
7
|
+
version = "1.3.0"
|
|
8
|
+
dependencies = [ "libsumo", "numpy", "matplotlib", "feasytools>=0.1.4", "fpowerkit>=0.3.4", "pyproj", "requests", "scikit-learn", "numba",]
|
|
9
|
+
requires-python = ">= 3.8"
|
|
10
|
+
license = "BSD-3-Clause"
|
|
11
|
+
description = "V2Sim: An Open-Source Microscopic V2G Simulation Platform in Urban Power and Transportation Network"
|
|
12
|
+
|
|
13
|
+
[project.readme]
|
|
14
|
+
file = "README.md"
|
|
15
|
+
content-type = "text/markdown"
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
v2g = [ "ecos", "cvxpy",]
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
v2sim-gui = "v2sim.tools.gui_main:main"
|
|
22
|
+
v2sim = "v2sim.tools.sim_single:work"
|
|
23
|
+
v2sim-para = "v2sim.tools.sim_para:main"
|
|
24
|
+
v2sim-advplot = "v2sim.tools.cmd_advplot:main"
|
|
25
|
+
v2sim-convert = "v2sim.tools.cmd_convert:main"
|
|
26
|
+
v2sim-csquery = "v2sim.tools.cmd_csquery:main"
|
|
27
|
+
v2sim-gen-cs = "v2sim.tools.cmd_gen_cs:main"
|
|
28
|
+
v2sim-gen-trip = "v2sim.tools.cmd_gen_trip:main"
|
|
29
|
+
v2sim-plot = "v2sim.tools.cmd_plot:main"
|
|
30
|
+
v2sim-osm = "v2sim.tools.gui_osm:entry"
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/fmy-xfk/v2sim"
|
|
34
|
+
Documentation = "https://github.com/fmy-xfk/v2sim/wiki"
|
|
35
|
+
Repository = "https://github.com/fmy-xfk/v2sim.git"
|
|
36
|
+
Issues = "https://github.com/fmy-xfk/v2sim/issues"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build]
|
|
39
|
+
include = [ "v2sim/*",]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from .locale import *
|
|
2
|
+
from .traffic import *
|
|
3
|
+
from .trafficgen import *
|
|
4
|
+
from .plotkit import *
|
|
5
|
+
from .plugins import *
|
|
6
|
+
from .statistics import *
|
|
7
|
+
from .sim_core import (
|
|
8
|
+
load_external_components,
|
|
9
|
+
get_sim_params,
|
|
10
|
+
simulate_multi,
|
|
11
|
+
simulate_single,
|
|
12
|
+
V2SimInstance,
|
|
13
|
+
MsgPack,
|
|
14
|
+
PLUGINS_FILE,
|
|
15
|
+
RESULTS_FOLDER,
|
|
16
|
+
TRIP_EVENT_LOG,
|
|
17
|
+
SIM_INFO_LOG,
|
|
18
|
+
PLUGINS_DIR,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__version__ = "1.3.0"
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
from v2sim.gui.com_no_vx import *
|
|
2
|
+
from v2sim.gui.langhelper import *
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
from PIL import Image, ImageTk
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
_ = LangLib.Load(__file__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CmpBox(Tk):
|
|
12
|
+
def __init__(self):
|
|
13
|
+
super().__init__()
|
|
14
|
+
|
|
15
|
+
self.title(_("TITLE"))
|
|
16
|
+
self.geometry("1024x768")
|
|
17
|
+
self.bind("<Configure>", self.on_resize)
|
|
18
|
+
|
|
19
|
+
self.folder1 = None
|
|
20
|
+
self.folder2 = None
|
|
21
|
+
self.original_image1 = None
|
|
22
|
+
self.original_image2 = None
|
|
23
|
+
self.folder_buf = "./results"
|
|
24
|
+
|
|
25
|
+
self.create_widgets()
|
|
26
|
+
|
|
27
|
+
def create_widgets(self):
|
|
28
|
+
self.menu = Menu(self)
|
|
29
|
+
self.config(menu=self.menu)
|
|
30
|
+
self.filemenu = Menu(self.menu, tearoff=0)
|
|
31
|
+
self.filemenu.add_command(label=_("OPEN_FOLDER1"), command=self.open_folder1)
|
|
32
|
+
self.filemenu.add_command(label=_("OPEN_FOLDER2"), command=self.open_folder2)
|
|
33
|
+
self.filemenu.add_separator()
|
|
34
|
+
self.filemenu.add_command(label=_("EXIT"), command=self.destroy)
|
|
35
|
+
self.menu.add_cascade(label=_("FILE"), menu=self.filemenu)
|
|
36
|
+
add_lang_menu(self.menu)
|
|
37
|
+
|
|
38
|
+
self.sidebar = Frame(self)
|
|
39
|
+
self.sidebar.pack(side=LEFT, fill=Y)
|
|
40
|
+
|
|
41
|
+
self.folder1_button = Button(self.sidebar, text=_("OPEN_FOLDER1"), command=self.open_folder1)
|
|
42
|
+
self.folder1_button.pack(pady=10)
|
|
43
|
+
|
|
44
|
+
self.folder2_button = Button(self.sidebar, text=_("OPEN_FOLDER2"), command=self.open_folder2)
|
|
45
|
+
self.folder2_button.pack(pady=10)
|
|
46
|
+
|
|
47
|
+
self.folder1_label = Label(self.sidebar, text=_("LB_FOLDER1").format(_("TO_BE_SELECTED")))
|
|
48
|
+
self.folder1_label.pack(pady=10)
|
|
49
|
+
|
|
50
|
+
self.folder2_label = Label(self.sidebar, text=_("LB_FOLDER2").format(_("TO_BE_SELECTED")))
|
|
51
|
+
self.folder2_label.pack(pady=10)
|
|
52
|
+
|
|
53
|
+
self.file_listbox = Listbox(self.sidebar)
|
|
54
|
+
self.file_listbox.pack(fill=BOTH, expand=True, pady=10)
|
|
55
|
+
self.file_listbox.bind("<<ListboxSelect>>", self.on_file_select)
|
|
56
|
+
|
|
57
|
+
self.image_frame = Frame(self)
|
|
58
|
+
self.image_frame.pack(side=RIGHT, fill=X, expand=True)
|
|
59
|
+
|
|
60
|
+
self.image1_label = Label(self.image_frame)
|
|
61
|
+
self.image1_label.pack(side=TOP, padx=10, pady=10)
|
|
62
|
+
|
|
63
|
+
self.image2_label = Label(self.image_frame)
|
|
64
|
+
self.image2_label.pack(side=TOP, padx=10, pady=10)
|
|
65
|
+
|
|
66
|
+
def open_folder1(self):
|
|
67
|
+
new_folder = filedialog.askdirectory(initialdir=self.folder_buf, title=_("AD_TITLE1"))
|
|
68
|
+
if new_folder:
|
|
69
|
+
folder_fig = os.path.join(new_folder, "figures")
|
|
70
|
+
if os.path.exists(folder_fig):
|
|
71
|
+
self.folder1 = folder_fig
|
|
72
|
+
self.folder1_label.config(text=_("LB_FOLDER1").format(os.path.basename(new_folder)))
|
|
73
|
+
self.update_file_list()
|
|
74
|
+
self.folder_buf = str(Path(new_folder).parent)
|
|
75
|
+
else:
|
|
76
|
+
MB.showerror(_("ERROR"), _("NO_FIG"))
|
|
77
|
+
|
|
78
|
+
def open_folder2(self):
|
|
79
|
+
new_folder = filedialog.askdirectory(initialdir=self.folder_buf, title=_("AD_TITLE2"))
|
|
80
|
+
if new_folder:
|
|
81
|
+
folder_fig = os.path.join(new_folder, "figures")
|
|
82
|
+
if os.path.exists(folder_fig):
|
|
83
|
+
self.folder2 = folder_fig
|
|
84
|
+
self.folder2_label.config(text=_("LB_FOLDER2").format(os.path.basename(new_folder)))
|
|
85
|
+
self.update_file_list()
|
|
86
|
+
self.folder_buf = str(Path(new_folder).parent)
|
|
87
|
+
else:
|
|
88
|
+
MB.showerror(_("ERROR"), _("NO_FIG"))
|
|
89
|
+
|
|
90
|
+
def update_file_list(self):
|
|
91
|
+
self.file_listbox.delete(0, END)
|
|
92
|
+
if self.folder1 and self.folder2:
|
|
93
|
+
files1 = set(os.listdir(self.folder1))
|
|
94
|
+
files2 = set(os.listdir(self.folder2))
|
|
95
|
+
common_files = files1.union(files2)
|
|
96
|
+
for file in sorted(common_files):
|
|
97
|
+
if file.lower().endswith(('png', 'jpg', 'jpeg', 'gif')): # 只列出图片文件
|
|
98
|
+
self.file_listbox.insert(END, file)
|
|
99
|
+
|
|
100
|
+
def on_file_select(self, event):
|
|
101
|
+
selected_index = self.file_listbox.curselection()
|
|
102
|
+
if selected_index:
|
|
103
|
+
file_name = self.file_listbox.get(selected_index)
|
|
104
|
+
self.display_images(file_name)
|
|
105
|
+
|
|
106
|
+
def resize(self):
|
|
107
|
+
sz = (self.winfo_width() - 200, self.winfo_height() // 2 - 20)
|
|
108
|
+
if self.original_image1 is not None:
|
|
109
|
+
resized_image1 = self.original_image1.copy()
|
|
110
|
+
resized_image1.thumbnail(sz)
|
|
111
|
+
image1 = ImageTk.PhotoImage(resized_image1)
|
|
112
|
+
|
|
113
|
+
self.image1_label.config(image=image1,text="")
|
|
114
|
+
self.image1 = image1
|
|
115
|
+
else:
|
|
116
|
+
self.image1_label.config(image='',text=_("NO_IMAGE"))
|
|
117
|
+
self.image1 = None
|
|
118
|
+
|
|
119
|
+
if self.original_image2 is not None:
|
|
120
|
+
resized_image2 = self.original_image2.copy()
|
|
121
|
+
resized_image2.thumbnail(sz)
|
|
122
|
+
image2 = ImageTk.PhotoImage(resized_image2)
|
|
123
|
+
|
|
124
|
+
self.image2_label.config(image=image2,text="")
|
|
125
|
+
self.image2 = image2
|
|
126
|
+
else:
|
|
127
|
+
self.image2_label.config(image='',text=_("NO_IMAGE"))
|
|
128
|
+
self.image2 = None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def on_resize(self, event):
|
|
132
|
+
self.resize()
|
|
133
|
+
|
|
134
|
+
def display_images(self, file_name:str):
|
|
135
|
+
if self.folder1 is None: return
|
|
136
|
+
img1_path = os.path.join(self.folder1, file_name)
|
|
137
|
+
if self.folder2 is None: return
|
|
138
|
+
img2_path = os.path.join(self.folder2, file_name)
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
if os.path.exists(img1_path):
|
|
142
|
+
self.original_image1 = Image.open(img1_path)
|
|
143
|
+
else:
|
|
144
|
+
self.original_image1 = None
|
|
145
|
+
if os.path.exists(img2_path):
|
|
146
|
+
self.original_image2 = Image.open(img2_path)
|
|
147
|
+
else:
|
|
148
|
+
self.original_image2 = None
|
|
149
|
+
except Exception as e:
|
|
150
|
+
MB.showerror(_("ERROR"), _("LOAD_FAILED").format(str(e)))
|
|
151
|
+
|
|
152
|
+
self.resize()
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
TITLE=Case comparer
|
|
2
|
+
ERROR=Error
|
|
3
|
+
OPEN_FOLDER1=Open folder 1
|
|
4
|
+
OPEN_FOLDER2=Open folder 2
|
|
5
|
+
TO_BE_SELECTED=(To be selected)
|
|
6
|
+
LB_FOLDER1=Folder 1: {}
|
|
7
|
+
LB_FOLDER2=Folder 2: {}
|
|
8
|
+
AD_TITLE1=Select folder 1
|
|
9
|
+
AD_TITLE2=Select folder 2
|
|
10
|
+
NO_FIG=No 'figures' folder in the selected folder! Please plot the data with gui_viewer.py first!
|
|
11
|
+
LOAD_FAILED=Cannot load image: {}
|
|
12
|
+
NO_IMAGE=(No image)
|
|
13
|
+
EXIT=Exit
|
|
14
|
+
FILE=File
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
TITLE=案例比较器
|
|
2
|
+
ERROR=错误
|
|
3
|
+
OPEN_FOLDER1=打开文件夹1
|
|
4
|
+
OPEN_FOLDER2=打开文件夹2
|
|
5
|
+
TO_BE_SELECTED=未选择
|
|
6
|
+
LB_FOLDER1=文件夹1: {}
|
|
7
|
+
LB_FOLDER2=文件夹2: {}
|
|
8
|
+
AD_TITLE1=选择文件夹1
|
|
9
|
+
AD_TITLE2=选择文件夹2
|
|
10
|
+
NO_FIG=所选文件夹中没有figures文件夹! 请先使用gui_viewer.py画图!
|
|
11
|
+
LOAD_FAILED=无法加载图片: {}
|
|
12
|
+
NO_IMAGE=无图像
|
|
13
|
+
EXIT=退出
|
|
14
|
+
FILE=文件
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Load Path
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
# Load Event Queue
|
|
5
|
+
from .evtq import EventQueue
|
|
6
|
+
|
|
7
|
+
# Load Language Library
|
|
8
|
+
from feasytools import LangLib, LangConfig
|
|
9
|
+
LangConfig.SetAppName("v2sim")
|
|
10
|
+
|
|
11
|
+
# High DPI awareness for Windows
|
|
12
|
+
import platform
|
|
13
|
+
if platform.system() == "Windows":
|
|
14
|
+
import ctypes
|
|
15
|
+
ctypes.windll.shcore.SetProcessDpiAwareness(1)
|
|
16
|
+
|
|
17
|
+
# Load Tk controls
|
|
18
|
+
from tkinter import (
|
|
19
|
+
Toplevel, messagebox as MB, BooleanVar, StringVar, IntVar, Canvas, Event, Tk, Menu, filedialog, Text, Listbox, PhotoImage, Widget,
|
|
20
|
+
NO, YES, NORMAL, DISABLED, END, BOTH, X, Y, LEFT, RIGHT, TOP, BOTTOM, W, E
|
|
21
|
+
)
|
|
22
|
+
from tkinter.ttk import Treeview, Button, LabelFrame, Checkbutton, Combobox, Frame, Label, Entry, Spinbox, Scrollbar, Radiobutton, Notebook, OptionMenu
|
|
23
|
+
|
|
24
|
+
# Load Type Hints
|
|
25
|
+
from typing import Dict, List, Set, Tuple, Any, Union, Optional, Iterable, Callable, Literal
|
|
26
|
+
|
|
27
|
+
# Set exports
|
|
28
|
+
__all__ = [
|
|
29
|
+
"LangLib", "LangConfig", "EventQueue", "Path", "Dict", "List", "Set", "Tuple", "Any", "Union", "Optional", "Iterable", "Callable", "Literal",
|
|
30
|
+
"Toplevel", "MB", "BooleanVar", "StringVar", "IntVar", "Canvas", "Event", "Tk", "Menu", "filedialog", "Text", "Listbox", "PhotoImage", "Widget",
|
|
31
|
+
"NO", "YES", "NORMAL", "DISABLED", "END", "X", "Y", "BOTH", "LEFT", "RIGHT", "TOP", "BOTTOM", "W", "E", "platform",
|
|
32
|
+
"Treeview", "Button", "LabelFrame", "Checkbutton", "Combobox", "Frame", "Label", "Entry", "Spinbox", "Scrollbar", "Radiobutton", "Notebook", "OptionMenu",
|
|
33
|
+
]
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
import time
|
|
3
|
+
import traceback
|
|
4
|
+
from collections import deque
|
|
5
|
+
from queue import Queue
|
|
6
|
+
from typing import Callable, Dict, Tuple
|
|
7
|
+
|
|
8
|
+
class EventQueue:
|
|
9
|
+
def __init__(self, parent, maxsize:int = 0, interval_ms:int = 100, max_proc_ms:int = 90):
|
|
10
|
+
self._Q = Queue(maxsize)
|
|
11
|
+
self._parent = parent
|
|
12
|
+
self._evt:Dict[str, Callable] = {}
|
|
13
|
+
self._interval_ms = interval_ms
|
|
14
|
+
self._max_proc_ns = max_proc_ms * 1e6 # Convert to nanoseconds
|
|
15
|
+
self._delegates:deque[Tuple[Callable, Tuple, Dict]] = deque()
|
|
16
|
+
self.do() # Start processing events immediately
|
|
17
|
+
|
|
18
|
+
def do(self):
|
|
19
|
+
"""Process all events in the queue."""
|
|
20
|
+
prod_next = True
|
|
21
|
+
st = time.time_ns()
|
|
22
|
+
|
|
23
|
+
cnt = 0
|
|
24
|
+
while self._delegates:
|
|
25
|
+
func, args, kwargs = self._delegates.popleft()
|
|
26
|
+
try:
|
|
27
|
+
func(*args, **kwargs)
|
|
28
|
+
except Exception as e:
|
|
29
|
+
print(f"Error in delegate function '{func.__name__}': {e}")
|
|
30
|
+
|
|
31
|
+
cnt = 0
|
|
32
|
+
while not self._Q.empty() and (time.time_ns() - st < self._max_proc_ns) and cnt < 100:
|
|
33
|
+
name, args, kwargs = self._Q.get()
|
|
34
|
+
if name == "__quit__":
|
|
35
|
+
self._Q.task_done()
|
|
36
|
+
prod_next = False
|
|
37
|
+
break
|
|
38
|
+
if name in self._evt and self._evt[name] is not None:
|
|
39
|
+
try:
|
|
40
|
+
self._evt[name](*args, **kwargs)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
traceback.print_exc()
|
|
43
|
+
print(f"Error processing event '{name}': {e}")
|
|
44
|
+
else:
|
|
45
|
+
print(f"Event '{name}' is not registered.")
|
|
46
|
+
self._Q.task_done()
|
|
47
|
+
self._parent.update() # Ensure the GUI updates after processing each event
|
|
48
|
+
cnt += 1
|
|
49
|
+
if prod_next:
|
|
50
|
+
intv = self._interval_ms
|
|
51
|
+
if cnt >= 100:
|
|
52
|
+
intv = max(intv // 10, 1)
|
|
53
|
+
self._parent.after(intv, self.do)
|
|
54
|
+
|
|
55
|
+
def register(self, name:str, callback:Callable):
|
|
56
|
+
"""Register an event handler for a specific event name."""
|
|
57
|
+
if name in self._evt:
|
|
58
|
+
raise ValueError(f"Event '{name}' is already registered.")
|
|
59
|
+
self._evt[name] = callback
|
|
60
|
+
|
|
61
|
+
def setcallback(self, name:str, callback:Callable):
|
|
62
|
+
"""Set or update the callback for an event."""
|
|
63
|
+
if name not in self._evt:
|
|
64
|
+
raise ValueError(f"Event '{name}' is not registered.")
|
|
65
|
+
self._evt[name] = callback
|
|
66
|
+
|
|
67
|
+
def trigger(self, name:str, *args, **kwargs):
|
|
68
|
+
"""Trigger an event by its name with optional arguments."""
|
|
69
|
+
if name not in self._evt:
|
|
70
|
+
raise ValueError(f"Event '{name}' is not registered.")
|
|
71
|
+
self._Q.put((name, args, kwargs))
|
|
72
|
+
|
|
73
|
+
def submit(self, name:str, func:Callable, *args, **kwargs):
|
|
74
|
+
"""Run a function asychoronously and submit the results to trigger an event."""
|
|
75
|
+
def _run_and_trigger(name, func, *args, **kwargs):
|
|
76
|
+
try:
|
|
77
|
+
result = func(*args, **kwargs)
|
|
78
|
+
if result is None:
|
|
79
|
+
result = ()
|
|
80
|
+
elif not isinstance(result, tuple):
|
|
81
|
+
result = (result,)
|
|
82
|
+
self.trigger(name, *result)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
traceback.print_exc()
|
|
85
|
+
print(f"Error in submitting function '{func.__name__}' for event '{name}': {e}")
|
|
86
|
+
threading.Thread(target=_run_and_trigger, args=(name, func, *args), kwargs=kwargs).start()
|
|
87
|
+
|
|
88
|
+
def asyncrun(self, func:Callable, *args, **kwargs):
|
|
89
|
+
"""Run a no-return function asynchronously"""
|
|
90
|
+
def _run(func, *args, **kwargs):
|
|
91
|
+
try:
|
|
92
|
+
func(*args, **kwargs)
|
|
93
|
+
except Exception as e:
|
|
94
|
+
traceback.print_exc()
|
|
95
|
+
print(f"Error in delegating function '{func.__name__}': {e}")
|
|
96
|
+
threading.Thread(target=_run, args=(func, *args), kwargs=kwargs).start()
|
|
97
|
+
|
|
98
|
+
def delegate(self, func:Callable, *args, **kwargs):
|
|
99
|
+
"""Run a no-return function on the main thread."""
|
|
100
|
+
self._delegates.append((func, args, kwargs))
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from v2sim.gui.com_no_vx import *
|
|
2
|
+
|
|
3
|
+
_ = LangLib(["zh_CN", "en_US"])
|
|
4
|
+
_.SetLangLib("zh_CN",
|
|
5
|
+
MB_INFO = "信息",
|
|
6
|
+
MENU_LANG = "语言",
|
|
7
|
+
MENU_LANG_AUTO = "(自动检测)",
|
|
8
|
+
LANG_RESTART = "语言已更改,请重启程序以应用更改。",
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
_.SetLangLib("en_US",
|
|
12
|
+
MB_INFO = "Information",
|
|
13
|
+
MENU_LANG = "Language",
|
|
14
|
+
MENU_LANG_AUTO = "(Auto Detect)",
|
|
15
|
+
LANG_RESTART = "Language has been changed. Please restart the application to apply the changes.",
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
def setLang(lang_code:str):
|
|
19
|
+
title = _["MB_INFO"]
|
|
20
|
+
info = _["LANG_RESTART"]
|
|
21
|
+
def _f():
|
|
22
|
+
nonlocal lang_code, title, info
|
|
23
|
+
LangConfig.SetLangCode(lang_code)
|
|
24
|
+
MB.showinfo(title, info)
|
|
25
|
+
return _f
|
|
26
|
+
|
|
27
|
+
def add_lang_menu(parent: Menu):
|
|
28
|
+
menuLang = Menu(parent, tearoff=False)
|
|
29
|
+
parent.add_cascade(label=_["MENU_LANG"], menu=menuLang)
|
|
30
|
+
menuLang.add_command(label=_["MENU_LANG_AUTO"], command=setLang("<auto>"))
|
|
31
|
+
menuLang.add_command(label="English (United States)", command=setLang("en_US"))
|
|
32
|
+
menuLang.add_command(label="中文 (简体)", command=setLang("zh_CN"))
|
|
33
|
+
|
|
34
|
+
__all__ = ["add_lang_menu"]
|