Skip to content

Commit

Permalink
add ex. slab_vol.py madcad1.py
Browse files Browse the repository at this point in the history
  • Loading branch information
marcomusy committed Nov 24, 2023
1 parent fc1f48e commit 92ee4c6
Show file tree
Hide file tree
Showing 9 changed files with 241 additions and 40 deletions.
7 changes: 6 additions & 1 deletion docs/changes.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
## Main changes

- fixes to `extrude()` thanks to @JeffreyWardman
- filter out triangle strips in Ribbon and extrude()
- improvements in doc strings
- add `utils.madcad2vedo` conversion as per #976 by @JeffreyWardman
- add `utils.camera_to_dict()`

## Breaking changes
- improvements to `shapes.Ellipsoid()` and bug fixes in #978 by @daniel-a-diaz
- improvements to `pointcloud.pca_ellipsoid()` and bug fixes
- improvements to `pointcloud.pca_ellipse()` and bug fixes


### Renaming


### Other changes
- add `core.apply_transform_from_actor()`
- add `add volume.slab()`
Expand All @@ -23,6 +26,8 @@

## New/Revised Examples
```
examples/volumetric/slab_vol.py
examples/other/madcad1.py
```

### Broken Examples
Expand Down
55 changes: 55 additions & 0 deletions examples/other/madcad1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Example of usage of the madcad library
# See https://pymadcad.readthedocs.io/en/latest/index.html
import vedo
from madcad import *

##########################################################################
points = [O, X, X + Z, 2 * X + Z, 2 * (X + Z), X + 2 * Z, X + 5 * Z, 5 * Z]
section = Wire(points).segmented().flip()
rev = revolution(2 * pi, (O, Z), section)
rev.mergeclose()
vedo.show("Revolution of a wire", rev, axes=7).close()


##########################################################################
m = screw(10, 20)
m["part"].option(color=vec3(70, 130, 180) / 255) # RGB
vedo.show("A blue screw", m, axes=1).close()


##########################################################################
# Obtain two different shapes that has noting to to with each other
m1 = brick(width=vec3(2))
m2 = m1.transform(vec3(0.5, 0.3, 0.4)).transform(quat(0.7 * vec3(1, 1, 0)))
# Remove the volume of the second to the first
diff = difference(m1, m2)
vedo.show("Boolean difference", diff, axes=14).close()


##########################################################################
cube = brick(width=vec3(2))
bevel(
cube,
[(0, 1), (1, 2), (2, 3), (0, 3), (1, 5), (0, 4)], # Edges to smooth
("width", 0.3), # Cutting description, known as 'cutter'
)
vedo.show("A bevel cube", cube, axes=1).close()


##########################################################################
square_profile = square((O, Z), 5).flip()
primitives = [
ArcCentered((5 * X, Y), O, 10 * X),
ArcCentered((15 * X, -Y), 10 * X, 20 * X),
]
# Generate a path
path = web(primitives)
path.mergeclose()
m = tube(square_profile, path)

vmesh = vedo.utils.madcad2vedo(m) # <-- convert to vedo.Mesh
print(vmesh)

scalar = vmesh.vertices[:, 0]
vmesh.cmap("rainbow", scalar).add_scalarbar(title="x-value")
vedo.show("Generating a path", vmesh, axes=7).close()
20 changes: 20 additions & 0 deletions examples/volumetric/slab_vol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Use slab() to extract a "thick" 2D slice from a 3D volume"""
from vedo import Axes, Volume, Box, dataurl, settings, show
from vedo.pyplot import histogram

settings.default_font = "Calco"

vol = Volume(dataurl + "embryo.tif")
vaxes = Axes(vol, xygrid=False)

slab = vol.slab([45,55], axis='z', operation='mean')
slab.cmap('Set1_r', vmin=10, vmax=80).add_scalarbar("intensity")
# histogram(slab).show().close() # quickly inspect it

bbox = slab.metadata["slab_bounding_box"]
slab.z(-bbox[5] + vol.zbounds()[0]) # move slab to the bottom

# create a box around the slab for reference
slab_box = Box(bbox).wireframe().c("black")

show(__doc__, vol, slab, slab_box, vaxes, axes=14, viewup='z')
2 changes: 1 addition & 1 deletion vedo/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ def box(self, scale=1, padding=0):
padding = [padding, padding, padding]
length, width, height = b[1] - b[0], b[3] - b[2], b[5] - b[4]
tol = (length + width + height) / 30000 # useful for boxing text
pos = [(b[0] + b[1]) / 2, (b[3] + b[2]) / 2, (b[5] + b[4]) / 2 - tol]
pos = [(b[0] + b[1])/2, (b[3] + b[2])/2, (b[5] + b[4])/2 - tol]
bx = vedo.shapes.Box(
pos,
length * scale + padding[0],
Expand Down
3 changes: 3 additions & 0 deletions vedo/plotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3040,6 +3040,9 @@ def _scan_input_return_acts(self, objs):

scanned_acts.append(dlf.MeshActor(a).actor)

elif "madcad" in str(type(a)):
scanned_acts.append(utils.madcad2vedo(a))

else:
vedo.logger.error(f"cannot understand input in show(): {type(a)}")

Expand Down
15 changes: 11 additions & 4 deletions vedo/shapes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3312,14 +3312,24 @@ def __init__(
![](https://vedo.embl.es/images/simulations/50738955-7e891800-11d9-11e9-85cd-02bd4f3f13ea.gif)
"""
src = vtk.new("CubeSource")

if len(pos) == 2:
pos = (pos[0], pos[1], 0)

if len(pos) == 6:
src.SetBounds(pos)
pos = [0,0,0]
elif len(size) == 3:
length, width, height = size
src.SetXLength(length)
src.SetYLength(width)
src.SetZLength(height)
src.SetCenter(pos)
else:
src.SetXLength(length)
src.SetYLength(width)
src.SetZLength(height)
src.SetCenter(pos)

src.Update()
pd = src.GetOutput()

Expand Down Expand Up @@ -3352,9 +3362,6 @@ def __init__(
vtc = utils.numpy2vtk(tc)
pd.GetPointData().SetTCoords(vtc)
super().__init__(pd, c, alpha)
if len(pos) == 2:
pos = (pos[0], pos[1], 0)
self.pos(pos)
self.name = "Box"


Expand Down
153 changes: 126 additions & 27 deletions vedo/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
"ProgressBar",
"progressbar",
"geometry",
"extract_cells_by_type",
"is_sequence",
"lin_interpolate",
"vector",
Expand All @@ -41,6 +40,8 @@
"print_inheritance_tree",
"camera_from_quaternion",
"camera_from_neuroglancer",
"camera_from_dict",
"camera_to_dict",
"oriented_camera",
"vedo2trimesh",
"trimesh2vedo",
Expand Down Expand Up @@ -566,7 +567,7 @@ def make3d(pts):
return np.c_[pts, np.zeros(pts.shape[0], dtype=pts.dtype)]

if pts.shape[1] != 3:
raise ValueError("input shape is not supported.")
raise ValueError(f"input shape is not supported: {pts.shape}")
return pts


Expand All @@ -592,31 +593,6 @@ def geometry(obj, extent=None):
return vedo.Mesh(gf.GetOutput())


def extract_cells_by_type(obj, types=()):
"""
Extract cells of a specified type from a vtk dataset.
Given an input `vtkDataSet` and a list of cell types, produce an output
containing only cells of the specified type(s).
Find [here](https://vtk.org/doc/nightly/html/vtkCellType_8h_source.html)
the list of possible cell types.
Return:
a `vtkDataSet` object which can be wrapped.
"""
ef = vtk.new("ExtractCellsByType")
try:
ef.SetInputData(obj.dataset)
except AttributeError:
ef.SetInputData(obj)

for ct in types:
ef.AddCellType(ct)
ef.Update()
return ef.GetOutput()


def buildPolyData(vertices, faces=None, lines=None, index_offset=0, tetras=False):
"""
Build a `vtkPolyData` object from a list of vertices
Expand Down Expand Up @@ -1917,6 +1893,38 @@ def camera_from_dict(camera, modify_inplace=None):
if cm_roll is not None: vcam.SetRoll(cm_roll)
return vcam

def camera_to_dict(vtkcam):
"""
Convert a [vtkCamera](https://vtk.org/doc/nightly/html/classvtkCamera.html)
object into a python dictionary.
Parameters of the camera are:
- `position` (3-tuple)
- `focal_point` (3-tuple)
- `viewup` (3-tuple)
- `distance` (float)
- `clipping_range` (2-tuple)
- `parallel_scale` (float)
- `thickness` (float)
- `view_angle` (float)
- `roll` (float)
Arguments:
vtkcam: (vtkCamera)
a `vtkCamera` object to convert.
"""
cam = dict()
cam["position"] = np.array(vtkcam.GetPosition())
cam["focal_point"] = np.array(vtkcam.GetFocalPoint())
cam["viewup"] = np.array(vtkcam.GetViewUp())
cam["distance"] = vtkcam.GetDistance()
cam["clipping_range"] = np.array(vtkcam.GetClippingRange())
cam["parallel_scale"] = vtkcam.GetParallelScale()
cam["thickness"] = vtkcam.GetThickness()
cam["view_angle"] = vtkcam.GetViewAngle()
cam["roll"] = vtkcam.GetRoll()
return cam


def vtkCameraToK3D(vtkcam):
"""
Expand Down Expand Up @@ -2374,6 +2382,97 @@ def vedo2open3d(vedo_mesh):
return o3d_mesh


def madcad2vedo(madcad_mesh):
"""
Convert a `madcad.Mesh` to a `vedo.Mesh`.
See [pymadcad website](https://pymadcad.readthedocs.io/en/latest/index.html)
for more info.
"""
try:
madcad_mesh = madcad_mesh["part"]
except:
pass

ppp = []
for p in madcad_mesh.points:
ppp.append([float(p[0]), float(p[1]), float(p[2])])
ppp = np.array(ppp)

fff = []
try:
for f in madcad_mesh.faces:
fff.append([int(f[0]), int(f[1]), int(f[2])])
fff = np.array(fff).astype(np.uint16)
except AttributeError:
# print("no faces")
pass

eee = []
try:
edges = madcad_mesh.edges
for e in edges:
eee.append([int(e[0]), int(e[1])])
eee = np.array(eee).astype(np.uint16)
except (AttributeError, TypeError):
# print("no edges")
pass

try:
line = np.array(madcad_mesh.indices).astype(np.uint16)
eee.append(line)
except AttributeError:
# print("no indices")
pass

ttt = []
try:
for t in madcad_mesh.tracks:
ttt.append(int(t))
ttt = np.array(ttt).astype(np.uint16)
except AttributeError:
# print("no tracks")
pass

###############################
poly = vedo.utils.buildPolyData(ppp, fff, eee)
if len(fff) == 0 and len(eee) == 0:
m = vedo.Points(poly)
else:
m = vedo.Mesh(poly)

if len(ttt) == len(fff):
m.celldata["tracks"] = ttt
maxt = np.max(ttt)
m.mapper.SetScalarRange(0, np.max(ttt))
if maxt==0: m.mapper.SetScalarVisibility(0)
elif len(ttt) == len(ppp):
m.pointdata["tracks"] = ttt
maxt = np.max(ttt)
m.mapper.SetScalarRange(0, maxt)
if maxt==0: m.mapper.SetScalarVisibility(0)

try:
m.info["madcad_groups"] = madcad_mesh.groups
except AttributeError:
# print("no groups")
pass

try:
options = dict(madcad_mesh.options)
if "display_wire" in options and options["display_wire"]:
m.lw(1).lc(madcad_mesh.c())
if "display_faces" in options and not options["display_faces"]:
m.alpha(0.2)
if "color" in options:
m.c(options["color"])
except AttributeError:
# print("no options")
pass

return m


def vtk_version_at_least(major, minor=0, build=0):
"""
Check the installed VTK version.
Expand Down
2 changes: 1 addition & 1 deletion vedo/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
_version = '2023.5.0+dev6'
_version = '2023.5.0+dev7'
Loading

0 comments on commit 92ee4c6

Please sign in to comment.