From 2d245b33384f9bff78c817305285dfab108c36d0 Mon Sep 17 00:00:00 2001 From: marcomusy Date: Sun, 18 Jun 2023 17:36:16 +0200 Subject: [PATCH] prerelease --- docs/changes.md | 20 +---- examples/advanced/cut_with_points2.py | 2 +- examples/advanced/interpolate_field.py | 24 +++--- .../basic/{bgImage.py => background_image.py} | 0 examples/pyplot/graph_lineage.py | 2 +- examples/pyplot/graph_network.py | 4 +- examples/pyplot/plot_stream.py | 4 +- examples/simulations/airplane1.py | 22 +++--- examples/simulations/airplane2.py | 13 ++-- examples/simulations/particle_simulator.py | 10 ++- examples/simulations/pendulum_3d.py | 17 ++-- examples/simulations/trail.py | 2 +- vedo/addons.py | 22 +++++- vedo/plotter.py | 78 +++++-------------- vedo/pointcloud.py | 75 ++++++++++-------- vedo/version.py | 2 +- 16 files changed, 134 insertions(+), 163 deletions(-) rename examples/basic/{bgImage.py => background_image.py} (100%) diff --git a/docs/changes.md b/docs/changes.md index 83a089d5..44ac8b7a 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -45,31 +45,13 @@ examples/advanced/timer_callback3.py examples/advanced/warp6.py examples/pyplot/histo_1d_e.py examples/other/tensor_grid2.py +examples/simulations/airplane1.py examples/simulations/lorenz.py examples/simulations/gas.py examples/simulations/aspring2_player.py ``` ### Broken Examples -``` -airplane1.py -examples/simulations/trail.py -particle_simulator.py -``` -align4.py -bgImage.py -colormap_list.py -mousehover3.py -cut_with_points2.py -interpolate_field.py -goniometer.py -pendulum_3d.pyq - -graph_lineage.py -graph_network.py -markpoint.py -plot_stream.py - meshio_read.py diff --git a/examples/advanced/cut_with_points2.py b/examples/advanced/cut_with_points2.py index 8ee08874..f3db19d0 100644 --- a/examples/advanced/cut_with_points2.py +++ b/examples/advanced/cut_with_points2.py @@ -18,4 +18,4 @@ line = Line(pts, closed=True).lw(5).c("green3") -show([(mesh, line), (cmesh, line, __doc__)], N=2, axes=1) +show([(mesh, line), (cmesh, line, __doc__)], N=2).close() diff --git a/examples/advanced/interpolate_field.py b/examples/advanced/interpolate_field.py index c008e88b..92a51d11 100644 --- a/examples/advanced/interpolate_field.py +++ b/examples/advanced/interpolate_field.py @@ -1,10 +1,5 @@ -"""Interpolate a vectorial field using: - -Thin Plate Spline or Radial Basis Function. - -Example shows how to share the same Camera -between different Plotter windows. -""" +"""Interpolate a vectorial field using +Thin Plate Spline or Radial Basis Function""" from scipy.interpolate import Rbf from vedo import Plotter, Points, Arrows, show import numpy as np @@ -29,15 +24,15 @@ src = Points(sources, c="r", r=12) trs = Points(sources + deltas, c="v", r=12) -arr = Arrows(sources, sources + deltas) +arr = Arrows(sources, sources + deltas).color("k8") ################################################# warp using Thin Plate Splines warped = apos.clone().warp(sources, sources+deltas) warped.alpha(0.4).color("lg").point_size(10) -allarr = Arrows(apos.points(), warped.points()) +allarr = Arrows(apos.points(), warped.points()).color("k8") set1 = [apos, warped, src, trs, arr, __doc__] -plt1 = show([set1, allarr], N=2, bg='bb') # returns the Plotter class +plt1 = show([set1, allarr], N=2, bg='bb', interactive=0) # returns the Plotter class ################################################# RBF @@ -54,16 +49,15 @@ positions_rbf = np.vstack([positions_x, positions_y, positions_z]) warped_rbf = Points(positions_rbf, r=2).alpha(0.4).color("lg").point_size(10) -allarr_rbf = Arrows(apos.points(), warped_rbf.points()) +allarr_rbf = Arrows(apos.points(), warped_rbf.points()).color("k8") -arr = Arrows(sources, sources + deltas) +arr = Arrows(sources, sources + deltas).color("k8") plt2 = Plotter(N=2, pos=(200, 300), bg='bb') -plt2.camera = plt1.camera # share the same camera with previous Plotter - plt2.at(0).show("Radial Basis Function", apos, warped_rbf, src, trs, arr) plt2.at(1).show(allarr_rbf) +plt2.interactive() -plt2.interactive().close() +plt2.close() plt1.close() diff --git a/examples/basic/bgImage.py b/examples/basic/background_image.py similarity index 100% rename from examples/basic/bgImage.py rename to examples/basic/background_image.py diff --git a/examples/pyplot/graph_lineage.py b/examples/pyplot/graph_lineage.py index cca42628..df72c92f 100644 --- a/examples/pyplot/graph_lineage.py +++ b/examples/pyplot/graph_lineage.py @@ -12,7 +12,7 @@ # Vertex generation is automatic, # add a child to vertex0, so that now vertex1 exists -g.add_child(0, edge_label="Mother giving birth\nto her baby cell") +g.add_child(0, edge_label="Mother cell") g.add_child(1); g.add_child(1) g.add_child(2); g.add_child(2); g.add_child(2) g.add_child(3); g.add_child(3, edge_label="daughter_38") diff --git a/examples/pyplot/graph_network.py b/examples/pyplot/graph_network.py index a7b579f3..86edc824 100644 --- a/examples/pyplot/graph_network.py +++ b/examples/pyplot/graph_network.py @@ -33,11 +33,11 @@ # Interpolate the node value to color the edges: graph.cmap('viridis', v2).add_scalarbar3d(c='k') -graph.scalarbar.shift(.3,0,0) +graph.scalarbar.shift(0.15,0,0).use_bounds(True) pts.cmap('viridis', v2) # This would colorize the edges directly with solid color based on a v3 array: # v3 = [sin(x) for x in range(graph.ncells)] # graph.cmap('jet', v3).add_scalarbar() -show(pts, graph, labs1, labs2, __doc__, axes=9, mode="image").close() +show(pts, graph, labs1, labs2, __doc__, zoom='tight').close() diff --git a/examples/pyplot/plot_stream.py b/examples/pyplot/plot_stream.py index 63065b2f..9a3fecfe 100644 --- a/examples/pyplot/plot_stream.py +++ b/examples/pyplot/plot_stream.py @@ -1,7 +1,7 @@ """Plot streamlines of the 2D field: -u(x,y) = -1 - x\^2 + y -v(x,y) = 1 + x - y\^2 +u(x,y) = -1 - x:^2 + y +v(x,y) = 1 + x - y:^2 """ from vedo import Points, show from vedo.pyplot import streamplot diff --git a/examples/simulations/airplane1.py b/examples/simulations/airplane1.py index 51387c8e..9ab4e7d0 100644 --- a/examples/simulations/airplane1.py +++ b/examples/simulations/airplane1.py @@ -1,20 +1,20 @@ -"""Draw the shadow and trailing line of a flying plane. Not really -a simulation.. just a way to illustrate how to move objects around!""" +"""Draw the shadow and trailing line of a moving object.""" from vedo import * world = Box(size=(30,15,8)).wireframe() airplane = Mesh(dataurl+"cessna.vtk").c("green") +airplane.pos(-15, 2.0, 0.15) +airplane.add_trail(n=100).add_shadow('z', -4) -plt = Plotter(axes=1, interactive=False) +plt = Plotter(interactive=False) +plt.show(world, airplane, __doc__, viewup="z") -for t in np.arange(0, 3.2, 0.02): - - # make up some movement - airplane.pos(9*t-15, 2-t, sin(3-t)).rotate_x(t) - if t==0: - airplane.add_trail(n=200).add_shadow('z', -4) - plt.show(world, airplane, __doc__, viewup="z", resetcam=False) - # plt.process_events() +for t in np.arange(0, 3.2, 0.04): + pos = (9*t-15, 2-t, sin(3-t)) # make up some movement + airplane.pos(pos).rotate_x(t) + airplane.update_trail() + airplane.update_shadows() + plt.render() plt.interactive().close() diff --git a/examples/simulations/airplane2.py b/examples/simulations/airplane2.py index 63441874..3cb35a05 100644 --- a/examples/simulations/airplane2.py +++ b/examples/simulations/airplane2.py @@ -5,19 +5,22 @@ world = Box([0,0,0], 30, 16, 8).wireframe() plane1 = Mesh(dataurl+"cessna.vtk").c("green") -plane1.pos(-15, 2, 0.14).add_trail(n=200) +plane1.pos(-15, 2, 0.15).add_trail(n=100) plane1.add_shadow('z', -4).add_shadow('y', 8) plane2 = plane1.clone().c("tomato") -plane2.pos(-15,-2,-0.21).add_trail(n=200) +plane2.pos(-15,-2,-0.20).add_trail(n=100) plane2.add_shadow('z', -4).add_shadow('y', 8) # Setup the scene -plt = Plotter(axes=1, interactive=False) +plt = Plotter(interactive=False) +plt.show(world, plane1, plane2, __doc__, viewup="z") -for t in np.arange(0, 3.2, 0.02): +for t in np.arange(0, 3.2, 0.04): plane1.pos(9*t-15, 2-t, sin(3-t)).rotate_x(0+t) # make up some movement plane2.pos(8*t-15, t-2, sin(t-3)).rotate_x(2-t) # for the 2 planes - plt.show(world, plane1, plane2, __doc__, viewup="z") + plane1.update_trail().update_shadows() + plane2.update_trail().update_shadows() + plt.render() plt.interactive().close() diff --git a/examples/simulations/particle_simulator.py b/examples/simulations/particle_simulator.py index b191f6e9..6aad4175 100644 --- a/examples/simulations/particle_simulator.py +++ b/examples/simulations/particle_simulator.py @@ -59,8 +59,12 @@ def simulate(self): a.vel += ftot / a.mass * self.dt # update velocity and position of a a.pos += a.vel * self.dt a.vsphere.pos(a.pos) - if plt: - plt.show(resetcam=not i, azimuth=1) + a.vsphere.update_trail() + if plt: + if i==0: + plt.reset_camera() + plt.azimuth(1) + plt.render() class Particle: @@ -86,7 +90,7 @@ def __init__(self, pos, charge, mass, radius, color, vel, fixed, negligible): self.negligible = negligible self.color = color if plt: - self.vsphere = Sphere(pos, r=radius, c=color).add_trail(lw=0.1, n=100, alpha=0.2) + self.vsphere = Sphere(pos, r=radius, c=color).add_trail(lw=1, n=75, alpha=0.5) plt.add(self.vsphere) # Sphere representing the particle diff --git a/examples/simulations/pendulum_3d.py b/examples/simulations/pendulum_3d.py index 0245adf4..77621769 100644 --- a/examples/simulations/pendulum_3d.py +++ b/examples/simulations/pendulum_3d.py @@ -1,4 +1,4 @@ -"""Double pendulum in 3D (press ESC to quit)""" +"""Double pendulum in 3D""" # Original idea and solution using sympy from: # https://www.youtube.com/watch?v=MtG9cueB548 from vedo import * @@ -13,8 +13,8 @@ ball1.add_shadow('z', -3) ball2.add_shadow('z', -3) -ball1.add_trail(n=20) -ball2.add_trail(n=20) +ball1.add_trail(n=10) +ball2.add_trail(n=10) ball1.trail.add_shadow('z', -3) # make trails project a shadow too ball2.trail.add_shadow('z', -3) @@ -25,7 +25,7 @@ # show the solution plt = Plotter(interactive=False) -plt.show(axes, __doc__, viewup='z') +plt.show(ball1, ball2, rod1, rod2, axes, __doc__, viewup='z') i = 0 for b1, b2 in zip(p1,p2): @@ -33,10 +33,13 @@ ball2.pos(b2) rod1.stretch([0,0,0], b1) rod2.stretch(b1, b2) - # show at max frame rate of 15 Hz - plt.show(ball1, ball2, rod1, rod2, resetcam=False, rate=15) + ball1.update_shadows().update_trail() + ball2.update_shadows().update_trail() + ball1.trail.update_shadows() + ball2.trail.update_shadows() + plt.render() i+=1 - if i > 50: + if i > 150: break plt.interactive().close() diff --git a/examples/simulations/trail.py b/examples/simulations/trail.py index 14f98558..b483f4fa 100644 --- a/examples/simulations/trail.py +++ b/examples/simulations/trail.py @@ -16,7 +16,7 @@ plt += [s, p, __doc__] for i in range(150): - p.pos(-2+i/100.0, sin(i/5.0)/15, 0) + p.pos(-2+i/100.0, sin(i/5.0)/15, 0).update_trail() plt.show(azimuth=-0.2) # stay interactive and after pressing q close diff --git a/vedo/addons.py b/vedo/addons.py index 62813135..657e814d 100644 --- a/vedo/addons.py +++ b/vedo/addons.py @@ -3926,7 +3926,7 @@ def Axes( return asse -def add_global_axes(axtype=None, c=None): +def add_global_axes(axtype=None, c=None, bounds=()): """ Draw axes on scene. Available axes types are @@ -3993,15 +3993,31 @@ def add_global_axes(axtype=None, c=None): # custom grid walls if plt.axes == 1 or plt.axes is True or isinstance(plt.axes, dict): + if len(bounds) == 6: + bnds = bounds + xrange = (bnds[0], bnds[1]) + yrange = (bnds[2], bnds[3]) + zrange = (bnds[4], bnds[5]) + else: + xrange=None + yrange=None + zrange=None + if isinstance(plt.axes, dict): plt.axes.update({"use_global": True}) # protect from invalid camelCase options from vedo<=2.3 for k in plt.axes: if k.lower() != k: return - asse = Axes(None, **plt.axes) + if "xrange" in plt.axes: + xrange = plt.axes.pop("xrange") + if "yrange" in plt.axes: + yrange = plt.axes.pop("yrange") + if "zrange" in plt.axes: + zrange = plt.axes.pop("zrange") + asse = Axes(**plt.axes, xrange=xrange, yrange=yrange, zrange=zrange) else: - asse = Axes(None, use_global=True) + asse = Axes(xrange=xrange, yrange=yrange, zrange=zrange) plt.renderer.AddActor(asse) plt.axes_instances[r] = asse diff --git a/vedo/plotter.py b/vedo/plotter.py index 4d6833e8..e72d7317 100644 --- a/vedo/plotter.py +++ b/vedo/plotter.py @@ -833,39 +833,13 @@ def add(self, *actors, at=None): if ren: ren.AddActor(a) + if hasattr(a, "rendered_at"): + ir = self.renderers.index(ren) + a.rendered_at.add(ir) + if hasattr(a, "scalarbar") and a.scalarbar: ren.AddActor(a.scalarbar) - if hasattr(a, "shadows") and a.shadows: - - # shad_acs = ren.GetActors() - # shad_acs.InitTraversal() - # for _ in range(shad_acs.GetNumberOfItems()): - # a = shad_acs.GetNextItem() - # try: - # if a.name == "Shadow": - # ren.RemoveActor(a) - # except AttributeError: - # pass - - for sha in a.shadows: - ren.RemoveActor(sha) # BUG? - - a.update_shadows() - # print(a.shadows) - # for sha in a.shadows: - # ren.AddActor(sha) - - if hasattr(a, "trail") and a.trail: - a.update_trail() - ren.AddActor(a.trail) - - # trails may also have shadows: - if a.trail.shadows: - a.trail.update_shadows() - for sha in a.trail.shadows: - ren.AddActor(sha) - return self def remove(self, *actors, at=None): @@ -2884,7 +2858,6 @@ def show( - 10 = Image - Check out `vedo.interaction_modes` for more options. """ - if self.wx_widget: return self @@ -2960,37 +2933,24 @@ def show( return backends.get_notebook_backend(self.actors) ######################################################################### - # # remove all old shadows from the scene - # shad_acs = self.renderer.GetActors() - # shad_acs.InitTraversal() - # for _ in range(shad_acs.GetNumberOfItems()): - # a = shad_acs.GetNextItem() - # try: - # if a.name == "Shadow": - # self.renderer.RemoveActor(a) - # except AttributeError: - # pass - - for ia in actors: - + for ia in utils.flatten(actors): + if isinstance(ia, vedo.base.Base3DProp): if ia._isfollower: # set by mesh.follow_camera() ia.SetCamera(self.camera) - ia.rendered_at.add(at) # set.add() - - # if ia.scalarbar: - # self.renderer.AddActor(ia.scalarbar) - # # fix gray color labels and title to white or black - # if isinstance(ia.scalarbar, vtk.vtkScalarBarActor): - # ltc = np.array(ia.scalarbar.GetLabelTextProperty().GetColor()) - # if np.linalg.norm(ltc - (0.5, 0.5, 0.5)) / 3 < 0.05: - # c = (0.9, 0.9, 0.9) - # if np.sum(self.renderer.GetBackground()) > 1.5: - # c = (0.1, 0.1, 0.1) - # ia.scalarbar.GetLabelTextProperty().SetColor(c) - # ia.scalarbar.GetTitleTextProperty().SetColor(c) + try: + # fix gray color labels and title to white or black + ltc = np.array(ia.scalarbar.GetLabelTextProperty().GetColor()) + if np.linalg.norm(ltc - (0.5, 0.5, 0.5)) / 3 < 0.05: + c = (0.9, 0.9, 0.9) + if np.sum(self.renderer.GetBackground()) > 1.5: + c = (0.1, 0.1, 0.1) + ia.scalarbar.GetLabelTextProperty().SetColor(c) + ia.scalarbar.GetTitleTextProperty().SetColor(c) + except AttributeError: + pass if self.sharecam: for r in self.renderers: @@ -2999,9 +2959,11 @@ def show( if self.qt_widget is not None: self.qt_widget.GetRenderWindow().AddRenderer(self.renderer) + if self.axes is not None: if viewup != "2d" or self.axes in [1, 8] or isinstance(self.axes, dict): - addons.add_global_axes(self.axes) + bns = self.renderer.ComputeVisiblePropBounds() + addons.add_global_axes(self.axes, bounds=bns) ######################################################################### if settings.default_backend in ["ipyvtk", "trame"]: diff --git a/vedo/pointcloud.py b/vedo/pointcloud.py index 65379b95..27ac4068 100644 --- a/vedo/pointcloud.py +++ b/vedo/pointcloud.py @@ -1316,7 +1316,37 @@ def update_trail(self): tpoly = self.trail.polydata(False) tpoly.GetPoints().SetData(utils.numpy2vtk(data, dtype=np.float32)) self.trail.SetPosition(currentpos) + return self + + def _compute_shadow(self, plane, point, direction): + shad = self.clone() + shad._data.GetPointData().SetTCoords(None) # remove any texture coords + shad.name = "Shadow" + + pts = shad.points() + if plane == 'x': + # shad = shad.project_on_plane('x') + # instead do it manually so in case of alpha<1 + # we dont see glitches due to coplanar points + # we leave a small tolerance of 0.1% in thickness + x0, x1 = self.xbounds() + pts[:, 0] = (pts[:, 0] - (x0 + x1) / 2) / 1000 + self.GetOrigin()[0] + shad.points(pts) + shad.x(point) + elif plane == 'y': + x0, x1 = self.ybounds() + pts[:, 1] = (pts[:, 1] - (x0 + x1) / 2) / 1000 + self.GetOrigin()[1] + shad.points(pts) + shad.y(point) + elif plane == "z": + x0, x1 = self.zbounds() + pts[:, 2] = (pts[:, 2] - (x0 + x1) / 2) / 1000 + self.GetOrigin()[2] + shad.points(pts) + shad.z(point) + else: + shad = shad.project_on_plane(plane, point, direction) + return shad def add_shadow(self, plane, point, direction=None, c=(0.6, 0.6, 0.6), alpha=1, culling=0): """ @@ -1347,33 +1377,7 @@ def add_shadow(self, plane, point, direction=None, c=(0.6, 0.6, 0.6), alpha=1, c ![](https://vedo.embl.es/images/simulations/57341963-b8910900-713c-11e9-898a-84b6d3712bce.gif) """ - shad = self.clone() - shad._data.GetPointData().SetTCoords(None) # remove any texture coords - shad.name = "Shadow" - - pts = shad.points() - if plane == 'x': - # shad = shad.project_on_plane('x') - # instead do it manually so in case of alpha<1 - # we dont see glitches due to coplanar points - # we leave a small tolerance of 0.1% in thickness - x0, x1 = self.xbounds() - pts[:, 0] = (pts[:, 0] - (x0 + x1) / 2) / 1000 + self.GetOrigin()[0] - shad.points(pts) - shad.x(point) - elif plane == 'y': - x0, x1 = self.ybounds() - pts[:, 1] = (pts[:, 1] - (x0 + x1) / 2) / 1000 + self.GetOrigin()[1] - shad.points(pts) - shad.y(point) - elif plane == "z": - x0, x1 = self.zbounds() - pts[:, 2] = (pts[:, 2] - (x0 + x1) / 2) / 1000 + self.GetOrigin()[2] - shad.points(pts) - shad.z(point) - else: - shad = shad.project_on_plane(plane, point, direction) - + shad = self._compute_shadow(plane, point, direction) shad.c(c).alpha(alpha) try: @@ -1399,12 +1403,14 @@ def update_shadows(self): """ Update the shadows of a moving object. """ - shadows = list(self.shadows) - self.shadows = [] - for sha in shadows: - color = sha.GetProperty().GetColor() - opacity = sha.GetProperty().GetOpacity() - self.add_shadow(**sha.info, c=color, alpha=opacity) + for sha in self.shadows: + plane = sha.info['plane'] + point = sha.info['point'] + direction = sha.info['direction'] + new_sha = self._compute_shadow(plane, point, direction) + sha._update(new_sha._data) + return self + def delete_cells_by_point_index(self, indices): """ @@ -2286,7 +2292,8 @@ def flagpole( macts = vedo.merge(acts).c(c).alpha(alpha) macts.SetOrigin(pt) - macts.bc("t").pickable(False).GetProperty().LightingOff() + macts.bc("tomato").pickable(False) + macts.GetProperty().LightingOff() macts.GetProperty().SetLineWidth(lw) macts.UseBoundsOff() macts.name = "FlagPole" diff --git a/vedo/version.py b/vedo/version.py index e0a93eb1..c47b9afb 100644 --- a/vedo/version.py +++ b/vedo/version.py @@ -1 +1 @@ -_version = '2023.4.4.dev29' +_version = '2023.4.5'