Skip to content

Commit 6b74cfd

Browse files
committed
fix: updating point/surface export and constructor
adding properties, allowing file streams adding from_dict and extending to_dict methods
1 parent 26edd3f commit 6b74cfd

File tree

2 files changed

+122
-15
lines changed

2 files changed

+122
-15
lines changed

LoopStructural/datatypes/_point.py

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from dataclasses import dataclass
22
import numpy as np
33

4-
from typing import Optional
4+
from typing import Optional, Union
5+
import io
56

67

78
@dataclass
@@ -16,6 +17,9 @@ def to_dict(self):
1617
"locations": self.locations,
1718
"values": self.values,
1819
"name": self.name,
20+
"properties": (
21+
{k: p.tolist() for k, p in self.properties.items()} if self.properties else None
22+
),
1923
}
2024

2125
def vtk(self):
@@ -25,9 +29,14 @@ def vtk(self):
2529
points["values"] = self.values
2630
return points
2731

28-
def save(self, filename):
29-
filename = str(filename)
30-
ext = filename.split('.')[-1]
32+
def save(self, filename: Union[str, io.StringIO], ext=None):
33+
if isinstance(filename, io.StringIO):
34+
if ext is None:
35+
raise ValueError('Please provide an extension for StringIO')
36+
ext = ext.lower()
37+
else:
38+
ext = filename.split('.')[-1].lower()
39+
filename = str(filename)
3140
if ext == 'json':
3241
import json
3342

@@ -49,9 +58,29 @@ def save(self, filename):
4958
from LoopStructural.export.gocad import _write_pointset
5059

5160
_write_pointset(self, filename)
61+
elif ext == 'csv':
62+
import pandas as pd
63+
64+
df = pd.DataFrame(self.locations, columns=['x', 'y', 'z'])
65+
df['value'] = self.values
66+
if self.properties is not None:
67+
for k, v in self.properties.items():
68+
df[k] = v
69+
df.to_csv(filename, index=False)
5270
else:
5371
raise ValueError(f'Unknown file extension {ext}')
5472

73+
@classmethod
74+
def from_dict(cls, d, flatten=False):
75+
if 'locations' not in d:
76+
raise ValueError('locations not in dictionary')
77+
locations = np.array(d['locations'])
78+
if flatten:
79+
locations = locations.reshape((-1, 3))
80+
return ValuePoints(
81+
locations, d.get('values', None), d.get('name', 'unnamed'), d.get('properties', None)
82+
)
83+
5584

5685
@dataclass
5786
class VectorPoints:
@@ -65,8 +94,14 @@ def to_dict(self):
6594
"locations": self.locations,
6695
"vectors": self.vectors,
6796
"name": self.name,
97+
"properties": (
98+
{k: p.tolist() for k, p in self.properties.items()} if self.properties else None
99+
),
68100
}
69101

102+
def from_dict(self, d):
103+
return VectorPoints(d['locations'], d['vectors'], d['name'], d.get('properties', None))
104+
70105
def vtk(self, geom='arrow', scale=1.0, scale_function=None, tolerance=0.05):
71106
import pyvista as pv
72107

@@ -108,5 +143,16 @@ def save(self, filename):
108143
from LoopStructural.export.gocad import _write_pointset
109144

110145
_write_pointset(self, filename)
146+
elif ext == 'csv':
147+
import pandas as pd
148+
149+
df = pd.DataFrame(self.locations, columns=['x', 'y', 'z'])
150+
df['vx'] = self.vectors[:, 0]
151+
df['vy'] = self.vectors[:, 1]
152+
df['vz'] = self.vectors[:, 2]
153+
if self.properties is not None:
154+
for k, v in self.properties.items():
155+
df[k] = v
156+
df.to_csv(filename)
111157
else:
112158
raise ValueError(f'Unknown file extension {ext}')

LoopStructural/datatypes/_surface.py

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
from dataclasses import dataclass
22
from typing import Optional
33
import numpy as np
4+
import io
45

56

67
@dataclass
78
class Surface:
89
vertices: np.ndarray
910
triangles: np.ndarray
10-
normals: np.ndarray
11-
name: str
11+
normals: Optional[np.ndarray] = None
12+
name: str = 'surface'
1213
values: Optional[np.ndarray] = None
1314
properties: Optional[dict] = None
15+
cell_properties: Optional[dict] = None
1416

1517
@property
1618
def triangle_area(self):
@@ -75,26 +77,77 @@ def vtk(self):
7577
surface = pv.PolyData.from_regular_faces(self.vertices, self.triangles)
7678
if self.values is not None:
7779
surface["values"] = self.values
80+
if self.properties is not None:
81+
for k, v in self.properties.items():
82+
surface.point_data[k] = np.array(v)
83+
if self.cell_properties is not None:
84+
for k, v in self.cell_properties.items():
85+
surface.cell_data[k] = np.array(v)
7886
return surface
7987

80-
def to_dict(self):
88+
def to_dict(self, flatten=False):
89+
triangles = self.triangles
90+
vertices = self.vertices
91+
if flatten:
92+
vertices = self.vertices.flatten()
93+
triangles = (
94+
np.hstack([np.ones((self.triangles.shape[0], 1)) * 3, self.triangles])
95+
.astype(int)
96+
.flatten()
97+
)
8198
return {
82-
"vertices": self.vertices,
83-
"triangles": self.triangles,
84-
"normals": self.normals,
99+
"vertices": vertices.tolist(),
100+
"triangles": triangles.tolist(),
101+
"normals": self.normals.tolist() if self.normals is not None else None,
102+
"properties": (
103+
{k: p.tolist() for k, p in self.properties.items()} if self.properties else None
104+
),
105+
"cell_properties": (
106+
{k: p.tolist() for k, p in self.cell_properties.items()}
107+
if self.cell_properties
108+
else None
109+
),
85110
"name": self.name,
86-
"values": self.values,
111+
"values": self.values.tolist() if self.values is not None else None,
87112
}
88113

89-
def save(self, filename):
90-
filename = str(filename)
91-
ext = filename.split('.')[-1]
114+
@classmethod
115+
def from_dict(cls, d, flatten=False):
116+
vertices = np.array(d['vertices'])
117+
triangles = np.array(d['triangles'])
118+
if flatten:
119+
vertices = vertices.reshape((-1, 3))
120+
triangles = triangles.reshape((-1, 4))[:, 1:]
121+
return cls(
122+
vertices,
123+
triangles,
124+
np.array(d['normals']),
125+
d['name'],
126+
np.array(d['values']),
127+
d.get('properties', None),
128+
d.get('cell_properties', None),
129+
)
130+
131+
def save(self, filename, ext=None):
132+
import pyvista as pv
133+
134+
print(filename, ext)
135+
if isinstance(filename, (io.StringIO, io.BytesIO)):
136+
if ext is None:
137+
raise ValueError('Please provide an extension for StringIO')
138+
ext = ext.lower()
139+
else:
140+
filename = str(filename)
141+
if ext is None:
142+
ext = filename.split('.')[-1].lower()
143+
92144
if ext == 'json':
93145
import json
94146

95147
with open(filename, 'w') as f:
96148
json.dump(self.to_dict(), f)
97149
elif ext == 'vtk':
150+
print(filename)
98151
self.vtk().save(filename)
99152
elif ext == 'obj':
100153
import meshio
@@ -105,7 +158,7 @@ def save(self, filename):
105158
[("triangle", self.triangles)],
106159
point_data={"normals": self.normals},
107160
)
108-
elif ext == 'ts':
161+
elif ext == 'ts' or ext == 'gocad':
109162
from LoopStructural.export.exporters import _write_feat_surfs_gocad
110163

111164
_write_feat_surfs_gocad(self, filename)
@@ -119,5 +172,13 @@ def save(self, filename):
119172

120173
with open(filename, 'wb') as f:
121174
pickle.dump(self, f)
175+
elif ext == 'csv':
176+
import pandas as pd
177+
178+
df = pd.DataFrame(self.vertices, columns=['x', 'y', 'z'])
179+
if self.properties:
180+
for k, v in self.properties.items():
181+
df[k] = v
182+
df.to_csv(filename, index=False)
122183
else:
123184
raise ValueError(f"Extension {ext} not supported")

0 commit comments

Comments
 (0)