def box(min=[0, 0, 0], max=[1, 1, 1], filled=False, color=QColor("blue"), effect_f=CustomEffects.material, matrix=np.eye(4, dtype='f4'), name="box"): color = ensure_QColor(color) indices = [0,1,3, 3,2,0, 7,5,4, 4,6,7, 4,5,1, 1,0,4, 5,7,3, 3,1,5, 6,2,3, 3,7,6, 4,0,2, 2,6,4] if filled else\ [0,1, 1,3, 3,2, 2,0, 4,5, 5,7, 7,6, 6,4, 0,4, 1,5, 2,6, 3,7] vertices = [ [min[0], min[1], min[2]] #0 , [min[0], min[1], max[2]] #1 , [min[0], max[1], min[2]] #2 , [min[0], max[1], max[2]] #3 , [max[0], min[1], min[2]] #4 , [max[0], min[1], max[2]] #5 , [max[0], max[1], min[2]] #6 , [max[0], max[1], max[2]] #7 ] normals = [ [-0.577350269, -0.577350269, -0.577350269] #0 , [-0.577350269, -0.577350269, 0.577350269] #1 , [-0.577350269, 0.577350269, -0.577350269] #2 , [-0.577350269, 0.577350269, 0.577350269] #3 , [0.577350269, -0.577350269, -0.577350269] #4 , [0.577350269, -0.577350269, 0.577350269] #5 , [0.577350269, 0.577350269, -0.577350269] #6 , [0.577350269, 0.577350269, 0.577350269] #7 ] return Actors.Actor( geometry=Geometry.Geometry( indices=Array.Array(ndarray=np.array(indices, 'u4')), attribs=Geometry.Attribs( vertices=Array.Array(ndarray=np.array(vertices, 'f4')), normals=Array.Array(ndarray=np.array(normals, 'f4'))), primitive_type=Geometry.PrimitiveType.TRIANGLES if filled else Geometry.PrimitiveType.LINES), effect=effect_f(color) if filled else CustomEffects.emissive(color), transform=ensure_Transform(matrix), name=name)
def __init__(self, parent=None): super(DasSampleToCloud, self).__init__(parent) self._sample = None self._seg3DSample = None self._referential = None self._undistort = False self._undistortRefTs = -1 self._primitiveType = Geometry.PrimitiveType.POINTS self._indices = Array.ArrayUInt1() self._indices.set_producer(self) self._amplitudes = Array.ArrayFloat1() self._amplitudes.set_producer(self) self._colors = Array.ArrayFloat4() self._colors.set_producer(self) self._transform = Transforms.Transform() self._transform.set_producer(self) self._minAmplitude = np.nan self._maxAmplitude = np.nan self._hasReferential = True self._logScale = False self._method = None self._amplitudeRatio = 100 #call setters: self.method = 'point_cloud' self.sample = Product.VariantProduct() self.seg3DSample = Product.VariantProduct()
def lines(indices, vertices, color=QColor("blue"), matrix=np.eye(4, dtype='f4'), name="lines"): color = ensure_QColor(color) return Actors.Actor(geometry=Geometry.Geometry( indices=Array.Array(ndarray=indices), attribs=Geometry.Attribs(vertices=Array.Array(ndarray=vertices)), primitive_type=Geometry.PrimitiveType.LINES), effect=CustomEffects.emissive(color), transform=ensure_Transform(matrix), name=name)
def colored_point_cloud(points, colors, matrix=np.eye(4, dtype='f4'), name="pcl"): #color = ensure_QColor(color) return Actors.Actor(geometry=Geometry.Geometry( attribs=CustomAttribs.ColorsAttribs( vertices=Array.Array(ndarray=points), colors=Array.Array(ndarray=colors)), primitive_type=Geometry.PrimitiveType.POINTS), effect=CustomEffects.point_colors(), transform=ensure_Transform(matrix), name=name)
def quad(top_left=[0, 0, 0], bottom_left=[0, 1, 0], bottom_right=[1, 1, 0], top_right=None, texcoords=[[0, 0], [0, 1], [1, 1], [1, 0]], filled=False, color=QColor("blue"), effect_f=CustomEffects.material, textures=None, matrix=np.eye(4, dtype='f4'), name="quad"): color = ensure_QColor(color) top_left = utils.to_numpy(top_left) bottom_left = utils.to_numpy(bottom_left) bottom_right = utils.to_numpy(bottom_right) v_top = top_left - bottom_left v_right = bottom_right - bottom_left if top_right is None: top_right = bottom_right + v_top else: top_right = utils.to_numpy(top_right) indices = [0, 1, 2, 3, 0, 2 ] if filled else [0, 1, 1, 2, 2, 0, 3, 0, 0, 2, 2, 3] vertices = np.vstack((top_left, bottom_left, bottom_right, top_right)) normals = np.empty_like(vertices) n = np.cross(v_right, v_top) normals[:] = n / np.linalg.norm(n) if textures is not None: effect = effect_f(textures=textures, color=color) else: effect = effect_f(color=color) return Actors.Actor(geometry=Geometry.Geometry( indices=Array.Array(ndarray=np.array(indices, 'u4')), attribs=CustomAttribs.TexcoordsAttribs( vertices=Array.Array(ndarray=np.array(vertices, 'f4')), normals=Array.Array(ndarray=np.array(normals, 'f4')), texcoords0=Array.Array(ndarray=np.array(texcoords, 'f4'))), primitive_type=Geometry.PrimitiveType.TRIANGLES if filled else Geometry.PrimitiveType.LINES), effect=effect, transform=ensure_Transform(matrix), name=name)
def __init__(self, parent=None): super(TracesGeometry, self).__init__(parent) self.ndarray = np.empty((0, 2), dtype=np.float32) #inputs: self._traces = None self._specs = None #outputs: self._indices = Array.ArrayUInt1() self._indices.set_producer(self) self._saturationIndices = Array.ArrayUInt1() self._saturationIndices.set_producer(self)
def text(text, font="Arial", font_size=6, line_width=1, color=QColor("blue"), matrix=np.eye(4, dtype='f4'), is_billboard=True, name="text", scale=0.1, origin=[0, 0, 0], u=[1, 0, 0], v=[0, 1, 0], w=[0, 0, 1]): ''' Warning, this function can crash if called before any call to QApplication(sys.argv) ''' color = ensure_QColor(color) origin = utils.to_numpy(origin) u = utils.to_numpy(u) v = utils.to_numpy(v) w = utils.to_numpy(w) indices = [] vertices = [] path = QPainterPath() path.addText(QPointF(0, 0), QFont(font, font_size), text) polygons = path.toSubpathPolygons() for polygon in polygons: for point in polygon: indices.append(len(vertices)) p = utils.to_numpy([point.x(), point.y(), 0]) * scale vertices.append(origin + p[0] * u + p[1] * v + p[2] * w) indices.append(-1) return Actors.Actor(geometry=Geometry.Geometry( indices=Array.Array(ndarray=np.array(indices, 'u4')), attribs=Geometry.Attribs(vertices=Array.Array( ndarray=np.array(vertices, 'f4'))), primitive_type=Geometry.PrimitiveType.LINE_LOOP), effect=CustomEffects.emissive( color, line_width=line_width, is_billboard=is_billboard), transform=ensure_Transform(matrix), name=f"{name}_{text}")
def __init__(self, parent=None): super(ROSStereoCalibratorFilter, self).__init__(parent=parent) self._imageArrayRight = None self._images_right = [] self._leftCalibPath = "" self._rightCalibPath = "" self._rightImageResult = Array.Array() self._rightImageResult.set_producer(self)
def from_mesh(mesh, color=QColor("blue"), effect_f=CustomEffects.material, scale=1, matrix=np.eye(4, dtype='f4'), name="mesh"): color = ensure_QColor(color) mesh.add_attribute("vertex_normal") return Actors.Actor(geometry=Geometry.Geometry( indices=Array.Array(ndarray=mesh.faces.flatten().astype('u4')), attribs=Geometry.Attribs( vertices=Array.Array(ndarray=mesh.vertices.astype('f4') * scale), normals=Array.Array(ndarray=mesh.get_vertex_attribute( "vertex_normal").astype('f4'))), primitive_type=Geometry.PrimitiveType.TRIANGLES), effect=effect_f(color=color), transform=ensure_Transform(matrix), name=name)
def __init__(self, parent=None): super(CloudBase, self).__init__(parent) self.ndarray = np.empty((0, 3), dtype=np.float32) #inputs: self._bankSelection = [] #empty means all self._packages = None self._specs = None #outputs: self._indices = Array.ArrayUInt1() self._indices.set_producer(self) self._minAmplitude = np.nan self._maxAmplitude = np.nan self._amplitudes = Array.ArrayFloat1() self._amplitudes.set_producer(self) self._banks = Array.ArrayUInt1() self._banks.set_producer(self) self._directions = None self._quad_directions = None
def axes(size=1, matrix=np.eye(4, dtype='f4'), line_width=1, name="axes"): indices = [0, 1, 2, 3, 4, 5] vertices = [ [0, 0, 0] #0 , [size, 0, 0] #1 , [0, 0, 0] #2 , [0, size, 0] #3 , [0, 0, 0] #4 , [0, 0, size] #5 ] colors = [ [1, 0, 0] #red , [1, 0, 0] #red , [0, 1, 0] #green , [0, 1, 0] #green , [0, 0, 1] #blue , [0, 0, 1] #blue ] return Actors.Actor( geometry=Geometry.Geometry( indices=Array.Array(ndarray=np.array(indices, 'u4')), attribs=CustomAttribs.ColorsAttribs( vertices=Array.Array(ndarray=np.array(vertices, 'f4')), colors=Array.Array(ndarray=np.array(colors, 'f4'))), primitive_type=Geometry.PrimitiveType.LINES), effect=CustomEffects.point_colors(line_width=line_width), transform=ensure_Transform(matrix), name=name)
def bbox(c=[0, 0, 0], d=[0, 0, 0], r=[0, 0, 0], color=QColor("blue"), effect_f=CustomEffects.material, matrix=np.eye(4, dtype='f4'), name="bbox", return_anchor=False, draw_orientation=True): color = ensure_QColor(color) indices = [ 0, 1, 1, 3, 3, 2, 2, 0, 4, 5, 5, 7, 7, 6, 6, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] vertices = linalg.bbox_to_8coordinates(c, d, r) vertices = np.vstack([vertices, np.mean(vertices[[5, 7]], axis=0)]) if draw_orientation: # add central front point # and indices to draw the direction arrow indices += [1, 8, 3, 8] text_anchor = vertices[np.argmin(np.sum(vertices, axis=1))] vertices = vertices.astype('f4') actor = Actors.Actor(geometry=Geometry.Geometry( indices=Array.Array(ndarray=np.array(indices, 'u4')), attribs=Geometry.Attribs(vertices=Array.Array(ndarray=vertices)), primitive_type=Geometry.PrimitiveType.LINES), effect=CustomEffects.emissive(color), transform=ensure_Transform(matrix), name=name) if return_anchor: return actor, vertices[-1] else: return actor
def colored_quad_cloud(points, amplitude, indices, colormap="viridis", log_scale=False, cm_resolution=256, matrix=np.eye(4, dtype='f4'), color=None, name="quad"): #color = ensure_QColor(color) min_amplitude = float(amplitude.min()) max_amplitude = float(amplitude.max()) if log_scale: norm = mpl_colors.LogNorm(1, cm_resolution) else: norm = mpl_colors.Normalize(0, cm_resolution) colormap_ = getattr(cm, colormap)(norm(np.arange(cm_resolution))) cm_array = np.ascontiguousarray(colormap_ * 255, dtype=np.uint8) if color is None: effect = CustomEffects.color_map(Array.Array(ndarray=cm_array), amplitude.min(), amplitude.max()) else: effect = CustomEffects.material(color=color) return Actors.Actor(geometry=Geometry.Geometry( indices=Array.Array(ndarray=indices), attribs=CustomAttribs.ColorsAttribs( vertices=Array.Array(ndarray=points), colors=Array.Array(ndarray=amplitude)), primitive_type=Geometry.PrimitiveType.TRIANGLES), effect=effect, transform=ensure_Transform(matrix), name=name)
def colormap_point_cloud(points, amplitude, min_amplitude=None, max_amplitude=None, colormap="viridis", log_scale=False, cm_resolution=256, matrix=np.eye(4, dtype='f4'), name="cmap_pcl"): """ resolution: the color map texture resolution, it affect granularity/precision of the color distribution only """ if min_amplitude is None: min_amplitude = float(amplitude.min()) if max_amplitude is None: max_amplitude = float(amplitude.max()) if log_scale: norm = mpl_colors.LogNorm(1, cm_resolution) else: norm = mpl_colors.Normalize(0, cm_resolution) colormap_ = getattr(cm, colormap)(norm(np.arange(cm_resolution))) cm_array = np.ascontiguousarray(colormap_ * 255, dtype=np.uint8) return Actors.Actor(geometry=Geometry.Geometry( attribs=CustomAttribs.AmplitudeAttribs( vertices=Array.Array(ndarray=points), amplitude=Array.Array(ndarray=amplitude)), primitive_type=Geometry.PrimitiveType.POINTS), effect=CustomEffects.color_map( Array.Array(ndarray=cm_array), min_amplitude, max_amplitude), transform=ensure_Transform(matrix), name=name)
def __init__(self): super(InFboRenderer, self).__init__() self.vertices_array = None self.sorted_actors = [] self.vertex_array = None self.render_to_texture = None self.render_to_texture_attachment = -1 self.render_to_texture_array = None self.locked_render_to_texture_array = Array.Array( ndarray=np.empty((0, 0, 4), np.uint8)) self.draw_buffers = [ GL.GL_COLOR_ATTACHMENT0, GL.GL_COLOR_ATTACHMENT1, GL.GL_COLOR_ATTACHMENT2, GL.GL_COLOR_ATTACHMENT3, GL.GL_COLOR_ATTACHMENT4 ]
def synchronize(self, viewport): # This function is called by Qt before calling render() # render() will then be called from another thread, which means anything # collected here (e.g. sorted_actors) should *not* be accessed during the rendering # I should map all buffers during synchronize, and copy all uniforms and whatnot viewport.setMirrorVertically(True) if self.vertex_array is None: # window = viewport.window() # gl_context = window.openglContext() # profile = QOpenGLVersionProfile() # profile.setProfile(QSurfaceFormat.CoreProfile) # profile.setVersion( 4, 1 ) # self.gl = gl_context.versionFunctions(profile) self.vertex_array = QOpenGLVertexArrayObject() self.vertex_array.create() self.background_color = viewport._backgroundColor self.sorted_actors = [] self.bo_actors = [] self.out_textures = {} if viewport.actors is None: return sorted_actors = sorted(list(viewport.actors.get_visible_actors()), key=attrgetter('renderRank')) sorted_actors.extend(viewport._debug_actors.get_visible_actors()) for actor in sorted_actors: if not actor.update(): if not hasattr(actor, "__error_reported___" ) or not actor.__error_reported___: LoggingManager.instance().warning("Not rendering actor " + str(actor) + ". It is has error " + str(actor._error) + ".") actor.__error_reported___ = True actor.productDirty.connect(lambda actor=actor: setattr( actor, "__error_reported___", False)) continue if not hasattr(actor, 'bo_actor'): actor.bo_actor = {} actor.productDirty.connect( lambda actor=actor: setattr(actor, "bo_actor", {})) if not actor.bo_actor: # actor was dirty or is new indices = actor.geometry.indices attribs = actor.geometry.attribs.get_attributes() bo_actor = { "attribs": {}, "textures": {}, "out_textures": {}, "uniforms": copy.deepcopy(actor.effect.shader0.uniforms), "indices": None, "program": actor.effect.shader0._program, "point_size": actor.effect.pointSize, "line_width": actor.effect.lineWidth, "transform": actor.transform.worldTransform() if actor.transform else QMatrix4x4(), "primitiveType": actor.geometry.primitiveType, "actor_not_thread_safe": actor } for name, value in viewitems(attribs): if value is None: continue self.attach_buffer_object(value, QOpenGLBuffer.VertexBuffer) value.___bo___.bind() self.map_buffer_object( value.___bo___, value.ndarray.astype('f4') if value.ndarray.dtype == np.float64 else value.ndarray) value.___bo___.release() bo_actor["attribs"][name] = value.___bo___ for name, value in viewitems(actor.effect.shader0.textures): if value is None: LoggingManager.instance().warning( 'texture {} is null'.format(name)) continue self.attach_texture_object(value) if value.___tex___.target() != self.to_texture_target( value): LoggingManager.instance().warning( 'expected texture target {}, got {}'.format( value.___tex___.target(), self.to_texture_target(array))) value.___tex___ = None self.attach_texture_object(value) if value.___tex___.dirty: tex_ndarray = value.ndarray if value.___tex___.target() == QOpenGLTexture.Target1D: value.___tex___.setSize(tex_ndarray.shape[0]) if value.___tex___.target() == QOpenGLTexture.Target2D: value.___tex___.setSize(tex_ndarray.shape[0], tex_ndarray.shape[1]) if value.___tex___.target() == QOpenGLTexture.Target3D: value.___tex___.setSize(tex_ndarray.shape[0], tex_ndarray.shape[1], tex_ndarray.shape[2]) value.___tex___.setFormat(QOpenGLTexture.RGBA8_UNorm) value.___tex___.allocateStorage() value.___tex___.setData(QOpenGLTexture.RGBA, QOpenGLTexture.UInt8, tex_ndarray.data) value.___tex___.shape = value.ndarray.shape value.___tex___.dtype = value.ndarray.dtype value.___tex___.dirty = False bo_actor["textures"][name] = value.___tex___ for name, value in viewitems( actor.effect.shader0.outputTextures): if value is None: LoggingManager.instance().warning( f'output texture {name} is null') continue self.goc_output_texture(value) bo_actor["out_textures"][name] = value.___tex___ self.out_textures[value.___tex___] = None if indices is not None and indices.size > 0: self.attach_buffer_object(indices, QOpenGLBuffer.IndexBuffer) indices.___bo___.bind() self.map_buffer_object(indices.___bo___, indices.ndarray) indices.___bo___.release() bo_actor["indices"] = indices.___bo___ actor.bo_actor = bo_actor self.sorted_actors.append(actor) self.bo_actors.append(actor.bo_actor) self.view_matrix = viewport.view_matrix() self.perspective_matrix = viewport.perspective_matrix() self.orthographic_matrix = viewport.orthographic_matrix() self.viewport_width = int(viewport.width()) self.viewport_height = int(viewport.height()) if viewport.render_to_texture_attachment != -1: old = self.render_to_texture_array self.render_to_texture_array = self.locked_render_to_texture_array self.locked_render_to_texture_array = old if old is not None else Array.Array( ndarray=np.empty((0, 0, 4), np.uint8)) if self.render_to_texture_attachment != viewport.render_to_texture_attachment: self.del_render_to_texture_attachment() self.render_to_texture_attachment = viewport.render_to_texture_attachment self.goc_output_texture(self.locked_render_to_texture_array)
def load_collada(filename, scale=1, matrix=np.eye(4, dtype='f4'), name="collada", bake_matrix=True, merge_actors=True, ignore_non_textured=False, invert_normals=False, type_id=-1, instance_id=-1): actors = Actors.Actors(shared_transform=ensure_Transform( np.eye(4, dtype='f4')) if bake_matrix else ensure_Transform(matrix), name=name, type_id=type_id, instance_id=instance_id) mesh = collada.Collada(filename) np_matrix = utils.to_numpy(matrix) textures_cache = {} actors_cache = {} bbox = np.full((2, 3), np.finfo('f4').max) bbox[1, :] = np.finfo('f4').min actors.all_vertices = [] actors.scale = scale for coll_geom in tqdm.tqdm(mesh.scene.objects('geometry')): for coll_prim in coll_geom.primitives(): #FIXME: stop ignoring colladas transforms if isinstance(coll_prim, collada.triangleset.BoundTriangleSet): triangles = coll_prim elif isinstance(coll_prim, collada.polylist.BoundPolylist): triangles = coll_prim.triangleset() else: LoggingManager.instance().warning( f"{type(coll_prim)} not implementend") continue textures = {} effect_signature = [] #for merging actors uniforms = {} for effect_name in triangles.material.effect.supported: value = getattr(triangles.material.effect, effect_name) if isinstance(value, collada.material.Map): texture_image = value.sampler.surface.image effect_signature.append((effect_name, texture_image.id)) if texture_image.id in textures_cache: textures[effect_name] = textures_cache[ texture_image.id] else: array = textures[effect_name] = textures_cache[ texture_image.id] = Array.Array( ndarray=utils.load_texture( texture_image.pilimage)) elif isinstance(value, tuple): uniforms[effect_name] = QColor.fromRgbF(*value) effect_signature.append((effect_name, value)) elif isinstance(value, float): uniforms[effect_name] = value effect_signature.append((effect_name, value)) elif value is not None: LoggingManager.instance().warning( f"Unsupported type {effect_name}: {type(value)}") if not textures and ignore_non_textured: continue effect_signature = frozenset(effect_signature) triangles.generateNormals() vertices = triangles.vertex.astype('f4') * scale normals = triangles.normal.astype('f4') if invert_normals: normals = normals * -1 if bake_matrix: vertices = linalg.map_points(np_matrix, vertices) normals = linalg.map_vectors(np_matrix, normals) indices = triangles.vertex_index.flatten().astype('u4') attributes_ndarrays = {"vertices": vertices, "normals": normals} indexed_vertices = vertices[triangles.vertex_index.flatten()] for i in range(3): bbox[0, i] = min(bbox[0, i], indexed_vertices[:, i].min()) bbox[1, i] = max(bbox[1, i], indexed_vertices[:, i].max()) if textures: if len(triangles.texcoordset) > 1: LoggingManager.instance().warning( f"warning, {type(coll_prim)} not implementend") orig_tc0 = triangles.texcoordset[0].astype('f4') tc0_idx = triangles.texcoord_indexset[0].flatten() if not np.all(tc0_idx == indices): assert tc0_idx.shape == indices.shape, "texcoord indices must be the same shape as vertex indices" #this will duplicate shared vertices so that we can have a separate texcoords for each triangle sharing vertices attributes_ndarrays['vertices'] = indexed_vertices attributes_ndarrays['normals'] = normals[ triangles.normal_index.flatten()] indices = np.arange(indices.shape[0], dtype=indices.dtype) uv = orig_tc0[tc0_idx] else: uv = np.empty((vertices.shape[0], 2), 'f4') uv[indices] = orig_tc0[tc0_idx] attributes_ndarrays['texcoords0'] = uv attribs = CustomAttribs.TexcoordsAttribs( vertices=Array.Array( ndarray=attributes_ndarrays['vertices']), normals=Array.Array( ndarray=attributes_ndarrays['normals']), texcoords0=Array.Array( ndarray=attributes_ndarrays['texcoords0'])) #FIXME: bind collada uniforms if present effect = CustomEffects.textured_material(textures) else: attribs = Geometry.Attribs( vertices=Array.Array( ndarray=attributes_ndarrays['vertices']), normals=Array.Array( ndarray=attributes_ndarrays['normals'])) #FIXME: bind other uniforms if present effect = CustomEffects.material(color=uniforms['diffuse'], back_color=uniforms['diffuse']) if invert_normals: indices = indices.reshape((indices.shape[0] // 3), 3)[:, [0, 2, 1]].flatten() if merge_actors and effect_signature in actors_cache: actor = actors_cache[effect_signature] actor_attributes = actor.geometry.attribs.get_attributes() n_vertices_before = actor_attributes['vertices'].shape[0] for attr_name, value in actor_attributes.items(): value.set_ndarray( np.vstack( (value.ndarray, attributes_ndarrays[attr_name]))) actor.geometry.indices.set_ndarray( np.hstack((actor.geometry.indices.ndarray, indices + n_vertices_before))) else: geometry = Geometry.Geometry( indices=Array.Array(ndarray=indices), attribs=attribs) actor = actors.addActor( Actors.Actor(geometry=geometry, effect=effect, transform=actors.shared_transform, name=f"{name}_{coll_geom.original.id}", type_id=type_id, instance_id=instance_id)) actors_cache[effect_signature] = actor actors.all_vertices.append( actor.geometry.attribs.vertices ) #if in merge actor mode, vertices are already there actors.bbox = bbox return actors