def _grid_views_default(self): # This needs to generate the geometries and access the materials grid_views = [] cmap = mcm.get_cmap("inferno") for level in range(self.ds.max_level + 1): # We truncate at half of the colormap so that we just get a slight # linear progression color = mcolors.to_hex( cmap(self.cmap_truncate * level / self.ds.max_level)) # Corners is shaped like 8, 3, NGrids this_level = self.ds.index.grid_levels[:, 0] == level corners = np.rollaxis(self.ds.index.grid_corners[:, :, this_level], 2).astype("float32") indices = (((np.arange(corners.shape[0]) * 8)[:, None] + _CORNER_INDICES[None, :]).ravel().astype("uint32")) corners.shape = (corners.size // 3, 3) geometry = pythreejs.BufferGeometry(attributes=dict( position=pythreejs.BufferAttribute(array=corners, normalized=False), index=pythreejs.BufferAttribute(array=indices, normalized=False), )) material = pythreejs.LineBasicMaterial(color=color, linewidth=1, linecap="round", linejoin="round") segments = pythreejs.LineSegments(geometry=geometry, material=material) grid_views.append(segments) return grid_views
def mesh(self, colors={}): import pythreejs as js import numpy as np lines = [] line_colors = [] red = [1, 0, 0] green = [0, 1, 0] exterior = self.project(exterior=True) interior = self.project(exterior=False) for color, polygons in zip([green, red], [exterior, interior]): for polygon in polygons: for segment in polygon.segments(): lines.extend([segment.p1, segment.p2]) line_colors.extend([color, color]) lines = np.array(lines, dtype=np.float32) line_colors = np.array(line_colors, dtype=np.float32) geometry = js.BufferGeometry(attributes={ 'position': js.BufferAttribute(lines, normalized=False), 'color': js.BufferAttribute(line_colors, normalized=False), }, ) material = js.LineBasicMaterial(vertexColors='VertexColors', linewidth=1) return js.LineSegments(geometry, material)
def __add_line_geometry(self, lines, shading, obj=None): lines = lines.astype("float32", copy=False) mi = np.min(lines, axis=0) ma = np.max(lines, axis=0) geometry = p3s.BufferGeometry( attributes={ 'position': p3s.BufferAttribute(lines, normalized=False) }) material = p3s.LineBasicMaterial(linewidth=shading["line_width"], color=shading["line_color"]) #, vertexColors='VertexColors'), lines = p3s.LineSegments(geometry=geometry, material=material) #type='LinePieces') line_obj = { "geometry": geometry, "mesh": lines, "material": material, "max": ma, "min": mi, "type": "Lines", "wireframe": None } if obj: return self.__add_object(line_obj, obj), line_obj else: return self.__add_object(line_obj)
def __initialize_wireframe(self): edges_material = three.LineBasicMaterial(color='#686868', linewidth=1, depthTest=True, opacity=.2, transparent=True) wireframe = self.__get_wireframe_from_boundary() return three.LineSegments(wireframe, material=edges_material)
def _create_mesh(geometry, color, wireframe, position): if wireframe: edges = p3.EdgesGeometry(geometry) mesh = p3.LineSegments(geometry=edges, material=p3.LineBasicMaterial(color=color)) else: material = p3.MeshBasicMaterial(color=color) mesh = p3.Mesh(geometry=geometry, material=material) mesh.position = tuple(position.value) return mesh
def _create_outline(self, axparams): """ Make a wireframe cube with tick labels """ box_geometry = p3.BoxBufferGeometry( axparams['x']["lims"][1] - axparams['x']["lims"][0], axparams['y']["lims"][1] - axparams['y']["lims"][0], axparams['z']["lims"][1] - axparams['z']["lims"][0]) edges = p3.EdgesGeometry(box_geometry) self.outline = p3.LineSegments( geometry=edges, material=p3.LineBasicMaterial(color='#000000'), position=axparams["centre"]) self.axticks = self._generate_axis_ticks_and_labels(axparams)
def render_wireframe(mesh, up_vector=(0, 1, 0)): geometry = build_geometry( mesh.triangles, mesh.positions, normals=getattr(mesh, "normals", None), colors=getattr(mesh, "colors", None), ) obj = three.LineSegments( geometry=three.WireframeGeometry(geometry), material=three.LineBasicMaterial(color="green"), position=[0, 0, 0], ) center = np.array(mesh.positions).reshape(-1, 3).mean(axis=0) offset = 8 * np.array(mesh.positions).reshape(-1, 3).std(axis=0) return render_scene(Scene(eye_pos=center + offset, obj_pos=center, obj=obj, up=up_vector))
def to_edge_mesh(surf, mapper, prop, use_edge_coloring=True, use_lines=False): """Convert a pyvista surface to a three.js edge mesh.""" # extract all edges from the surface. Should not use triangular # mesh here as mesh may contain more than triangular faces if use_lines: edges_mesh = surf edges = segment_poly_cells(surf) else: edges_mesh = surf.extract_all_edges() edges = edges_mesh.lines.reshape(-1, 3)[:, 1:] attr = { 'position': array_to_float_buffer(edges_mesh.points), 'index': cast_to_min_size(edges, surf.n_points), } # add in colors coloring = get_coloring(mapper, surf) if coloring != 'NoColors' and not use_edge_coloring: if mapper.GetScalarModeAsString() == 'UsePointData': edge_scalars = edges_mesh.point_data.active_scalars edge_colors = map_scalars(mapper, edge_scalars) attr['color'] = array_to_float_buffer(edge_colors) edge_geo = tjs.BufferGeometry(attributes=attr) mesh_attr = {} if coloring != 'NoColors': mesh_attr['vertexColors'] = coloring if use_edge_coloring: edge_color = prop.GetEdgeColor() else: edge_color = prop.GetColor() edge_mat = tjs.LineBasicMaterial(color=color_to_hex(edge_color), linewidth=prop.GetLineWidth(), opacity=prop.GetOpacity(), side='FrontSide', **mesh_attr) return tjs.LineSegments(edge_geo, edge_mat)
def create_outline(self): """ Make a wireframe cube with tick labels """ box_geometry = p3.BoxBufferGeometry( self.xminmax['x'][1] - self.xminmax['x'][0], self.xminmax['y'][1] - self.xminmax['y'][0], self.xminmax['z'][1] - self.xminmax['z'][0]) edges = p3.EdgesGeometry(box_geometry) outline = p3.LineSegments( geometry=edges, material=p3.LineBasicMaterial(color='#000000'), position=[ 0.5 * np.sum(self.xminmax['x']), 0.5 * np.sum(self.xminmax['y']), 0.5 * np.sum(self.xminmax['z']) ]) ticks_and_labels = self.generate_axis_ticks_and_labels() return outline, ticks_and_labels
def visualize(self, colors={}): from ..space import Vector import pythreejs as js import numpy as np prior = Motion(x=0, y=0, z=0, f=0) lines = [] line_colors = [] for parent, command in self.commands(): if isinstance(command, Motion): updated = prior.merge(command) pv = Vector(*prior.xyz) uv = Vector(*updated.xyz) delta = pv - uv start = (uv + pv) / 2 lines.extend([prior.xyz, updated.xyz]) a1 = delta.rotate(Vector(0, 0, 1), tau / 16) * 0.1 a2 = delta.rotate(Vector(0, 0, 1), -tau / 16) * 0.1 lines.extend( [start, (a1 + start).xyz, start, (a2 + start).xyz]) prior = updated color = getattr(parent, 'color', [0, 1, 0]) line_colors.extend([color, color]) line_colors.extend([color, color]) line_colors.extend([color, color]) lines = np.array(lines, dtype=np.float32) line_colors = np.array(line_colors, dtype=np.float32) geometry = js.BufferGeometry(attributes={ 'position': js.BufferAttribute(lines, normalized=False), 'color': js.BufferAttribute(line_colors, normalized=False), }, ) material = js.LineBasicMaterial(vertexColors='VertexColors', linewidth=1) return js.LineSegments(geometry, material)
def add_mesh(self, v, f, c=None, uv=None, shading={}, texture_data=None): sh = self.__get_shading(shading) mesh_obj = {} #it is a tet if v.shape[1] == 3 and f.shape[1] == 4: f_tmp = np.ndarray([f.shape[0]*4, 3], dtype=f.dtype) for i in range(f.shape[0]): f_tmp[i*4+0] = np.array([f[i][1], f[i][0], f[i][2]]) f_tmp[i*4+1] = np.array([f[i][0], f[i][1], f[i][3]]) f_tmp[i*4+2] = np.array([f[i][1], f[i][2], f[i][3]]) f_tmp[i*4+3] = np.array([f[i][2], f[i][0], f[i][3]]) f = f_tmp if v.shape[1] == 2: v = np.append(v, np.zeros([v.shape[0], 1]), 1) # Type adjustment vertices v = v.astype("float32", copy=False) # Color setup colors, coloring = self.__get_colors(v, f, c, sh) # Type adjustment faces and colors c = colors.astype("float32", copy=False) # Material and geometry setup ba_dict = {"color": p3s.BufferAttribute(c)} if coloring == "FaceColors": verts = np.zeros((f.shape[0]*3, 3), dtype="float32") for ii in range(f.shape[0]): #print(ii*3, f[ii]) verts[ii*3] = v[f[ii,0]] verts[ii*3+1] = v[f[ii,1]] verts[ii*3+2] = v[f[ii,2]] v = verts else: f = f.astype("uint32", copy=False).ravel() ba_dict["index"] = p3s.BufferAttribute(f, normalized=False) ba_dict["position"] = p3s.BufferAttribute(v, normalized=False) if type(uv) != type(None): uv = (uv - np.min(uv)) / (np.max(uv) - np.min(uv)) if texture_data is None: texture_data = gen_checkers(20, 20) tex = p3s.DataTexture(data=texture_data, format="RGBFormat", type="FloatType") material = p3s.MeshStandardMaterial(map=tex, reflectivity=sh["reflectivity"], side=sh["side"], roughness=sh["roughness"], metalness=sh["metalness"], flatShading=sh["flat"], polygonOffset=True, polygonOffsetFactor= 1, polygonOffsetUnits=5) ba_dict["uv"] = p3s.BufferAttribute(uv.astype("float32", copy=False)) else: material = p3s.MeshStandardMaterial(vertexColors=coloring, reflectivity=sh["reflectivity"], side=sh["side"], roughness=sh["roughness"], metalness=sh["metalness"], flatShading=sh["flat"], polygonOffset=True, polygonOffsetFactor= 1, polygonOffsetUnits=5) geometry = p3s.BufferGeometry(attributes=ba_dict) if coloring == "VertexColors": geometry.exec_three_obj_method('computeVertexNormals') else: geometry.exec_three_obj_method('computeFaceNormals') # Mesh setup mesh = p3s.Mesh(geometry=geometry, material=material) # Wireframe setup mesh_obj["wireframe"] = None if sh["wireframe"]: wf_geometry = p3s.WireframeGeometry(mesh.geometry) # WireframeGeometry wf_material = p3s.LineBasicMaterial(color=sh["wire_color"], linewidth=sh["wire_width"]) wireframe = p3s.LineSegments(wf_geometry, wf_material) mesh.add(wireframe) mesh_obj["wireframe"] = wireframe # Bounding box setup if sh["bbox"]: v_box, f_box = self.__get_bbox(v) _, bbox = self.add_edges(v_box, f_box, sh, mesh) mesh_obj["bbox"] = [bbox, v_box, f_box] # Object setup mesh_obj["max"] = np.max(v, axis=0) mesh_obj["min"] = np.min(v, axis=0) mesh_obj["geometry"] = geometry mesh_obj["mesh"] = mesh mesh_obj["material"] = material mesh_obj["type"] = "Mesh" mesh_obj["shading"] = sh mesh_obj["coloring"] = coloring mesh_obj["arrays"] = [v, f, c] # TODO replays with proper storage or remove if not needed return self.__add_object(mesh_obj)
def _render_obj(self, rendered_obj, **kw): obj_geometry = pjs.BufferGeometry(attributes=dict( position=pjs.BufferAttribute(rendered_obj.plot_verts), color=pjs.BufferAttribute(rendered_obj.base_cols), normal=pjs.BufferAttribute( rendered_obj.face_normals.astype('float32')))) vertices = rendered_obj.vertices # Create a mesh. Note that the material need to be told to use the vertex colors. my_object_mesh = pjs.Mesh( geometry=obj_geometry, material=pjs.MeshLambertMaterial(vertexColors='VertexColors'), position=[0, 0, 0], ) line_material = pjs.LineBasicMaterial(color='#ffffff', transparent=True, opacity=0.3, linewidth=1.0) my_object_wireframe_mesh = pjs.LineSegments( geometry=obj_geometry, material=line_material, position=[0, 0, 0], ) n_vert = vertices.shape[0] center = vertices.mean(axis=0) extents = self._get_extents(vertices) max_delta = np.max(extents[:, 1] - extents[:, 0]) camPos = [center[i] + 4 * max_delta for i in range(3)] light_pos = [center[i] + (i + 3) * max_delta for i in range(3)] # Set up a scene and render it: camera = pjs.PerspectiveCamera(position=camPos, fov=20, children=[ pjs.DirectionalLight( color='#ffffff', position=light_pos, intensity=0.5) ]) camera.up = (0, 0, 1) v = [0.0, 0.0, 0.0] if n_vert > 0: v = vertices[0].tolist() select_point_geom = pjs.SphereGeometry(radius=1.0) select_point_mesh = pjs.Mesh( select_point_geom, material=pjs.MeshBasicMaterial(color=SELECTED_VERTEX_COLOR), position=v, scale=(0.0, 0.0, 0.0)) #select_edge_mesh = pjs.ArrowHelper(dir=pjs.Vector3(1.0, 0.0, 0.0), origin=pjs.Vector3(0.0, 0.0, 0.0), length=1.0, # hex=SELECTED_EDGE_COLOR_INT, headLength=0.1, headWidth=0.05) arrow_cyl_mesh = pjs.Mesh(geometry=pjs.SphereGeometry(radius=0.01), material=pjs.MeshLambertMaterial()) arrow_head_mesh = pjs.Mesh(geometry=pjs.SphereGeometry(radius=0.001), material=pjs.MeshLambertMaterial()) scene_things = [ my_object_mesh, my_object_wireframe_mesh, select_point_mesh, arrow_cyl_mesh, arrow_head_mesh, camera, pjs.AmbientLight(color='#888888') ] if self.draw_grids: grids, space = self._get_grids(vertices) scene_things.append(grids) scene = pjs.Scene(children=scene_things, background=BACKGROUND_COLOR) click_picker = pjs.Picker(controlling=my_object_mesh, event='dblclick') out = Output() top_msg = HTML() def on_dblclick(change): if change['name'] == 'point': try: point = np.array(change['new']) face = click_picker.faceIndex face_points = rendered_obj.face_verts[face] face_vecs = face_points - np.roll(face_points, 1, axis=0) edge_lens = np.sqrt((face_vecs**2).sum(axis=1)) point_vecs = face_points - point[np.newaxis, :] point_dists = (point_vecs**2).sum(axis=1) min_point = np.argmin(point_dists) v1s = point_vecs.copy() v2s = np.roll(v1s, -1, axis=0) edge_mids = 0.5 * (v2s + v1s) edge_mid_dists = (edge_mids**2).sum(axis=1) min_edge_point = np.argmin(edge_mid_dists) edge_start = min_edge_point edge = face * 3 + edge_start close_vert = rendered_obj.face_verts[face, min_point] edge_start_vert = rendered_obj.face_verts[face, edge_start] edge_end_vert = rendered_obj.face_verts[face, (edge_start + 1) % 3] vertex = face * 3 + min_point radius = min( [edge_lens.max() * 0.02, 0.1 * edge_lens.min()]) edge_head_length = radius * 4 edge_head_width = radius * 2 select_point_mesh.scale = (radius, radius, radius) top_msg.value = '<font color="{}">selected face: {}</font>, <font color="{}">edge: {}</font>, <font color="{}"> vertex: {}</font>'.format( SELECTED_FACE_COLOR, face, SELECTED_EDGE_COLOR, edge, SELECTED_VERTEX_COLOR, vertex) newcols = rendered_obj.base_cols.copy() newcols[face * 3:(face + 1) * 3] = np.array( SELECTED_FACE_RGB, dtype='float32') select_point_mesh.position = close_vert.tolist() obj_geometry.attributes['color'].array = newcols with out: make_arrow(arrow_cyl_mesh, arrow_head_mesh, edge_start_vert, edge_end_vert, radius / 2, radius, radius * 3, SELECTED_EDGE_COLOR) except: with out: print(traceback.format_exc()) click_picker.observe(on_dblclick, names=['point']) renderer_obj = pjs.Renderer( camera=camera, background='#cccc88', background_opacity=0, scene=scene, controls=[pjs.OrbitControls(controlling=camera), click_picker], width=self.width, height=self.height) display_things = [top_msg, renderer_obj, out] if self.draw_grids: s = """ <svg width="{}" height="30"> <rect width="20" height="20" x="{}" y="0" style="fill:none;stroke-width:1;stroke:rgb(0,255,0)" /> <text x="{}" y="15">={:.1f}</text> Sorry, your browser does not support inline SVG. </svg>""".format(self.width, self.width // 2, self.width // 2 + 25, space) display_things.append(HTML(s)) display(VBox(display_things))
def _get_grids(self, obj_vertices): extents = self._get_extents(obj_vertices) grid_verts = [] deltas = [extent[1] - extent[0] for extent in extents] max_extent = max(deltas) space1 = 10.0**pymath.floor( pymath.log(max_extent) / pymath.log(10.0) - 0.5) space2 = 2 * 10.0**pymath.floor( pymath.log(max_extent / 2.0) / pymath.log(10.0) - 0.5) space = space2 if max_extent / space2 < 5: space = space1 N = int(pymath.floor(max_extent / space + 2.0)) grid_cols = [] axis_cols = ['#ff3333', '#33ff33', '#3333ff'] ends = [] for axis1 in range(3): start = pymath.floor(extents[axis1][0] / space) * space ends.append(start + space * N) for axis2 in range(3): axis3 = [x for x in [0, 1, 2] if x not in [axis1, axis2]][0] if axis1 == axis2: continue delta = extents[axis1][1] - extents[axis1][0] start2 = pymath.floor(extents[axis2][0] / space) * space end2 = start2 + (N - 1) * space verts = self._get_grid_lines(axis1, start, space, N, axis2, start2, end2) grid_verts.extend(verts) grid_cols.extend([axis_cols[axis3] for vert in verts]) # now draw the X,Y,Z labels: char_width = max_extent * 0.05 char_lines = [] # X: char_lines_x = [] char_lines_x.append([[0.0, 0.0], [1.0, 1.0]]) char_lines_x.append([[0.0, 1.0], [1.0, 0.0]]) char_lines.append(char_lines_x) # Y: char_lines_y = [] char_lines_y.append([[0.5, 0.0], [0.5, 0.5]]) char_lines_y.append([[0.5, 0.5], [0.0, 1.0]]) char_lines_y.append([[0.5, 0.5], [1.0, 1.0]]) char_lines.append(char_lines_y) # Z: char_lines_z = [] char_lines_z.append([[1.0, 1.0], [0.0, 1.0]]) char_lines_z.append([[0.0, 1.0], [1.0, 0.0]]) char_lines_z.append([[1.0, 0.0], [0.0, 0.0]]) char_lines.append(char_lines_z) for iaxis in range(3): ax1 = [0, 1, 2][iaxis] ax2 = [2, 2, 1][iaxis] char_lns = char_lines[iaxis] segs = [[[0, 0], [ends[iaxis] + char_width, 0]], [[ends[iaxis] + char_width, 0], [ends[iaxis] + 0.5 * char_width, 0.5 * char_width]], [[ends[iaxis] + char_width, 0], [ends[iaxis] + 0.5 * char_width, -0.5 * char_width]]] for seg in segs: for pt in seg: pt3 = [0, 0, 0] pt3[ax1] += pt[0] pt3[ax2] += pt[1] grid_verts.append(pt3) grid_cols.append('#000000') for seg in char_lns: for pt in seg: pt3 = [0, 0, 0] pt3[iaxis] += ends[iaxis] + 2 * char_width pt3[ax1] += pt[0] * char_width pt3[ax2] += 1.2 * (pt[1] - 0.5) * char_width grid_verts.append(pt3) grid_cols.append('#000000') lines_geom = pjs.Geometry(vertices=grid_verts, colors=grid_cols) lines = pjs.LineSegments(geometry=lines_geom, material=pjs.LineBasicMaterial( linewidth=self.grid_lines_width, transparent=True, opacity=0.5, dashSize=10, gapSize=10, vertexColors='VertexColors'), type='LinePieces') return lines, space