phg-vis 1.3.1__tar.gz → 1.3.2__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.
- {phg_vis-1.3.1/phg_vis.egg-info → phg_vis-1.3.2}/PKG-INFO +1 -1
- phg_vis-1.3.2/phg/__init__.py +329 -0
- phg_vis-1.3.2/phg/pipe_string_phg.py +411 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2/phg_vis.egg-info}/PKG-INFO +1 -1
- {phg_vis-1.3.1 → phg_vis-1.3.2}/setup.py +1 -1
- phg_vis-1.3.1/phg/__init__.py +0 -113
- phg_vis-1.3.1/phg/pipe_string_phg.py +0 -285
- {phg_vis-1.3.1 → phg_vis-1.3.2}/LICENSE +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/MANIFEST.in +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/README.md +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/phg_to_shader.py +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/shader_render.py +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/GCU.dll +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/dragpad.exe +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/dragpad_config.ini +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/freeglut.dll +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/imgui/main.lua +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/lua.dll +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/script.phg +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/sqlite3.dll +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/vis.exe +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/vis.ini +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/vis/zlib1.dll +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg/visphg.py +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg_vis.egg-info/SOURCES.txt +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg_vis.egg-info/dependency_links.txt +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/phg_vis.egg-info/top_level.txt +0 -0
- {phg_vis-1.3.1 → phg_vis-1.3.2}/setup.cfg +0 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PHG - Python Hypergraphics Library
|
|
3
|
+
===================================
|
|
4
|
+
|
|
5
|
+
A powerful graphics library for procedural 3D visualization using PHG scripts.
|
|
6
|
+
|
|
7
|
+
Main Features:
|
|
8
|
+
- PHG script visualization via vis.exe
|
|
9
|
+
- Shader-based rendering with GLSL conversion
|
|
10
|
+
- Pipe system visualization with world/local coordinate systems
|
|
11
|
+
- Multiple pipe visualization support
|
|
12
|
+
- Real-time and image rendering capabilities
|
|
13
|
+
|
|
14
|
+
Version: 1.3.1
|
|
15
|
+
Author: PanGuoJun
|
|
16
|
+
License: MIT
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from .visphg import vis, image
|
|
20
|
+
from .shader_render import ShaderRenderer, render_shader
|
|
21
|
+
from .phg_to_shader import PHGToShaderConverter, phg_to_shader
|
|
22
|
+
from .pipe_string_phg import (
|
|
23
|
+
world_pipe_to_phg,
|
|
24
|
+
local_pipe_to_phg,
|
|
25
|
+
world_pipestr_vis,
|
|
26
|
+
local_pipestr_vis,
|
|
27
|
+
multiple_pipes_vis
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Extend ShaderRenderer class to support direct PHG rendering
|
|
31
|
+
class PHGShaderRenderer(ShaderRenderer):
|
|
32
|
+
"""Shader renderer that supports direct PHG rendering"""
|
|
33
|
+
|
|
34
|
+
def render_phg(self, phg_script: str, duration=0, interactive=True):
|
|
35
|
+
"""
|
|
36
|
+
Render PHG script
|
|
37
|
+
|
|
38
|
+
Parameters:
|
|
39
|
+
phg_script: PHG script code
|
|
40
|
+
duration: Render duration
|
|
41
|
+
interactive: Whether to allow interaction
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
success: Whether rendering was successful
|
|
45
|
+
"""
|
|
46
|
+
converter = PHGToShaderConverter()
|
|
47
|
+
shader_code = converter.generate_shader_code(phg_script)
|
|
48
|
+
|
|
49
|
+
if not shader_code:
|
|
50
|
+
print("Error: PHG conversion failed")
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
return self.render_shader(shader_code, duration, interactive)
|
|
54
|
+
|
|
55
|
+
# Convenience functions
|
|
56
|
+
def render_phg(phg_script: str, width=800, height=600, duration=0, title="PHG Renderer"):
|
|
57
|
+
"""
|
|
58
|
+
Directly render PHG script
|
|
59
|
+
|
|
60
|
+
Parameters:
|
|
61
|
+
phg_script: PHG script code
|
|
62
|
+
width: Window width
|
|
63
|
+
height: Window height
|
|
64
|
+
duration: Render duration
|
|
65
|
+
title: Window title
|
|
66
|
+
"""
|
|
67
|
+
renderer = PHGShaderRenderer(width, height, title)
|
|
68
|
+
success = renderer.render_phg(phg_script, duration)
|
|
69
|
+
renderer.close()
|
|
70
|
+
return success
|
|
71
|
+
|
|
72
|
+
def convert_phg_to_shader(phg_script: str) -> str:
|
|
73
|
+
"""
|
|
74
|
+
Convert PHG script to GLSL shader code
|
|
75
|
+
|
|
76
|
+
Parameters:
|
|
77
|
+
phg_script: PHG script
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
shader_code: GLSL shader code
|
|
81
|
+
"""
|
|
82
|
+
return phg_to_shader(phg_script)
|
|
83
|
+
|
|
84
|
+
def visualize_pipe_variants(pipe_variants, start_position=None, colors=None, coordinate_system='world'):
|
|
85
|
+
"""
|
|
86
|
+
Visualize multiple pipe variants for comparison
|
|
87
|
+
|
|
88
|
+
Parameters:
|
|
89
|
+
pipe_variants: List of pipe strings or configuration dictionaries
|
|
90
|
+
start_position: Starting coordinate (optional)
|
|
91
|
+
colors: List of colors for each pipe variant
|
|
92
|
+
coordinate_system: 'world' or 'local' coordinate system
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
PHG script string
|
|
96
|
+
"""
|
|
97
|
+
from coordinate_system import vec3, quat, coord3
|
|
98
|
+
|
|
99
|
+
# Handle start position
|
|
100
|
+
if start_position is None:
|
|
101
|
+
start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
102
|
+
else:
|
|
103
|
+
start_c = start_position
|
|
104
|
+
|
|
105
|
+
# Handle different input formats
|
|
106
|
+
if isinstance(pipe_variants[0], str):
|
|
107
|
+
# Simple list of pipe strings
|
|
108
|
+
if colors is None:
|
|
109
|
+
# Generate distinct colors for each variant
|
|
110
|
+
import colorsys
|
|
111
|
+
colors = []
|
|
112
|
+
for i in range(len(pipe_variants)):
|
|
113
|
+
hue = i / len(pipe_variants)
|
|
114
|
+
rgb = colorsys.hsv_to_rgb(hue, 0.8, 0.9)
|
|
115
|
+
colors.append(tuple(int(c * 255) for c in rgb))
|
|
116
|
+
|
|
117
|
+
if coordinate_system == 'world':
|
|
118
|
+
return world_pipestr_vis(pipe_variants, start_c, colors)
|
|
119
|
+
else:
|
|
120
|
+
return local_pipestr_vis(pipe_variants, start_c, colors)
|
|
121
|
+
|
|
122
|
+
else:
|
|
123
|
+
# List of configuration dictionaries
|
|
124
|
+
pipe_configs = []
|
|
125
|
+
for i, variant in enumerate(pipe_variants):
|
|
126
|
+
if isinstance(variant, str):
|
|
127
|
+
config = {
|
|
128
|
+
'pipe_str': variant,
|
|
129
|
+
'start_c': start_c,
|
|
130
|
+
'color': colors[i] if colors else None,
|
|
131
|
+
'radius': 0.3
|
|
132
|
+
}
|
|
133
|
+
else:
|
|
134
|
+
config = variant
|
|
135
|
+
if 'start_c' not in config:
|
|
136
|
+
config['start_c'] = start_c
|
|
137
|
+
|
|
138
|
+
pipe_configs.append(config)
|
|
139
|
+
|
|
140
|
+
return multiple_pipes_vis(pipe_configs, coordinate_system)
|
|
141
|
+
|
|
142
|
+
def create_pipe_comparison_grid(pipe_strings, grid_size=(2, 2), start_position=None,
|
|
143
|
+
base_color=(0, 55, 255), coordinate_system='world'):
|
|
144
|
+
"""
|
|
145
|
+
Create a grid layout for comparing multiple pipe paths
|
|
146
|
+
|
|
147
|
+
Parameters:
|
|
148
|
+
pipe_strings: List of pipe strings to compare
|
|
149
|
+
grid_size: (rows, cols) for grid layout
|
|
150
|
+
start_position: Base starting position
|
|
151
|
+
base_color: Base color for pipes
|
|
152
|
+
coordinate_system: 'world' or 'local'
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
PHG script string
|
|
156
|
+
"""
|
|
157
|
+
from coordinate_system import vec3, quat, coord3
|
|
158
|
+
|
|
159
|
+
if start_position is None:
|
|
160
|
+
start_position = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
161
|
+
|
|
162
|
+
rows, cols = grid_size
|
|
163
|
+
spacing = 5.0 # Space between pipes in grid
|
|
164
|
+
|
|
165
|
+
pipe_configs = []
|
|
166
|
+
|
|
167
|
+
for i, pipe_str in enumerate(pipe_strings):
|
|
168
|
+
if i >= rows * cols:
|
|
169
|
+
break
|
|
170
|
+
|
|
171
|
+
row = i // cols
|
|
172
|
+
col = i % cols
|
|
173
|
+
|
|
174
|
+
# Calculate position in grid
|
|
175
|
+
x_offset = col * spacing
|
|
176
|
+
z_offset = row * spacing
|
|
177
|
+
|
|
178
|
+
# Create individual start position for this pipe
|
|
179
|
+
individual_start = coord3(
|
|
180
|
+
vec3(
|
|
181
|
+
start_position.o.x + x_offset,
|
|
182
|
+
start_position.o.y,
|
|
183
|
+
start_position.o.z + z_offset
|
|
184
|
+
),
|
|
185
|
+
start_position.Q()
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Generate color variation
|
|
189
|
+
color_variation = (
|
|
190
|
+
min(255, base_color[0] + (i * 30) % 100),
|
|
191
|
+
min(255, base_color[1] + (i * 50) % 100),
|
|
192
|
+
min(255, base_color[2] + (i * 70) % 100)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
pipe_configs.append({
|
|
196
|
+
'pipe_str': pipe_str,
|
|
197
|
+
'start_c': individual_start,
|
|
198
|
+
'color': color_variation,
|
|
199
|
+
'radius': 0.25 + (i * 0.05) # Vary radius slightly
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
return multiple_pipes_vis(pipe_configs, coordinate_system)
|
|
203
|
+
|
|
204
|
+
def generate_pipe_variants_from_rules(base_pipe, num_variants=5, apply_rules=None):
|
|
205
|
+
"""
|
|
206
|
+
Generate pipe variants using transformation rules
|
|
207
|
+
|
|
208
|
+
Parameters:
|
|
209
|
+
base_pipe: Base pipe string
|
|
210
|
+
num_variants: Number of variants to generate
|
|
211
|
+
apply_rules: List of rules to apply ('swap', 'insert', 'cancel')
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
List of pipe variant strings
|
|
215
|
+
"""
|
|
216
|
+
if apply_rules is None:
|
|
217
|
+
apply_rules = ['swap', 'insert', 'cancel']
|
|
218
|
+
|
|
219
|
+
variants = [base_pipe]
|
|
220
|
+
|
|
221
|
+
# Import the pipe transformer if available
|
|
222
|
+
try:
|
|
223
|
+
from .pipe_string_phg import PipeStringTransformer
|
|
224
|
+
transformer = PipeStringTransformer()
|
|
225
|
+
|
|
226
|
+
for _ in range(num_variants - 1):
|
|
227
|
+
current_pipe = base_pipe
|
|
228
|
+
|
|
229
|
+
# Apply random transformations
|
|
230
|
+
import random
|
|
231
|
+
for _ in range(random.randint(1, 3)):
|
|
232
|
+
rule = random.choice(apply_rules)
|
|
233
|
+
|
|
234
|
+
if rule == 'swap' and len(current_pipe) >= 2:
|
|
235
|
+
i, j = random.sample(range(len(current_pipe)), 2)
|
|
236
|
+
current_pipe = transformer.swap_positions(current_pipe, i, j)
|
|
237
|
+
|
|
238
|
+
elif rule == 'insert':
|
|
239
|
+
position = random.randint(0, len(current_pipe))
|
|
240
|
+
direction = random.choice(list(transformer.CANCEL_PAIRS.keys()))
|
|
241
|
+
current_pipe = transformer.insert_cancel_pair(current_pipe, position, direction)
|
|
242
|
+
|
|
243
|
+
elif rule == 'cancel':
|
|
244
|
+
current_pipe = transformer.cancel_adjacent_pairs(current_pipe)
|
|
245
|
+
|
|
246
|
+
# Simplify and add if valid
|
|
247
|
+
simplified = transformer.simplify_path(current_pipe)
|
|
248
|
+
if simplified not in variants:
|
|
249
|
+
variants.append(simplified)
|
|
250
|
+
|
|
251
|
+
except ImportError:
|
|
252
|
+
# Fallback: simple variant generation
|
|
253
|
+
import random
|
|
254
|
+
for i in range(num_variants - 1):
|
|
255
|
+
# Simple character shuffling
|
|
256
|
+
pipe_list = list(base_pipe)
|
|
257
|
+
random.shuffle(pipe_list)
|
|
258
|
+
variant = ''.join(pipe_list)
|
|
259
|
+
if variant not in variants:
|
|
260
|
+
variants.append(variant)
|
|
261
|
+
|
|
262
|
+
return variants[:num_variants]
|
|
263
|
+
|
|
264
|
+
# Enhanced pipe visualization with transformation support
|
|
265
|
+
def visualize_pipe_with_transformations(pipe_string, start_position=None,
|
|
266
|
+
transformations=None, show_variants=3):
|
|
267
|
+
"""
|
|
268
|
+
Visualize a pipe string along with its transformed variants
|
|
269
|
+
|
|
270
|
+
Parameters:
|
|
271
|
+
pipe_string: Base pipe string
|
|
272
|
+
start_position: Starting coordinate
|
|
273
|
+
transformations: List of transformation rules to apply
|
|
274
|
+
show_variants: Number of variants to show
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
PHG script string
|
|
278
|
+
"""
|
|
279
|
+
# Generate variants
|
|
280
|
+
variants = generate_pipe_variants_from_rules(
|
|
281
|
+
pipe_string,
|
|
282
|
+
num_variants=show_variants + 1, # +1 for original
|
|
283
|
+
apply_rules=transformations
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
# Create comparison visualization
|
|
287
|
+
return visualize_pipe_variants(variants, start_position)
|
|
288
|
+
|
|
289
|
+
__all__ = [
|
|
290
|
+
# Core visualization functions
|
|
291
|
+
'vis',
|
|
292
|
+
'image',
|
|
293
|
+
|
|
294
|
+
# Shader rendering
|
|
295
|
+
'ShaderRenderer',
|
|
296
|
+
'render_shader',
|
|
297
|
+
'render_phg',
|
|
298
|
+
'PHGShaderRenderer',
|
|
299
|
+
|
|
300
|
+
# PHG conversion
|
|
301
|
+
'PHGToShaderConverter',
|
|
302
|
+
'phg_to_shader',
|
|
303
|
+
'convert_phg_to_shader',
|
|
304
|
+
|
|
305
|
+
# Pipe visualization
|
|
306
|
+
'world_pipe_to_phg',
|
|
307
|
+
'local_pipe_to_phg',
|
|
308
|
+
'world_pipestr_vis',
|
|
309
|
+
'local_pipestr_vis',
|
|
310
|
+
'multiple_pipes_vis',
|
|
311
|
+
|
|
312
|
+
# Enhanced pipe visualization
|
|
313
|
+
'visualize_pipe_variants',
|
|
314
|
+
'create_pipe_comparison_grid',
|
|
315
|
+
'generate_pipe_variants_from_rules',
|
|
316
|
+
'visualize_pipe_with_transformations',
|
|
317
|
+
]
|
|
318
|
+
|
|
319
|
+
__version__ = "1.3.1"
|
|
320
|
+
__author__ = "PanGuoJun"
|
|
321
|
+
__description__ = "Python Hypergraphics Library"
|
|
322
|
+
|
|
323
|
+
# Package initialization information
|
|
324
|
+
print(f"PHG {__version__} - {__description__}")
|
|
325
|
+
print("[OK] Visualization module loaded")
|
|
326
|
+
print("[OK] Shader converter loaded")
|
|
327
|
+
print("[OK] Pipe visualization loaded")
|
|
328
|
+
print("[OK] Multiple pipe visualization support loaded")
|
|
329
|
+
print("[OK] Pipe transformation utilities loaded")
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pipe String to PHG Converter
|
|
3
|
+
============================
|
|
4
|
+
|
|
5
|
+
This module provides functionality to convert pipe strings into PHG (Python Graphics) scripts.
|
|
6
|
+
Supports both world coordinate system and local coordinate system pipe descriptions.
|
|
7
|
+
|
|
8
|
+
Main Features:
|
|
9
|
+
- world_pipe_to_phg: World coordinate system pipe conversion
|
|
10
|
+
- local_pipe_to_phg: Local coordinate system pipe conversion
|
|
11
|
+
- world_pipestr_vis: Direct visualization for world coordinate pipes
|
|
12
|
+
- local_pipestr_vis: Direct visualization for local coordinate pipes
|
|
13
|
+
|
|
14
|
+
Pipe String Format:
|
|
15
|
+
- F: Forward
|
|
16
|
+
- B: Backward
|
|
17
|
+
- R: Right
|
|
18
|
+
- L: Left
|
|
19
|
+
- U: Up
|
|
20
|
+
- D: Down
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import phg
|
|
24
|
+
from coordinate_system import vec3, quat, coord3
|
|
25
|
+
|
|
26
|
+
# Default color and pipe radius
|
|
27
|
+
DEFAULT_PIPE_COLOR = (0, 55, 255)
|
|
28
|
+
DEFAULT_PIPE_RADIUS = 0.3
|
|
29
|
+
|
|
30
|
+
def world_pipe_to_phg(world_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
31
|
+
"""
|
|
32
|
+
Convert world coordinate system pipe string to PHG script
|
|
33
|
+
|
|
34
|
+
Parameters:
|
|
35
|
+
world_pipe_str: World coordinate pipe string (e.g., "FFRUD")
|
|
36
|
+
start_c: Starting coordinate system
|
|
37
|
+
pipe_color: Pipe color as (R, G, B) tuple
|
|
38
|
+
pipe_radius: Pipe radius
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
PHG script string
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
# World coordinate direction definitions
|
|
45
|
+
world_directions = {
|
|
46
|
+
'F': vec3(0, 0, 1), # Forward (World Z+)
|
|
47
|
+
'B': vec3(0, 0, -1), # Backward (World Z-)
|
|
48
|
+
'R': vec3(1, 0, 0), # Right (World X+)
|
|
49
|
+
'L': vec3(-1, 0, 0), # Left (World X-)
|
|
50
|
+
'U': vec3(0, 1, 0), # Up (World Y+)
|
|
51
|
+
'D': vec3(0, -1, 0) # Down (World Y-)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Parse color
|
|
55
|
+
r, g, b = pipe_color
|
|
56
|
+
|
|
57
|
+
# Pipe component mapping (all components use fixed length 1.0)
|
|
58
|
+
pipe_components = {
|
|
59
|
+
'F': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:90;z:-0.5;}};z:1.0}}',
|
|
60
|
+
'B': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:-90;z:{-1.0-0.5};}};z:1.0}}',
|
|
61
|
+
'R': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:90;x:1.0;z:-1.0}}}},{{x:1.0;ry:-90;}}',
|
|
62
|
+
'L': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:-90;m:x;z:-1.0;x:-1.0}}}},{{x:-1.0;ry:90;}}',
|
|
63
|
+
'U': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:90;y:1.0;z:-1}}}},{{y:1.0;rx:90;}}',
|
|
64
|
+
'D': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:-90;y:-1;z:-1}}}},{{y:-1.0;rx:-90;}}'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
# Initialize current coordinate system (using starting coordinate)
|
|
68
|
+
cur_c = coord3(start_c.o, start_c.Q())
|
|
69
|
+
|
|
70
|
+
# Store all pipe component scripts
|
|
71
|
+
script_parts = []
|
|
72
|
+
|
|
73
|
+
# Iterate through each character in pipe string
|
|
74
|
+
for move_char in world_pipe_str:
|
|
75
|
+
if move_char not in pipe_components:
|
|
76
|
+
print(f"Warning: Unknown pipe character '{move_char}', skipped")
|
|
77
|
+
continue
|
|
78
|
+
|
|
79
|
+
# Get current movement direction in world coordinates
|
|
80
|
+
world_dir = world_directions[move_char]
|
|
81
|
+
|
|
82
|
+
# Transform world direction to current local coordinate system
|
|
83
|
+
local_dir = vec3(
|
|
84
|
+
world_dir.dot(cur_c.ux), # Component in local X-axis
|
|
85
|
+
world_dir.dot(cur_c.uy), # Component in local Y-axis
|
|
86
|
+
world_dir.dot(cur_c.uz) # Component in local Z-axis
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Find component with largest absolute value to determine main movement direction
|
|
90
|
+
abs_components = [abs(local_dir.x), abs(local_dir.y), abs(local_dir.z)]
|
|
91
|
+
max_idx = abs_components.index(max(abs_components))
|
|
92
|
+
|
|
93
|
+
# Determine local movement direction based on maximum component
|
|
94
|
+
if max_idx == 0: # X-axis
|
|
95
|
+
local_move = 'R' if local_dir.x > 0 else 'L'
|
|
96
|
+
elif max_idx == 1: # Y-axis
|
|
97
|
+
local_move = 'U' if local_dir.y > 0 else 'D'
|
|
98
|
+
else: # Z-axis
|
|
99
|
+
local_move = 'F' if local_dir.z > 0 else 'B'
|
|
100
|
+
|
|
101
|
+
# Add corresponding pipe component script
|
|
102
|
+
script_parts.append(pipe_components[local_move])
|
|
103
|
+
|
|
104
|
+
# Update current coordinate system (simulate new position and direction after movement)
|
|
105
|
+
if local_move == 'F':
|
|
106
|
+
# Forward: move 1.0 unit along local Z-axis positive direction
|
|
107
|
+
cur_c = cur_c * coord3(vec3(0, 0, 1.0))
|
|
108
|
+
elif local_move == 'B':
|
|
109
|
+
# Backward: move 1.0 unit along local Z-axis negative direction
|
|
110
|
+
cur_c = cur_c * coord3(vec3(0, 0, -1.0))
|
|
111
|
+
elif local_move == 'R':
|
|
112
|
+
# Right turn: rotate -90 degrees around Y-axis, then move 1.0 unit along X-axis
|
|
113
|
+
rotation = quat(-3.1416 / 2, cur_c.uy)
|
|
114
|
+
cur_c = cur_c * rotation
|
|
115
|
+
cur_c = cur_c * coord3(vec3(1.0, 0, 0))
|
|
116
|
+
elif local_move == 'L':
|
|
117
|
+
# Left turn: rotate 90 degrees around Y-axis, then move 1.0 unit along X-axis
|
|
118
|
+
rotation = quat(3.1416 / 2, cur_c.uy)
|
|
119
|
+
cur_c = cur_c * rotation
|
|
120
|
+
cur_c = cur_c * coord3(vec3(-1.0, 0, 0))
|
|
121
|
+
elif local_move == 'U':
|
|
122
|
+
# Up turn: rotate 90 degrees around X-axis, then move 1.0 unit along Y-axis
|
|
123
|
+
rotation = quat(3.1416 / 2, cur_c.ux)
|
|
124
|
+
cur_c = cur_c * rotation
|
|
125
|
+
cur_c = cur_c * coord3(vec3(0, 1.0, 0))
|
|
126
|
+
elif local_move == 'D':
|
|
127
|
+
# Down turn: rotate -90 degrees around X-axis, then move 1.0 unit along Y-axis
|
|
128
|
+
rotation = quat(-3.1416 / 2, cur_c.ux)
|
|
129
|
+
cur_c = cur_c * rotation
|
|
130
|
+
cur_c = cur_c * coord3(vec3(0, -1.0, 0))
|
|
131
|
+
|
|
132
|
+
# Combine all pipe component scripts
|
|
133
|
+
inner_script = ',\n'.join(script_parts)
|
|
134
|
+
|
|
135
|
+
# Get quaternion of starting coordinate system
|
|
136
|
+
q = start_c.Q()
|
|
137
|
+
|
|
138
|
+
# Build complete PHG script
|
|
139
|
+
complete_script = f"""{{
|
|
140
|
+
{{xyz:{start_c.o.x},{start_c.o.y},{start_c.o.z};q:{q.w},{q.x},{q.y},{q.z};s:0.5;
|
|
141
|
+
<{inner_script}>}}
|
|
142
|
+
}}"""
|
|
143
|
+
|
|
144
|
+
return complete_script
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def local_pipe_to_phg(local_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
148
|
+
"""
|
|
149
|
+
Convert local coordinate system pipe string to PHG script
|
|
150
|
+
|
|
151
|
+
Parameters:
|
|
152
|
+
local_pipe_str: Local coordinate pipe string (e.g., "FFRUD")
|
|
153
|
+
start_c: Starting coordinate system
|
|
154
|
+
pipe_color: Pipe color as (R, G, B) tuple
|
|
155
|
+
pipe_radius: Pipe radius
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
PHG script string
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
# Parse color
|
|
162
|
+
r, g, b = pipe_color
|
|
163
|
+
|
|
164
|
+
# Pipe component mapping (all components use fixed length 1.0)
|
|
165
|
+
pipe_components = {
|
|
166
|
+
'F': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:90;z:-0.5;}};z:1.0}}',
|
|
167
|
+
'B': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:-90;z:{-1.0-0.5};}};z:1.0}}',
|
|
168
|
+
'R': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:90;x:1.0;z:-1.0}}}},{{x:1.0;ry:-90;}}',
|
|
169
|
+
'L': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:-90;m:x;z:-1.0;x:-1.0}}}},{{x:-1.0;ry:90;}}',
|
|
170
|
+
'U': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:90;y:1.0;z:-1}}}},{{y:1.0;rx:90;}}',
|
|
171
|
+
'D': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:-90;y:-1;z:-1}}}},{{y:-1.0;rx:-90;}}'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Store all pipe component scripts
|
|
175
|
+
script_parts = []
|
|
176
|
+
|
|
177
|
+
# Iterate through each character in pipe string
|
|
178
|
+
for move_char in local_pipe_str:
|
|
179
|
+
if move_char not in pipe_components:
|
|
180
|
+
print(f"Warning: Unknown pipe character '{move_char}', skipped")
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
# Directly use local coordinate system movement commands
|
|
184
|
+
script_parts.append(pipe_components[move_char])
|
|
185
|
+
|
|
186
|
+
# Combine all pipe component scripts
|
|
187
|
+
inner_script = ',\n'.join(script_parts)
|
|
188
|
+
|
|
189
|
+
# Get quaternion of starting coordinate system
|
|
190
|
+
q = start_c.Q()
|
|
191
|
+
|
|
192
|
+
# Build complete PHG script
|
|
193
|
+
complete_script = f"""{{
|
|
194
|
+
{{xyz:{start_c.o.x},{start_c.o.y},{start_c.o.z};q:{q.w},{q.x},{q.y},{q.z};s:0.5;
|
|
195
|
+
<{inner_script}>}}
|
|
196
|
+
}}"""
|
|
197
|
+
|
|
198
|
+
return complete_script
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def world_pipestr_vis(world_pipe_strs, start_c=None, pipe_colors=None, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
202
|
+
"""
|
|
203
|
+
Direct visualization for world coordinate pipe strings with support for multiple pipes
|
|
204
|
+
|
|
205
|
+
Parameters:
|
|
206
|
+
world_pipe_strs: World coordinate pipe string or list of strings (e.g., "FFRUD" or ["FFR", "LLU"])
|
|
207
|
+
start_c: Starting coordinate system, defaults to origin
|
|
208
|
+
pipe_colors: Single color or list of colors as (R, G, B) tuples
|
|
209
|
+
pipe_radius: Pipe radius
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
PHG script string
|
|
213
|
+
"""
|
|
214
|
+
# Handle single string input
|
|
215
|
+
if isinstance(world_pipe_strs, str):
|
|
216
|
+
world_pipe_strs = [world_pipe_strs]
|
|
217
|
+
|
|
218
|
+
# Handle single color input
|
|
219
|
+
if pipe_colors is None:
|
|
220
|
+
pipe_colors = [DEFAULT_PIPE_COLOR] * len(world_pipe_strs)
|
|
221
|
+
elif isinstance(pipe_colors, tuple):
|
|
222
|
+
pipe_colors = [pipe_colors] * len(world_pipe_strs)
|
|
223
|
+
|
|
224
|
+
# Ensure colors list matches pipes list length
|
|
225
|
+
if len(pipe_colors) != len(world_pipe_strs):
|
|
226
|
+
pipe_colors = [DEFAULT_PIPE_COLOR] * len(world_pipe_strs)
|
|
227
|
+
print("Warning: Colors list length doesn't match pipes list, using default colors")
|
|
228
|
+
|
|
229
|
+
# Use default origin if no starting coordinate provided
|
|
230
|
+
if start_c is None:
|
|
231
|
+
start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
232
|
+
|
|
233
|
+
# Generate PHG scripts for all pipes
|
|
234
|
+
script_parts = []
|
|
235
|
+
for i, (pipe_str, color) in enumerate(zip(world_pipe_strs, pipe_colors)):
|
|
236
|
+
phg_script = world_pipe_to_phg(pipe_str, start_c, color, pipe_radius)
|
|
237
|
+
# Extract inner content between outer braces
|
|
238
|
+
inner_content = phg_script.strip()[1:-1].strip()
|
|
239
|
+
script_parts.append(inner_content)
|
|
240
|
+
|
|
241
|
+
# Combine all pipe scripts
|
|
242
|
+
combined_script = "{\n" + ",\n".join(script_parts) + "\n}"
|
|
243
|
+
|
|
244
|
+
# Call visualization function
|
|
245
|
+
try:
|
|
246
|
+
phg.vis(combined_script)
|
|
247
|
+
print(f"Visualizing {len(world_pipe_strs)} world coordinate pipes")
|
|
248
|
+
except ImportError:
|
|
249
|
+
print("Warning: Cannot import visualization module, returning PHG script")
|
|
250
|
+
|
|
251
|
+
return combined_script
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def local_pipestr_vis(local_pipe_strs, start_c=None, pipe_colors=None, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
255
|
+
"""
|
|
256
|
+
Direct visualization for local coordinate pipe strings with support for multiple pipes
|
|
257
|
+
|
|
258
|
+
Parameters:
|
|
259
|
+
local_pipe_strs: Local coordinate pipe string or list of strings (e.g., "FFRUD" or ["FFR", "LLU"])
|
|
260
|
+
start_c: Starting coordinate system, defaults to origin
|
|
261
|
+
pipe_colors: Single color or list of colors as (R, G, B) tuples
|
|
262
|
+
pipe_radius: Pipe radius
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
PHG script string
|
|
266
|
+
"""
|
|
267
|
+
# Handle single string input
|
|
268
|
+
if isinstance(local_pipe_strs, str):
|
|
269
|
+
local_pipe_strs = [local_pipe_strs]
|
|
270
|
+
|
|
271
|
+
# Handle single color input
|
|
272
|
+
if pipe_colors is None:
|
|
273
|
+
pipe_colors = [DEFAULT_PIPE_COLOR] * len(local_pipe_strs)
|
|
274
|
+
elif isinstance(pipe_colors, tuple):
|
|
275
|
+
pipe_colors = [pipe_colors] * len(local_pipe_strs)
|
|
276
|
+
|
|
277
|
+
# Ensure colors list matches pipes list length
|
|
278
|
+
if len(pipe_colors) != len(local_pipe_strs):
|
|
279
|
+
pipe_colors = [DEFAULT_PIPE_COLOR] * len(local_pipe_strs)
|
|
280
|
+
print("Warning: Colors list length doesn't match pipes list, using default colors")
|
|
281
|
+
|
|
282
|
+
# Use default origin if no starting coordinate provided
|
|
283
|
+
if start_c is None:
|
|
284
|
+
start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
285
|
+
|
|
286
|
+
# Generate PHG scripts for all pipes
|
|
287
|
+
script_parts = []
|
|
288
|
+
for i, (pipe_str, color) in enumerate(zip(local_pipe_strs, pipe_colors)):
|
|
289
|
+
phg_script = local_pipe_to_phg(pipe_str, start_c, color, pipe_radius)
|
|
290
|
+
# Extract inner content between outer braces
|
|
291
|
+
inner_content = phg_script.strip()[1:-1].strip()
|
|
292
|
+
script_parts.append(inner_content)
|
|
293
|
+
|
|
294
|
+
# Combine all pipe scripts
|
|
295
|
+
combined_script = "{\n" + ",\n".join(script_parts) + "\n}"
|
|
296
|
+
|
|
297
|
+
# Call visualization function
|
|
298
|
+
try:
|
|
299
|
+
phg.vis(combined_script)
|
|
300
|
+
print(f"Visualizing {len(local_pipe_strs)} local coordinate pipes")
|
|
301
|
+
except ImportError:
|
|
302
|
+
print("Warning: Cannot import visualization module, returning PHG script")
|
|
303
|
+
|
|
304
|
+
return combined_script
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def multiple_pipes_vis(pipe_configs, coordinate_system='world'):
|
|
308
|
+
"""
|
|
309
|
+
Advanced visualization for multiple pipes with individual configurations
|
|
310
|
+
|
|
311
|
+
Parameters:
|
|
312
|
+
pipe_configs: List of pipe configuration dictionaries with keys:
|
|
313
|
+
- 'pipe_str': Pipe string (required)
|
|
314
|
+
- 'start_c': Starting coordinate (optional, defaults to origin)
|
|
315
|
+
- 'color': Pipe color (optional, defaults to DEFAULT_PIPE_COLOR)
|
|
316
|
+
- 'radius': Pipe radius (optional, defaults to DEFAULT_PIPE_RADIUS)
|
|
317
|
+
coordinate_system: 'world' or 'local' coordinate system
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
PHG script string
|
|
321
|
+
"""
|
|
322
|
+
script_parts = []
|
|
323
|
+
|
|
324
|
+
for i, config in enumerate(pipe_configs):
|
|
325
|
+
pipe_str = config.get('pipe_str')
|
|
326
|
+
start_c = config.get('start_c', coord3(vec3(0, 0, 0), quat(1, 0, 0, 0)))
|
|
327
|
+
color = config.get('color', DEFAULT_PIPE_COLOR)
|
|
328
|
+
radius = config.get('radius', DEFAULT_PIPE_RADIUS)
|
|
329
|
+
|
|
330
|
+
if coordinate_system.lower() == 'world':
|
|
331
|
+
phg_script = world_pipe_to_phg(pipe_str, start_c, color, radius)
|
|
332
|
+
else:
|
|
333
|
+
phg_script = local_pipe_to_phg(pipe_str, start_c, color, radius)
|
|
334
|
+
|
|
335
|
+
# Extract inner content
|
|
336
|
+
inner_content = phg_script.strip()[1:-1].strip()
|
|
337
|
+
script_parts.append(inner_content)
|
|
338
|
+
|
|
339
|
+
# Combine all pipe scripts
|
|
340
|
+
combined_script = "{\n" + ",\n".join(script_parts) + "\n}"
|
|
341
|
+
|
|
342
|
+
# Call visualization
|
|
343
|
+
try:
|
|
344
|
+
phg.vis(combined_script)
|
|
345
|
+
print(f"Visualizing {len(pipe_configs)} pipes in {coordinate_system} coordinate system")
|
|
346
|
+
except ImportError:
|
|
347
|
+
print("Warning: Cannot import visualization module, returning PHG script")
|
|
348
|
+
|
|
349
|
+
return combined_script
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
# Usage Examples
|
|
353
|
+
if __name__ == "__main__":
|
|
354
|
+
# Create starting coordinate system (example)
|
|
355
|
+
start_coord = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
356
|
+
|
|
357
|
+
# Example 1: Single world coordinate pipe string
|
|
358
|
+
example_world_pipe = "FFRUD" # Forward twice, right, up, down
|
|
359
|
+
print("World Coordinate Pipe Example:")
|
|
360
|
+
phg_script = world_pipe_to_phg(example_world_pipe, start_coord)
|
|
361
|
+
print("Generated PHG Script:")
|
|
362
|
+
print(phg_script)
|
|
363
|
+
print()
|
|
364
|
+
|
|
365
|
+
# Example 2: Single local coordinate pipe string
|
|
366
|
+
example_local_pipe = "FFRUD" # Movements in local coordinate system
|
|
367
|
+
print("Local Coordinate Pipe Example:")
|
|
368
|
+
phg_script = local_pipe_to_phg(example_local_pipe, start_coord)
|
|
369
|
+
print("Generated PHG Script:")
|
|
370
|
+
print(phg_script)
|
|
371
|
+
print()
|
|
372
|
+
|
|
373
|
+
# Example 3: Multiple pipes visualization
|
|
374
|
+
print("Multiple Pipes Visualization Example:")
|
|
375
|
+
|
|
376
|
+
# Multiple world coordinate pipes with different colors
|
|
377
|
+
world_pipes = ["FFR", "LLU", "RRD"]
|
|
378
|
+
world_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] # Red, Green, Blue
|
|
379
|
+
world_pipestr_vis(world_pipes, start_coord, world_colors)
|
|
380
|
+
print()
|
|
381
|
+
|
|
382
|
+
# Multiple local coordinate pipes
|
|
383
|
+
local_pipes = ["FFR", "BBL", "UUD"]
|
|
384
|
+
local_colors = [(255, 255, 0), (255, 0, 255), (0, 255, 255)] # Yellow, Magenta, Cyan
|
|
385
|
+
local_pipestr_vis(local_pipes, start_coord, local_colors)
|
|
386
|
+
print()
|
|
387
|
+
|
|
388
|
+
# Example 4: Advanced multiple pipes configuration
|
|
389
|
+
print("Advanced Multiple Pipes Configuration:")
|
|
390
|
+
pipe_configs = [
|
|
391
|
+
{
|
|
392
|
+
'pipe_str': 'FFR',
|
|
393
|
+
'start_c': coord3(vec3(0, 0, 0), quat(1, 0, 0, 0)),
|
|
394
|
+
'color': (255, 100, 100),
|
|
395
|
+
'radius': 0.4
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
'pipe_str': 'LLU',
|
|
399
|
+
'start_c': coord3(vec3(5, 0, 0), quat(1, 0, 0, 0)),
|
|
400
|
+
'color': (100, 255, 100),
|
|
401
|
+
'radius': 0.3
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
'pipe_str': 'RRD',
|
|
405
|
+
'start_c': coord3(vec3(0, 5, 0), quat(1, 0, 0, 0)),
|
|
406
|
+
'color': (100, 100, 255),
|
|
407
|
+
'radius': 0.2
|
|
408
|
+
}
|
|
409
|
+
]
|
|
410
|
+
|
|
411
|
+
multiple_pipes_vis(pipe_configs, 'world')
|
phg_vis-1.3.1/phg/__init__.py
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
PHG - Python Hypergraphics Library
|
|
3
|
-
===================================
|
|
4
|
-
|
|
5
|
-
A powerful graphics library for procedural 3D visualization using PHG scripts.
|
|
6
|
-
|
|
7
|
-
Main Features:
|
|
8
|
-
- PHG script visualization via vis.exe
|
|
9
|
-
- Shader-based rendering with GLSL conversion
|
|
10
|
-
- Pipe system visualization with world/local coordinate systems
|
|
11
|
-
- Real-time and image rendering capabilities
|
|
12
|
-
|
|
13
|
-
Version: 0.2.0
|
|
14
|
-
Author: PanGuoJun
|
|
15
|
-
License: MIT
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
from .visphg import vis, image
|
|
19
|
-
from .shader_render import ShaderRenderer, render_shader
|
|
20
|
-
from .phg_to_shader import PHGToShaderConverter, phg_to_shader
|
|
21
|
-
from .pipe_string_phg import (
|
|
22
|
-
world_pipe_to_phg,
|
|
23
|
-
local_pipe_to_phg,
|
|
24
|
-
world_pipestr_vis,
|
|
25
|
-
local_pipestr_vis
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
# Extend ShaderRenderer class to support direct PHG rendering
|
|
29
|
-
class PHGShaderRenderer(ShaderRenderer):
|
|
30
|
-
"""Shader renderer that supports direct PHG rendering"""
|
|
31
|
-
|
|
32
|
-
def render_phg(self, phg_script: str, duration=0, interactive=True):
|
|
33
|
-
"""
|
|
34
|
-
Render PHG script
|
|
35
|
-
|
|
36
|
-
Parameters:
|
|
37
|
-
phg_script: PHG script code
|
|
38
|
-
duration: Render duration
|
|
39
|
-
interactive: Whether to allow interaction
|
|
40
|
-
|
|
41
|
-
Returns:
|
|
42
|
-
success: Whether rendering was successful
|
|
43
|
-
"""
|
|
44
|
-
converter = PHGToShaderConverter()
|
|
45
|
-
shader_code = converter.generate_shader_code(phg_script)
|
|
46
|
-
|
|
47
|
-
if not shader_code:
|
|
48
|
-
print("Error: PHG conversion failed")
|
|
49
|
-
return False
|
|
50
|
-
|
|
51
|
-
return self.render_shader(shader_code, duration, interactive)
|
|
52
|
-
|
|
53
|
-
# Convenience functions
|
|
54
|
-
def render_phg(phg_script: str, width=800, height=600, duration=0, title="PHG Renderer"):
|
|
55
|
-
"""
|
|
56
|
-
Directly render PHG script
|
|
57
|
-
|
|
58
|
-
Parameters:
|
|
59
|
-
phg_script: PHG script code
|
|
60
|
-
width: Window width
|
|
61
|
-
height: Window height
|
|
62
|
-
duration: Render duration
|
|
63
|
-
title: Window title
|
|
64
|
-
"""
|
|
65
|
-
renderer = PHGShaderRenderer(width, height, title)
|
|
66
|
-
success = renderer.render_phg(phg_script, duration)
|
|
67
|
-
renderer.close()
|
|
68
|
-
return success
|
|
69
|
-
|
|
70
|
-
def convert_phg_to_shader(phg_script: str) -> str:
|
|
71
|
-
"""
|
|
72
|
-
Convert PHG script to GLSL shader code
|
|
73
|
-
|
|
74
|
-
Parameters:
|
|
75
|
-
phg_script: PHG script
|
|
76
|
-
|
|
77
|
-
Returns:
|
|
78
|
-
shader_code: GLSL shader code
|
|
79
|
-
"""
|
|
80
|
-
return phg_to_shader(phg_script)
|
|
81
|
-
|
|
82
|
-
__all__ = [
|
|
83
|
-
# Core visualization functions
|
|
84
|
-
'vis',
|
|
85
|
-
'image',
|
|
86
|
-
|
|
87
|
-
# Shader rendering
|
|
88
|
-
'ShaderRenderer',
|
|
89
|
-
'render_shader',
|
|
90
|
-
'render_phg',
|
|
91
|
-
'PHGShaderRenderer',
|
|
92
|
-
|
|
93
|
-
# PHG conversion
|
|
94
|
-
'PHGToShaderConverter',
|
|
95
|
-
'phg_to_shader',
|
|
96
|
-
'convert_phg_to_shader',
|
|
97
|
-
|
|
98
|
-
# Pipe visualization
|
|
99
|
-
'world_pipe_to_phg',
|
|
100
|
-
'local_pipe_to_phg',
|
|
101
|
-
'world_pipestr_vis',
|
|
102
|
-
'local_pipestr_vis',
|
|
103
|
-
]
|
|
104
|
-
|
|
105
|
-
__version__ = "1.3.1"
|
|
106
|
-
__author__ = "PanGuoJun"
|
|
107
|
-
__description__ = "Python Hypergraphics Library"
|
|
108
|
-
|
|
109
|
-
# Package initialization information
|
|
110
|
-
print(f"PHG {__version__} - {__description__}")
|
|
111
|
-
print("[OK] Visualization module loaded")
|
|
112
|
-
print("[OK] Shader converter loaded")
|
|
113
|
-
print("[OK] Pipe visualization loaded")
|
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Pipe String to PHG Converter
|
|
3
|
-
============================
|
|
4
|
-
|
|
5
|
-
该模块提供了管道字符串转换为PHG(Python Graphics)脚本的功能。
|
|
6
|
-
支持世界坐标系和局部坐标系两种管道描述方式。
|
|
7
|
-
|
|
8
|
-
主要功能:
|
|
9
|
-
- world_pipe_to_phg: 世界坐标系管道转换
|
|
10
|
-
- local_pipe_to_phg: 局部坐标系管道转换
|
|
11
|
-
- world_pipestr_vis: 世界坐标系管道直接可视化
|
|
12
|
-
- local_pipestr_vis: 局部坐标系管道直接可视化
|
|
13
|
-
|
|
14
|
-
管道字符串格式:
|
|
15
|
-
- F: 前进 (Forward)
|
|
16
|
-
- B: 后退 (Back)
|
|
17
|
-
- R: 右转 (Right)
|
|
18
|
-
- L: 左转 (Left)
|
|
19
|
-
- U: 上转 (Up)
|
|
20
|
-
- D: 下转 (Down)
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
import phg
|
|
24
|
-
from coordinate_system import vec3, quat, coord3
|
|
25
|
-
|
|
26
|
-
# 默认颜色和管径
|
|
27
|
-
DEFAULT_PIPE_COLOR = (0, 55, 255)
|
|
28
|
-
DEFAULT_PIPE_RADIUS = 0.3
|
|
29
|
-
|
|
30
|
-
def world_pipe_to_phg(world_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
31
|
-
"""
|
|
32
|
-
将世界坐标系下的管道字符串转换为PHG脚本
|
|
33
|
-
|
|
34
|
-
参数:
|
|
35
|
-
world_pipe_str: 世界坐标系管道字符串(如 "FFRUD")
|
|
36
|
-
start_c: 起始坐标系
|
|
37
|
-
pipe_color: 管道颜色,格式为(R, G, B)元组
|
|
38
|
-
pipe_radius: 管道半径
|
|
39
|
-
|
|
40
|
-
返回:
|
|
41
|
-
PHG脚本字符串
|
|
42
|
-
"""
|
|
43
|
-
|
|
44
|
-
# 世界坐标系方向定义
|
|
45
|
-
world_directions = {
|
|
46
|
-
'F': vec3(0, 0, 1), # 前(世界Z+)
|
|
47
|
-
'B': vec3(0, 0, -1), # 后(世界Z-)
|
|
48
|
-
'R': vec3(1, 0, 0), # 右(世界X+)
|
|
49
|
-
'L': vec3(-1, 0, 0), # 左(世界X-)
|
|
50
|
-
'U': vec3(0, 1, 0), # 上(世界Y+)
|
|
51
|
-
'D': vec3(0, -1, 0) # 下(世界Y-)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
# 解析颜色
|
|
55
|
-
r, g, b = pipe_color
|
|
56
|
-
|
|
57
|
-
# 管道部件映射(所有部件使用固定长度1.0)
|
|
58
|
-
pipe_components = {
|
|
59
|
-
'F': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:90;z:-0.5;}};z:1.0}}',
|
|
60
|
-
'B': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:-90;z:{-1.0-0.5};}};z:1.0}}',
|
|
61
|
-
'R': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:90;x:1.0;z:-1.0}}}},{{x:1.0;ry:-90;}}',
|
|
62
|
-
'L': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:-90;m:x;z:-1.0;x:-1.0}}}},{{x:-1.0;ry:90;}}',
|
|
63
|
-
'U': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:90;y:1.0;z:-1}}}},{{y:1.0;rx:90;}}',
|
|
64
|
-
'D': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:-90;y:-1;z:-1}}}},{{y:-1.0;rx:-90;}}'
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
# 初始化当前坐标系(使用起始坐标系)
|
|
68
|
-
cur_c = coord3(start_c.o, start_c.Q())
|
|
69
|
-
|
|
70
|
-
# 存储所有管道部件的脚本
|
|
71
|
-
script_parts = []
|
|
72
|
-
|
|
73
|
-
# 遍历管道字符串中的每个字符
|
|
74
|
-
for move_char in world_pipe_str:
|
|
75
|
-
if move_char not in pipe_components:
|
|
76
|
-
print(f"警告: 未知的管道字符 '{move_char}',已跳过")
|
|
77
|
-
continue
|
|
78
|
-
|
|
79
|
-
# 获取当前移动在世界坐标系中的方向
|
|
80
|
-
world_dir = world_directions[move_char]
|
|
81
|
-
|
|
82
|
-
# 将世界方向转换到当前局部坐标系
|
|
83
|
-
local_dir = vec3(
|
|
84
|
-
world_dir.dot(cur_c.ux), # 在局部X轴的分量
|
|
85
|
-
world_dir.dot(cur_c.uy), # 在局部Y轴的分量
|
|
86
|
-
world_dir.dot(cur_c.uz) # 在局部Z轴的分量
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
# 找到绝对值最大的分量来确定主要移动方向
|
|
90
|
-
abs_components = [abs(local_dir.x), abs(local_dir.y), abs(local_dir.z)]
|
|
91
|
-
max_idx = abs_components.index(max(abs_components))
|
|
92
|
-
|
|
93
|
-
# 根据最大分量确定局部移动方向
|
|
94
|
-
if max_idx == 0: # X轴
|
|
95
|
-
local_move = 'R' if local_dir.x > 0 else 'L'
|
|
96
|
-
elif max_idx == 1: # Y轴
|
|
97
|
-
local_move = 'U' if local_dir.y > 0 else 'D'
|
|
98
|
-
else: # Z轴
|
|
99
|
-
local_move = 'F' if local_dir.z > 0 else 'B'
|
|
100
|
-
|
|
101
|
-
# 添加对应的管道部件脚本
|
|
102
|
-
script_parts.append(pipe_components[local_move])
|
|
103
|
-
|
|
104
|
-
# 更新当前坐标系(模拟移动后的新位置和方向)
|
|
105
|
-
if local_move == 'F':
|
|
106
|
-
# 前进:沿局部Z轴正方向移动1.0单位
|
|
107
|
-
cur_c = cur_c * coord3(vec3(0, 0, 1.0))
|
|
108
|
-
elif local_move == 'B':
|
|
109
|
-
# 后退:沿局部Z轴负方向移动1.0单位
|
|
110
|
-
cur_c = cur_c * coord3(vec3(0, 0, -1.0))
|
|
111
|
-
elif local_move == 'R':
|
|
112
|
-
# 右转:绕Y轴旋转-90度,然后沿X轴移动1.0单位
|
|
113
|
-
rotation = quat(-3.1416 / 2, cur_c.uy)
|
|
114
|
-
cur_c = cur_c * rotation
|
|
115
|
-
cur_c = cur_c * coord3(vec3(1.0, 0, 0))
|
|
116
|
-
elif local_move == 'L':
|
|
117
|
-
# 左转:绕Y轴旋转90度,然后沿X轴移动1.0单位
|
|
118
|
-
rotation = quat(3.1416 / 2, cur_c.uy)
|
|
119
|
-
cur_c = cur_c * rotation
|
|
120
|
-
cur_c = cur_c * coord3(vec3(-1.0, 0, 0))
|
|
121
|
-
elif local_move == 'U':
|
|
122
|
-
# 上转:绕X轴旋转90度,然后沿Y轴移动1.0单位
|
|
123
|
-
rotation = quat(3.1416 / 2, cur_c.ux)
|
|
124
|
-
cur_c = cur_c * rotation
|
|
125
|
-
cur_c = cur_c * coord3(vec3(0, 1.0, 0))
|
|
126
|
-
elif local_move == 'D':
|
|
127
|
-
# 下转:绕X轴旋转-90度,然后沿Y轴移动1.0单位
|
|
128
|
-
rotation = quat(-3.1416 / 2, cur_c.ux)
|
|
129
|
-
cur_c = cur_c * rotation
|
|
130
|
-
cur_c = cur_c * coord3(vec3(0, -1.0, 0))
|
|
131
|
-
|
|
132
|
-
# 组合所有管道部件的脚本
|
|
133
|
-
inner_script = ',\n'.join(script_parts)
|
|
134
|
-
|
|
135
|
-
# 获取起始坐标系的四元数
|
|
136
|
-
q = start_c.Q()
|
|
137
|
-
|
|
138
|
-
# 构建完整的PHG脚本
|
|
139
|
-
complete_script = f"""{{
|
|
140
|
-
{{xyz:{start_c.o.x},{start_c.o.y},{start_c.o.z};q:{q.w},{q.x},{q.y},{q.z};s:0.5;
|
|
141
|
-
<{inner_script}>}}
|
|
142
|
-
}}"""
|
|
143
|
-
|
|
144
|
-
return complete_script
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def local_pipe_to_phg(local_pipe_str, start_c, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
148
|
-
"""
|
|
149
|
-
将局部坐标系下的管道字符串转换为PHG脚本
|
|
150
|
-
|
|
151
|
-
参数:
|
|
152
|
-
local_pipe_str: 局部坐标系管道字符串(如 "FFRUD")
|
|
153
|
-
start_c: 起始坐标系
|
|
154
|
-
pipe_color: 管道颜色,格式为(R, G, B)元组
|
|
155
|
-
pipe_radius: 管道半径
|
|
156
|
-
|
|
157
|
-
返回:
|
|
158
|
-
PHG脚本字符串
|
|
159
|
-
"""
|
|
160
|
-
|
|
161
|
-
# 解析颜色
|
|
162
|
-
r, g, b = pipe_color
|
|
163
|
-
|
|
164
|
-
# 管道部件映射(所有部件使用固定长度1.0)
|
|
165
|
-
pipe_components = {
|
|
166
|
-
'F': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:90;z:-0.5;}};z:1.0}}',
|
|
167
|
-
'B': f'{{{{rgb:{r},{g},{b};md:cylinder {pipe_radius} 1.0;rx:-90;z:{-1.0-0.5};}};z:1.0}}',
|
|
168
|
-
'R': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:90;x:1.0;z:-1.0}}}},{{x:1.0;ry:-90;}}',
|
|
169
|
-
'L': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}ry:-90;m:x;z:-1.0;x:-1.0}}}},{{x:-1.0;ry:90;}}',
|
|
170
|
-
'U': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:90;y:1.0;z:-1}}}},{{y:1.0;rx:90;}}',
|
|
171
|
-
'D': f'{{{{{{rgb:{r},{g},{b};md:elbow 90 0.5 {pipe_radius};x:0.5;z:0.5;}}rz:-90;y:-1;z:-1}}}},{{y:-1.0;rx:-90;}}'
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
# 存储所有管道部件的脚本
|
|
175
|
-
script_parts = []
|
|
176
|
-
|
|
177
|
-
# 遍历管道字符串中的每个字符
|
|
178
|
-
for move_char in local_pipe_str:
|
|
179
|
-
if move_char not in pipe_components:
|
|
180
|
-
print(f"警告: 未知的管道字符 '{move_char}',已跳过")
|
|
181
|
-
continue
|
|
182
|
-
|
|
183
|
-
# 直接使用局部坐标系的移动命令
|
|
184
|
-
script_parts.append(pipe_components[move_char])
|
|
185
|
-
|
|
186
|
-
# 组合所有管道部件的脚本
|
|
187
|
-
inner_script = ',\n'.join(script_parts)
|
|
188
|
-
|
|
189
|
-
# 获取起始坐标系的四元数
|
|
190
|
-
q = start_c.Q()
|
|
191
|
-
|
|
192
|
-
# 构建完整的PHG脚本
|
|
193
|
-
complete_script = f"""{{
|
|
194
|
-
{{xyz:{start_c.o.x},{start_c.o.y},{start_c.o.z};q:{q.w},{q.x},{q.y},{q.z};s:0.5;
|
|
195
|
-
<{inner_script}>}}
|
|
196
|
-
}}"""
|
|
197
|
-
|
|
198
|
-
return complete_script
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def world_pipestr_vis(world_pipe_str, start_c=None, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
202
|
-
"""
|
|
203
|
-
世界坐标系管道字符串直接可视化
|
|
204
|
-
|
|
205
|
-
参数:
|
|
206
|
-
world_pipe_str: 世界坐标系管道字符串(如 "FFRUD")
|
|
207
|
-
start_c: 起始坐标系,默认为原点
|
|
208
|
-
pipe_color: 管道颜色,格式为(R, G, B)元组
|
|
209
|
-
pipe_radius: 管道半径
|
|
210
|
-
|
|
211
|
-
返回:
|
|
212
|
-
PHG脚本字符串
|
|
213
|
-
"""
|
|
214
|
-
# 如果没有提供起始坐标系,使用默认原点
|
|
215
|
-
if start_c is None:
|
|
216
|
-
start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
217
|
-
|
|
218
|
-
# 生成PHG脚本
|
|
219
|
-
phg_script = world_pipe_to_phg(world_pipe_str, start_c, pipe_color, pipe_radius)
|
|
220
|
-
|
|
221
|
-
# 调用可视化函数
|
|
222
|
-
try:
|
|
223
|
-
from .visphg import vis
|
|
224
|
-
vis(phg_script)
|
|
225
|
-
except ImportError:
|
|
226
|
-
print("警告: 无法导入可视化模块,返回PHG脚本")
|
|
227
|
-
|
|
228
|
-
return phg_script
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def local_pipestr_vis(local_pipe_str, start_c=None, pipe_color=DEFAULT_PIPE_COLOR, pipe_radius=DEFAULT_PIPE_RADIUS):
|
|
232
|
-
"""
|
|
233
|
-
局部坐标系管道字符串直接可视化
|
|
234
|
-
|
|
235
|
-
参数:
|
|
236
|
-
local_pipe_str: 局部坐标系管道字符串(如 "FFRUD")
|
|
237
|
-
start_c: 起始坐标系,默认为原点
|
|
238
|
-
pipe_color: 管道颜色,格式为(R, G, B)元组
|
|
239
|
-
pipe_radius: 管道半径
|
|
240
|
-
|
|
241
|
-
返回:
|
|
242
|
-
PHG脚本字符串
|
|
243
|
-
"""
|
|
244
|
-
# 如果没有提供起始坐标系,使用默认原点
|
|
245
|
-
if start_c is None:
|
|
246
|
-
start_c = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
247
|
-
|
|
248
|
-
# 生成PHG脚本
|
|
249
|
-
phg_script = local_pipe_to_phg(local_pipe_str, start_c, pipe_color, pipe_radius)
|
|
250
|
-
|
|
251
|
-
# 调用可视化函数
|
|
252
|
-
try:
|
|
253
|
-
from .visphg import vis
|
|
254
|
-
vis(phg_script)
|
|
255
|
-
except ImportError:
|
|
256
|
-
print("警告: 无法导入可视化模块,返回PHG脚本")
|
|
257
|
-
|
|
258
|
-
return phg_script
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
# 使用示例
|
|
262
|
-
if __name__ == "__main__":
|
|
263
|
-
# 创建起始坐标系(示例)
|
|
264
|
-
start_coord = coord3(vec3(0, 0, 0), quat(1, 0, 0, 0))
|
|
265
|
-
|
|
266
|
-
# 示例1: 世界坐标系管道字符串
|
|
267
|
-
example_world_pipe = "FFRUD" # 前进2次,右转,上转,下转
|
|
268
|
-
print("世界坐标系管道示例:")
|
|
269
|
-
phg_script = world_pipe_to_phg(example_world_pipe, start_coord)
|
|
270
|
-
print("生成的PHG脚本:")
|
|
271
|
-
print(phg_script)
|
|
272
|
-
print()
|
|
273
|
-
|
|
274
|
-
# 示例2: 局部坐标系管道字符串
|
|
275
|
-
example_local_pipe = "FFRUD" # 在局部坐标系中的移动
|
|
276
|
-
print("局部坐标系管道示例:")
|
|
277
|
-
phg_script = local_pipe_to_phg(example_local_pipe, start_coord)
|
|
278
|
-
print("生成的PHG脚本:")
|
|
279
|
-
print(phg_script)
|
|
280
|
-
print()
|
|
281
|
-
|
|
282
|
-
# 示例3: 直接可视化
|
|
283
|
-
print("直接可视化示例:")
|
|
284
|
-
# world_pipestr_vis(example_world_pipe) # 世界坐标系可视化
|
|
285
|
-
# local_pipestr_vis(example_local_pipe) # 局部坐标系可视化
|
|
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
|
|
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
|
|
File without changes
|