moleditpy 1.9.2__tar.gz → 1.9.4__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.
- {moleditpy-1.9.2 → moleditpy-1.9.4}/PKG-INFO +1 -1
- {moleditpy-1.9.2 → moleditpy-1.9.4}/pyproject.toml +1 -1
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy/main.py +109 -41
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy.egg-info/PKG-INFO +1 -1
- {moleditpy-1.9.2 → moleditpy-1.9.4}/README.md +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/setup.cfg +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy/__init__.py +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy/assets/icon.ico +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy/assets/icon.png +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy.egg-info/SOURCES.txt +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy.egg-info/dependency_links.txt +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy.egg-info/entry_points.txt +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy.egg-info/requires.txt +0 -0
- {moleditpy-1.9.2 → moleditpy-1.9.4}/src/moleditpy.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: moleditpy
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.4
|
|
4
4
|
Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
|
|
5
5
|
Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/HiroYokoyama/python_molecular_editor
|
|
@@ -11,7 +11,7 @@ DOI 10.5281/zenodo.17268532
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
#Version
|
|
14
|
-
VERSION = '1.9.
|
|
14
|
+
VERSION = '1.9.4'
|
|
15
15
|
|
|
16
16
|
print("-----------------------------------------------------")
|
|
17
17
|
print("MoleditPy — A Python-based molecular editing software")
|
|
@@ -4315,7 +4315,6 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4315
4315
|
super().mouseMoveEvent(event)
|
|
4316
4316
|
|
|
4317
4317
|
def mouseReleaseEvent(self, event):
|
|
4318
|
-
|
|
4319
4318
|
if not self.window.is_2d_editable:
|
|
4320
4319
|
return
|
|
4321
4320
|
|
|
@@ -4329,22 +4328,19 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4329
4328
|
if self.mode.startswith('template') and is_click:
|
|
4330
4329
|
if self.template_context and self.template_context.get('points'):
|
|
4331
4330
|
context = self.template_context
|
|
4332
|
-
|
|
4333
4331
|
# Check if this is a user template
|
|
4334
4332
|
if self.mode.startswith('template_user'):
|
|
4335
4333
|
self.add_user_template_fragment(context)
|
|
4336
4334
|
else:
|
|
4337
4335
|
self.add_molecule_fragment(context['points'], context['bonds_info'], existing_items=context.get('items', []))
|
|
4338
|
-
|
|
4339
4336
|
self.data_changed_in_event = True
|
|
4340
|
-
|
|
4341
4337
|
# イベント処理をここで完了させ、下のアイテムが選択されるのを防ぐ
|
|
4342
4338
|
self.start_atom=None; self.start_pos = None; self.press_pos = None
|
|
4343
4339
|
if self.data_changed_in_event: self.window.push_undo_state()
|
|
4344
4340
|
return
|
|
4345
4341
|
|
|
4346
4342
|
released_item = self.itemAt(end_pos, self.views()[0].transform())
|
|
4347
|
-
|
|
4343
|
+
|
|
4348
4344
|
# 1. 特殊モード(ラジカル/電荷)の処理
|
|
4349
4345
|
if (self.mode == 'radical') and is_click and isinstance(released_item, AtomItem):
|
|
4350
4346
|
atom = released_item
|
|
@@ -4371,7 +4367,6 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4371
4367
|
|
|
4372
4368
|
elif self.mode.startswith('bond') and is_click and isinstance(released_item, BondItem):
|
|
4373
4369
|
b = released_item
|
|
4374
|
-
|
|
4375
4370
|
if self.mode == 'bond_2_5':
|
|
4376
4371
|
try:
|
|
4377
4372
|
if b.order == 2:
|
|
@@ -4391,53 +4386,40 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4391
4386
|
if hasattr(self.window, 'statusBar'):
|
|
4392
4387
|
self.window.statusBar().showMessage(f"Error changing E/Z stereochemistry: {e}", 5000)
|
|
4393
4388
|
return # この後の処理は行わない
|
|
4394
|
-
|
|
4395
4389
|
elif self.bond_stereo != 0 and b.order == self.bond_order and b.stereo == self.bond_stereo:
|
|
4396
4390
|
# 方向性を反転させる
|
|
4397
4391
|
old_id1, old_id2 = b.atom1.atom_id, b.atom2.atom_id
|
|
4398
|
-
|
|
4399
4392
|
# 1. 古い方向の結合をデータから削除
|
|
4400
4393
|
self.data.remove_bond(old_id1, old_id2)
|
|
4401
|
-
|
|
4402
4394
|
# 2. 逆方向で結合をデータに再追加
|
|
4403
4395
|
new_key, _ = self.data.add_bond(old_id2, old_id1, self.bond_order, self.bond_stereo)
|
|
4404
|
-
|
|
4405
4396
|
# 3. BondItemの原子参照を入れ替え、新しいデータと関連付ける
|
|
4406
4397
|
b.atom1, b.atom2 = b.atom2, b.atom1
|
|
4407
4398
|
self.data.bonds[new_key]['item'] = b
|
|
4408
|
-
|
|
4409
4399
|
# 4. 見た目を更新
|
|
4410
4400
|
b.update_position()
|
|
4411
|
-
|
|
4412
4401
|
else:
|
|
4413
4402
|
# 既存の結合を一度削除
|
|
4414
4403
|
self.data.remove_bond(b.atom1.atom_id, b.atom2.atom_id)
|
|
4415
|
-
|
|
4416
4404
|
# BondItemが記憶している方向(b.atom1 -> b.atom2)で、新しい結合様式を再作成
|
|
4417
4405
|
# これにより、修正済みのadd_bondが呼ばれ、正しい方向で保存される
|
|
4418
4406
|
new_key, _ = self.data.add_bond(b.atom1.atom_id, b.atom2.atom_id, self.bond_order, self.bond_stereo)
|
|
4419
|
-
|
|
4420
4407
|
# BondItemの見た目とデータ参照を更新
|
|
4421
4408
|
b.prepareGeometryChange()
|
|
4422
4409
|
b.order = self.bond_order
|
|
4423
4410
|
b.stereo = self.bond_stereo
|
|
4424
4411
|
self.data.bonds[new_key]['item'] = b
|
|
4425
4412
|
b.update()
|
|
4426
|
-
|
|
4427
4413
|
self.clearSelection()
|
|
4428
4414
|
self.data_changed_in_event = True
|
|
4429
|
-
|
|
4430
4415
|
# 3. 新規原子・結合の作成処理 (atom_* モード および すべての bond_* モードで許可)
|
|
4431
4416
|
elif self.start_atom and (self.mode.startswith('atom') or self.mode.startswith('bond')):
|
|
4432
4417
|
line = QLineF(self.start_atom.pos(), end_pos); end_item = self.itemAt(end_pos, self.views()[0].transform())
|
|
4433
|
-
|
|
4434
4418
|
# 使用する結合様式を決定
|
|
4435
4419
|
# atomモードの場合は bond_order/stereo を None にして create_bond にデフォルト値(1, 0)を適用
|
|
4436
4420
|
# bond_* モードの場合は現在の設定 (self.bond_order/stereo) を使用
|
|
4437
4421
|
order_to_use = self.bond_order if self.mode.startswith('bond') else None
|
|
4438
4422
|
stereo_to_use = self.bond_stereo if self.mode.startswith('bond') else None
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
4423
|
if is_click:
|
|
4442
4424
|
# 短いクリック: 既存原子のシンボル更新 (atomモードのみ)
|
|
4443
4425
|
if self.mode.startswith('atom') and self.start_atom.symbol != self.current_atom_symbol:
|
|
@@ -4451,25 +4433,20 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4451
4433
|
new_id = self.create_atom(self.current_atom_symbol, end_pos); new_item = self.data.atoms[new_id]['item']
|
|
4452
4434
|
self.create_bond(self.start_atom, new_item, bond_order=order_to_use, bond_stereo=stereo_to_use)
|
|
4453
4435
|
self.data_changed_in_event = True
|
|
4454
|
-
|
|
4455
4436
|
# 4. 空白領域からの新規作成処理 (atom_* モード および すべての bond_* モードで許可)
|
|
4456
4437
|
elif self.start_pos and (self.mode.startswith('atom') or self.mode.startswith('bond')):
|
|
4457
4438
|
line = QLineF(self.start_pos, end_pos)
|
|
4458
|
-
|
|
4459
4439
|
# 使用する結合様式を決定
|
|
4460
4440
|
order_to_use = self.bond_order if self.mode.startswith('bond') else None
|
|
4461
4441
|
stereo_to_use = self.bond_stereo if self.mode.startswith('bond') else None
|
|
4462
|
-
|
|
4463
4442
|
if line.length() < 10:
|
|
4464
4443
|
self.create_atom(self.current_atom_symbol, end_pos); self.data_changed_in_event = True
|
|
4465
4444
|
else:
|
|
4466
4445
|
end_item = self.itemAt(end_pos, self.views()[0].transform())
|
|
4467
|
-
|
|
4468
4446
|
if isinstance(end_item, AtomItem):
|
|
4469
4447
|
start_id = self.create_atom(self.current_atom_symbol, self.start_pos)
|
|
4470
4448
|
start_item = self.data.atoms[start_id]['item']
|
|
4471
4449
|
self.create_bond(start_item, end_item, bond_order=order_to_use, bond_stereo=stereo_to_use)
|
|
4472
|
-
|
|
4473
4450
|
else:
|
|
4474
4451
|
start_id = self.create_atom(self.current_atom_symbol, self.start_pos)
|
|
4475
4452
|
end_id = self.create_atom(self.current_atom_symbol, end_pos)
|
|
@@ -4480,11 +4457,9 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4480
4457
|
bond_stereo=stereo_to_use
|
|
4481
4458
|
)
|
|
4482
4459
|
self.data_changed_in_event = True
|
|
4483
|
-
|
|
4484
4460
|
# 5. それ以外の処理 (Selectモードなど)
|
|
4485
4461
|
else: super().mouseReleaseEvent(event)
|
|
4486
4462
|
|
|
4487
|
-
|
|
4488
4463
|
# 削除されたオブジェクトを安全にチェック
|
|
4489
4464
|
moved_atoms = []
|
|
4490
4465
|
for item, old_pos in self.initial_positions_in_event.items():
|
|
@@ -4495,7 +4470,6 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4495
4470
|
except RuntimeError:
|
|
4496
4471
|
# オブジェクトが削除されている場合はスキップ
|
|
4497
4472
|
continue
|
|
4498
|
-
|
|
4499
4473
|
if moved_atoms:
|
|
4500
4474
|
self.data_changed_in_event = True
|
|
4501
4475
|
bonds_to_update = set()
|
|
@@ -4507,12 +4481,9 @@ class MoleculeScene(QGraphicsScene):
|
|
|
4507
4481
|
# オブジェクトが削除されている場合はスキップ
|
|
4508
4482
|
continue
|
|
4509
4483
|
for bond in bonds_to_update: bond.update_position()
|
|
4510
|
-
|
|
4511
4484
|
# 原子移動後に測定ラベルの位置を更新
|
|
4512
4485
|
self.window.update_2d_measurement_labels()
|
|
4513
|
-
|
|
4514
4486
|
if self.views(): self.views()[0].viewport().update()
|
|
4515
|
-
|
|
4516
4487
|
self.start_atom=None; self.start_pos = None; self.press_pos = None; self.temp_line = None
|
|
4517
4488
|
self.template_context = {}
|
|
4518
4489
|
# Clear user template data when switching modes
|
|
@@ -7009,7 +6980,7 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
7009
6980
|
if abs(current_pos[0] - self._mouse_press_pos[0]) > 3 or abs(current_pos[1] - self._mouse_press_pos[1]) > 3:
|
|
7010
6981
|
self._mouse_moved_during_drag = True
|
|
7011
6982
|
|
|
7012
|
-
if self._is_dragging_atom:
|
|
6983
|
+
if self._is_dragging_atom and mw.dragged_atom_info is not None:
|
|
7013
6984
|
# カスタムの原子ドラッグ処理
|
|
7014
6985
|
self.is_dragging = True
|
|
7015
6986
|
atom_id = mw.dragged_atom_info['id']
|
|
@@ -7075,6 +7046,72 @@ class CustomInteractorStyle(vtkInteractorStyleTrackballCamera):
|
|
|
7075
7046
|
mw.draw_molecule_3d(mw.current_mol)
|
|
7076
7047
|
mw.push_undo_state()
|
|
7077
7048
|
mw.dragged_atom_info = None
|
|
7049
|
+
# Always ensure the visual representation matches the actual
|
|
7050
|
+
# RDKit conformer coordinates when the mouse is released.
|
|
7051
|
+
try:
|
|
7052
|
+
if mw.current_mol and mw.current_mol.GetNumConformers() > 0:
|
|
7053
|
+
conf = mw.current_mol.GetConformer()
|
|
7054
|
+
# Rebuild the authoritative atom_positions_3d from the conformer
|
|
7055
|
+
mw.atom_positions_3d = np.array([list(conf.GetAtomPosition(i)) for i in range(mw.current_mol.GetNumAtoms())])
|
|
7056
|
+
|
|
7057
|
+
# If a glyph_source exists (typical), update its points and mark modified
|
|
7058
|
+
if hasattr(mw, 'glyph_source') and mw.glyph_source is not None:
|
|
7059
|
+
try:
|
|
7060
|
+
mw.glyph_source.points = mw.atom_positions_3d
|
|
7061
|
+
mw.glyph_source.Modified()
|
|
7062
|
+
except Exception:
|
|
7063
|
+
# Fallback to a full redraw if updating glyph_source fails
|
|
7064
|
+
try:
|
|
7065
|
+
mw.draw_molecule_3d(mw.current_mol)
|
|
7066
|
+
except Exception:
|
|
7067
|
+
pass
|
|
7068
|
+
|
|
7069
|
+
# Refresh overlays and labels that depend on atom_positions_3d
|
|
7070
|
+
try:
|
|
7071
|
+
mw.update_3d_selection_display()
|
|
7072
|
+
except Exception:
|
|
7073
|
+
pass
|
|
7074
|
+
try:
|
|
7075
|
+
mw.update_measurement_labels_display()
|
|
7076
|
+
except Exception:
|
|
7077
|
+
pass
|
|
7078
|
+
try:
|
|
7079
|
+
mw.update_2d_measurement_labels()
|
|
7080
|
+
except Exception:
|
|
7081
|
+
pass
|
|
7082
|
+
try:
|
|
7083
|
+
mw.show_all_atom_info()
|
|
7084
|
+
except Exception:
|
|
7085
|
+
pass
|
|
7086
|
+
|
|
7087
|
+
# Final render to make sure everything is consistent
|
|
7088
|
+
try:
|
|
7089
|
+
if hasattr(mw, 'plotter') and mw.plotter:
|
|
7090
|
+
mw.plotter.render()
|
|
7091
|
+
except Exception:
|
|
7092
|
+
pass
|
|
7093
|
+
# As a final safety-net, ensure the visual scene exactly matches
|
|
7094
|
+
# the authoritative RDKit conformer coordinates. This forces a
|
|
7095
|
+
# full redraw if any lower-level updates failed to sync.
|
|
7096
|
+
try:
|
|
7097
|
+
if mw.current_mol and mw.current_mol.GetNumConformers() > 0:
|
|
7098
|
+
# Redraw the molecule and render to guarantee consistency
|
|
7099
|
+
try:
|
|
7100
|
+
mw.draw_molecule_3d(mw.current_mol)
|
|
7101
|
+
except Exception:
|
|
7102
|
+
# If a full redraw fails, at least attempt a render
|
|
7103
|
+
pass
|
|
7104
|
+
try:
|
|
7105
|
+
if hasattr(mw, 'plotter') and mw.plotter:
|
|
7106
|
+
mw.plotter.render()
|
|
7107
|
+
except Exception:
|
|
7108
|
+
pass
|
|
7109
|
+
except Exception:
|
|
7110
|
+
# Silently ignore any errors during this final sync step
|
|
7111
|
+
pass
|
|
7112
|
+
except Exception:
|
|
7113
|
+
# Do not allow a failure here to interrupt release flow
|
|
7114
|
+
pass
|
|
7078
7115
|
else:
|
|
7079
7116
|
# カメラ回転の後始末を親クラスに任せます
|
|
7080
7117
|
super().OnLeftButtonUp()
|
|
@@ -7812,14 +7849,6 @@ class MainWindow(QMainWindow):
|
|
|
7812
7849
|
|
|
7813
7850
|
edit_menu.addSeparator()
|
|
7814
7851
|
|
|
7815
|
-
# Templates
|
|
7816
|
-
template_action = QAction("Templates...", self)
|
|
7817
|
-
template_action.setShortcut(QKeySequence("Ctrl+T"))
|
|
7818
|
-
template_action.triggered.connect(self.open_template_dialog)
|
|
7819
|
-
edit_menu.addAction(template_action)
|
|
7820
|
-
|
|
7821
|
-
edit_menu.addSeparator()
|
|
7822
|
-
|
|
7823
7852
|
select_all_action = QAction("Select All", self); select_all_action.setShortcut(QKeySequence.StandardKey.SelectAll)
|
|
7824
7853
|
select_all_action.triggered.connect(self.select_all); edit_menu.addAction(select_all_action)
|
|
7825
7854
|
|
|
@@ -8402,6 +8431,15 @@ class MainWindow(QMainWindow):
|
|
|
8402
8431
|
self.view_2d.setFocus()
|
|
8403
8432
|
return
|
|
8404
8433
|
|
|
8434
|
+
# 描画モード変更時に測定モードと3D編集モードをリセット
|
|
8435
|
+
if self.measurement_mode:
|
|
8436
|
+
self.measurement_action.setChecked(False)
|
|
8437
|
+
self.toggle_measurement_mode(False) # 測定モードを無効化
|
|
8438
|
+
|
|
8439
|
+
if self.is_3d_edit_mode:
|
|
8440
|
+
self.edit_3d_action.setChecked(False)
|
|
8441
|
+
self.toggle_3d_edit_mode(False) # 3D編集モードを無効化
|
|
8442
|
+
|
|
8405
8443
|
mol = self.data.to_rdkit_mol(use_2d_stereo=False)
|
|
8406
8444
|
|
|
8407
8445
|
# 分子オブジェクトが作成できない場合でも化学的問題をチェック
|
|
@@ -9975,6 +10013,18 @@ class MainWindow(QMainWindow):
|
|
|
9975
10013
|
for i in range(self.current_mol.GetNumAtoms()):
|
|
9976
10014
|
atom = self.current_mol.GetAtomWithIdx(i)
|
|
9977
10015
|
pos = conf.GetAtomPosition(i)
|
|
10016
|
+
|
|
10017
|
+
# Try to preserve original editor atom ID (if present) so it can be
|
|
10018
|
+
# restored when loading PMEPRJ files. RDKit atom properties may
|
|
10019
|
+
# contain _original_atom_id when the molecule was created from
|
|
10020
|
+
# the editor's 2D structure.
|
|
10021
|
+
original_id = None
|
|
10022
|
+
try:
|
|
10023
|
+
if atom.HasProp("_original_atom_id"):
|
|
10024
|
+
original_id = atom.GetIntProp("_original_atom_id")
|
|
10025
|
+
except Exception:
|
|
10026
|
+
original_id = None
|
|
10027
|
+
|
|
9978
10028
|
atom_3d = {
|
|
9979
10029
|
"index": i,
|
|
9980
10030
|
"symbol": atom.GetSymbol(),
|
|
@@ -9984,7 +10034,9 @@ class MainWindow(QMainWindow):
|
|
|
9984
10034
|
"z": pos.z,
|
|
9985
10035
|
"formal_charge": atom.GetFormalCharge(),
|
|
9986
10036
|
"num_explicit_hs": atom.GetNumExplicitHs(),
|
|
9987
|
-
"num_implicit_hs": atom.GetNumImplicitHs()
|
|
10037
|
+
"num_implicit_hs": atom.GetNumImplicitHs(),
|
|
10038
|
+
# include original editor atom id when available for round-trip
|
|
10039
|
+
"original_id": original_id
|
|
9988
10040
|
}
|
|
9989
10041
|
atoms_3d.append(atom_3d)
|
|
9990
10042
|
|
|
@@ -10130,6 +10182,8 @@ class MainWindow(QMainWindow):
|
|
|
10130
10182
|
"""JSONデータから状態を復元"""
|
|
10131
10183
|
self.dragged_atom_info = None
|
|
10132
10184
|
self.clear_2d_editor(push_to_undo=False)
|
|
10185
|
+
self._enable_3d_edit_actions(False)
|
|
10186
|
+
self._enable_3d_features(False)
|
|
10133
10187
|
|
|
10134
10188
|
# 3Dビューアーモードの設定
|
|
10135
10189
|
is_3d_mode = json_data.get("is_3d_viewer_mode", False)
|
|
@@ -10216,6 +10270,18 @@ class MainWindow(QMainWindow):
|
|
|
10216
10270
|
atom_data["y"],
|
|
10217
10271
|
atom_data["z"]
|
|
10218
10272
|
]
|
|
10273
|
+
# Restore original editor atom id into RDKit atom property
|
|
10274
|
+
try:
|
|
10275
|
+
original_id = atom_data.get("original_id", None)
|
|
10276
|
+
if original_id is not None and idx < self.current_mol.GetNumAtoms():
|
|
10277
|
+
rd_atom = self.current_mol.GetAtomWithIdx(idx)
|
|
10278
|
+
# set as int prop so other code expecting _original_atom_id works
|
|
10279
|
+
rd_atom.SetIntProp("_original_atom_id", int(original_id))
|
|
10280
|
+
except Exception:
|
|
10281
|
+
pass
|
|
10282
|
+
self._enable_3d_edit_actions(True)
|
|
10283
|
+
self._enable_3d_features(True)
|
|
10284
|
+
|
|
10219
10285
|
# 3D分子があれば必ず3D表示
|
|
10220
10286
|
self.draw_molecule_3d(self.current_mol)
|
|
10221
10287
|
# ViewerモードならUIも切り替え
|
|
@@ -10223,6 +10289,8 @@ class MainWindow(QMainWindow):
|
|
|
10223
10289
|
self._enter_3d_viewer_ui_mode()
|
|
10224
10290
|
else:
|
|
10225
10291
|
self.is_2d_editable = True
|
|
10292
|
+
self.plotter.reset_camera()
|
|
10293
|
+
|
|
10226
10294
|
except Exception as e:
|
|
10227
10295
|
print(f"Warning: Could not restore 3D molecular data: {e}")
|
|
10228
10296
|
self.current_mol = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: moleditpy
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.4
|
|
4
4
|
Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
|
|
5
5
|
Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/HiroYokoyama/python_molecular_editor
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|