-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathensight2obj.py
115 lines (85 loc) · 4.13 KB
/
ensight2obj.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python
"""
ensight2obj script
==================
This script converts surface elements of EnSight Gold parts
into OBJ format (text). EnSight parts are represented as OBJ groups.
Demonstrates reading steady-state geometry, node coordinates,
connectivity using traditional I/O.
For commandline usage, run the script with ``--help``.
"""
import argparse
import re
import sys
from typing import Optional
import numpy as np
import ensightreader
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("ensight_case", metavar="*.case", help="input EnSight Gold case (C Binary)")
parser.add_argument("output_obj", metavar="*.obj", help="output OBJ file (text)")
parser.add_argument("--only-parts", metavar="regex", help="only export parts matching given "
"regular expression (Python re.search)")
args = parser.parse_args()
ensight_case_path = args.ensight_case
output_obj_path = args.output_obj
part_name_regex = args.only_parts
return ensight2obj(ensight_case_path, output_obj_path, part_name_regex)
def ensight2obj(ensight_case_path: str, output_obj_path: str, part_name_regex: Optional[str] = None) -> int:
"""Main function of ensight2obj.py"""
print("Reading input EnSight case", ensight_case_path)
case = ensightreader.read_case(ensight_case_path)
geofile = case.get_geometry_model()
print("I see", len(geofile.get_part_names()), "parts in case")
parts = []
for part_id, part in geofile.parts.items():
if not part.is_surface():
print("Skipping part", part.part_name, "(not a surface part)")
elif part_name_regex and not re.search(part_name_regex, part.part_name):
print("Skipping part", part.part_name, "(name doesn't match)")
else:
parts.append(part)
print("Reading nodes...")
node_arrays = []
with geofile.open() as fp_geo:
for part in parts:
node_array = part.read_nodes(fp_geo)
node_arrays.append(node_array)
all_nodes = np.vstack(node_arrays)
number_of_nodes = all_nodes.shape[0]
print("Writing output OBJ", output_obj_path)
# OBJ uses uses global vertex numbering, starting from 1.
# EnSight uses per-part vertex numbering, starting from 1.
# To accommodate this, we need to increment the IDs for subsequent EnSight parts.
node_id_offset = 0
with open(output_obj_path, "w") as fp_obj, geofile.open() as fp_geo:
print(f"Writing {number_of_nodes} nodes...", flush=True)
for i in range(number_of_nodes):
print("v", *all_nodes[i], file=fp_obj)
for i, part in enumerate(parts):
print(f"Writing part {part.part_name}...", flush=True)
print("g", part.part_name, file=fp_obj) # translate EnSight parts to OBJ groups
for block in part.element_blocks:
if block.element_type.dimension != 2:
print(f"\tSkipping {block.number_of_elements} {block.element_type.value} elements", flush=True)
continue
print(f"\tWriting {block.number_of_elements} {block.element_type.value} elements", flush=True)
print("#", block.element_type.value, file=fp_obj)
if block.element_type == block.element_type.NSIDED:
polygon_node_counts, polygon_connectivity = block.read_connectivity_nsided(fp_geo)
polygon_connectivity += node_id_offset
k = 0
for j in range(len(polygon_node_counts)):
node_count = polygon_node_counts[j]
print("f", *(polygon_connectivity[k:k + node_count]), file=fp_obj)
k += node_count
else:
connectivity = block.read_connectivity(fp_geo)
connectivity += node_id_offset
for j in range(connectivity.shape[0]):
print("f", *(connectivity[j]), file=fp_obj)
node_id_offset += part.number_of_nodes
print("\nAll done.")
return 0
if __name__ == "__main__":
sys.exit(main())