def __init__(self, fanout, depth, spread=default_spread, rootColor=default_rootColor, edgeColor=default_edgeColor, scale=default_scale, actor=None): Component.__init__(self, actor) self.fanout = fanout self.depth = depth self.spread = spread self.rootColor = rootColor self.edgeColor = edgeColor self.scale = scale self.rootScale = self.scale # NOTE this will also apply to children #self.childScale = np.float32([1.0, 1.0, 1.0]) # NOTE this will get compounded if the radial tree is a true hierarchy, better to use scale = 1 (default) # Recursively generate radial tree treeRoot = self.createRadialTree( self.fanout, self.depth, self.spread, isRoot=True) # creates full hierarchy and returns root actor treeRoot.components['Transform'] = Transform( rotation=np.random.uniform(-pi / 2, pi / 2, size=3), scale=self.rootScale, actor=treeRoot ) # NOTE random rotation ensures child vectors are not always generated close to the same canonical vectors treeRoot.components['Material'] = Material(color=self.rootColor, actor=treeRoot) treeRoot.components['Mesh'] = Mesh.getMesh(src=self.treeRootModelFile, actor=treeRoot) # Attach this hierarchy to current actor self.actor.children.append(treeRoot)
def __init__(self, scale=cube_scale, actor=None): Component.__init__(self, actor) Trackable.__init__(self) self.scale = scale # Scale vertices of base cube, specify edges, and initialize list of markers self.vertices = cube_vertices * self.scale self.vertex_colors = cube_vertex_colors self.vertex_scale = 0.3 * self.scale # NOTE for rendering only, depends on 3D model self.edges = cube_edges self.edge_scale = 0.1 * self.scale # NOTE for rendering only, depends on 3D model self.edge_color = np.float32([0.8, 0.7, 0.5]) # NOTE for rendering only # TODO make some of these parameters come from XML # NOTE Mark generated child actors (corners and edges) as transient, to prevent them from being exported in XML # Add spheres at cube corners (vertices) with appropriate color; also add color markers for vertex, colorName in zip(self.vertices, self.vertex_colors): vertexActor = Actor(self.actor.renderer, isTransient=True) vertexActor.components['Transform'] = Transform(translation=vertex, scale=self.vertex_scale, actor=vertexActor) vertexActor.components['Material'] = Material(color=colors_by_name[colorName], actor=vertexActor) vertexActor.components['Mesh'] = Mesh.getMesh(src="SmallSphere.obj", actor=vertexActor) self.actor.children.append(vertexActor) marker = ColorMarker(self, colorName) marker.worldPos = vertex self.markers.append(marker) # Add edges for u, v in self.edges: if u < len(self.vertices) and v < len(self.vertices) and self.vertices[u] is not None and self.vertices[v] is not None: # sanity check midPoint = (self.vertices[u] + self.vertices[v]) / 2.0 diff = self.vertices[v] - self.vertices[u] mag = np.linalg.norm(diff, ord=2) xy_mag = hypot(diff[0], diff[1]) #zx_mag = hypot(diff[2], diff[0]) rotation = np.degrees(np.float32([atan2(diff[1], diff[0]), acos(diff[1] / mag), 0])) if (mag != 0 and xy_mag != 0) else np.float32([0.0, 0.0, 0.0]) #print "u: ", self.vertices[u], ", v: ", self.vertices[v], ", v-u: ", diff, ", mag: ", mag, ", rot:", rotation edgeActor = Actor(self.actor.renderer, isTransient=True) edgeActor.components['Transform'] = Transform(translation=midPoint, rotation=rotation, scale=self.edge_scale, actor=edgeActor) edgeActor.components['Material'] = Material(color=self.edge_color, actor=edgeActor) edgeActor.components['Mesh'] = Mesh.getMesh(src="CubeEdge.obj", actor=edgeActor) # TODO fix Z-fighting issue and use CubeEdge_cylinder.obj self.actor.children.append(edgeActor)
def __init__(self, fanout, depth, spread=default_spread, rootColor=default_rootColor, edgeColor=default_edgeColor, scale=default_scale, actor=None): Component.__init__(self, actor) self.fanout = fanout self.depth = depth self.spread = spread self.rootColor = rootColor self.edgeColor = edgeColor self.scale = scale self.rootScale = self.scale # NOTE this will also apply to children #self.childScale = np.float32([1.0, 1.0, 1.0]) # NOTE this will get compounded if the radial tree is a true hierarchy, better to use scale = 1 (default) # Recursively generate radial tree treeRoot = self.createRadialTree(self.fanout, self.depth, self.spread, isRoot=True) # creates full hierarchy and returns root actor treeRoot.components['Transform'] = Transform(rotation=np.random.uniform(-pi/2, pi/2, size=3), scale=self.rootScale, actor=treeRoot) # NOTE random rotation ensures child vectors are not always generated close to the same canonical vectors treeRoot.components['Material'] = Material(color=self.rootColor, actor=treeRoot) treeRoot.components['Mesh'] = Mesh.getMesh(src=self.treeRootModelFile, actor=treeRoot) # Attach this hierarchy to current actor self.actor.children.append(treeRoot)
def createRadialTree(self, fanout, depth, spread, isRoot=False): if depth <= 0: return None # * Create this node (an actor) treeNode = Actor(self.actor.renderer, isTransient=True) # * Attach children if depth > 1 if depth > 1: if isRoot: # ** Pick all random directions first, to ensure a good spread, and then generate children childVectors = np.float32( [[ -1, -1, -1 ], [ 1, -1, -1 ], [ 1, 1, -1 ], [ -1, 1, -1 ], [ -1, -1, 1 ], [ 1, -1, 1 ], [ 1, 1, 1 ], [ -1, 1, 1 ]]) # NOTE these canonical directions are same as cube vertices! # ** Perturb child vectors, and compute unit direction vectors perturbation = np.random.normal(scale=1.0, size=childVectors.shape) #print "RadialTree.__init__(): Child:-\norig. vectors:\n", childVectors, "\nperturbation :\n", perturbation childVectors += perturbation #print "pert. vectors:\n", childVectors childNorms = np.apply_along_axis(lambda vec:np.linalg.norm(vec, ord=2), 1, childVectors) #print "child norms:\n", childNorms childUnits = childVectors / childNorms[:, np.newaxis] # ** Use child unit vectors one by one to create fanout first-level children numChildren = fanout if fanout <= childUnits.shape[0] else childUnits.shape[0] # NOTE assert/enforce: actual fanout <= childUnits.shape[0] # TODO randomly pick from child unit vectors without replacement? for unit in childUnits[0:numChildren]: translation = self.treeEdgeLength * unit phi = np.arctan2(-unit[2], unit[0]) theta = np.arcsin(unit[1]) rotation = np.degrees(np.float32([ 0, phi, theta ])) # NOTE random X-axis rotation can be added (but won't make any difference): np.random.uniform(-pi, pi) #print "RadialTree.__init__(): Child:-\nunit:", unit, "[ norm = ", np.linalg.norm(unit, ord=2), "]\ntranslation:", translation, "\nrotation:", rotation childNode = self.createRadialTree(np.random.random_integers(3, 4), depth - 1, spread) # recurse down, decreasing depth childNode.components['Transform'] = Transform(translation=translation, rotation=rotation, actor=childNode) # NOTE scaling will accumulate, so use scale = 1 (default) childNode.components['Material'] = Material(color=self.edgeColor, actor=childNode) childNode.components['Mesh'] = Mesh.getMesh(src=self.treeEdgeModelFile, actor=childNode) treeNode.children.append(childNode) else: while len(treeNode.children) < fanout: # ** Pick a random direction for creating a new child spread_rad = np.radians(spread) phi = np.random.uniform(-spread_rad, spread_rad) # rotation around Y axis theta = np.random.uniform(-spread_rad, spread_rad) # rotation around Z axis rotation = np.degrees(np.float32([ 0.0, phi, theta ])) # this will serve as orientation for the tree edge # TODO pick a random length; scale X axis accordingly (how? flatten tree hierarchy? pick from discrete lengths and use different models accordingly?) # ** Compute relative position of new child (in cartesian coordinates) and normalized unit vector translation = np.float32([ self.treeEdgeLength * cos(theta) * cos(phi), self.treeEdgeLength * sin(theta), -self.treeEdgeLength * cos(theta) * sin(phi) ]) norm = np.linalg.norm(translation, ord=2) unit = translation / norm # TODO check closeness condition (too close to existing nodes? parent? - need absolute coordinates for that!) # ** Generate and add child (with nested tree) childNode = self.createRadialTree(np.random.random_integers(3, 4), depth - 1, spread) # recurse down, decreasing depth childNode.components['Transform'] = Transform(translation=translation, rotation=rotation, actor=childNode) # NOTE scaling will accumulate, so use scale = 1 (default) childNode.components['Material'] = Material(color=self.edgeColor, actor=childNode) childNode.components['Mesh'] = Mesh.getMesh(src=self.treeEdgeModelFile, actor=childNode) treeNode.children.append(childNode) return treeNode
def __init__(self, scale=cube_scale, actor=None): Component.__init__(self, actor) Trackable.__init__(self) self.scale = scale # Scale vertices of base cube, specify edges, and initialize list of markers self.vertices = cube_vertices * self.scale self.vertex_colors = cube_vertex_colors self.vertex_scale = 0.3 * self.scale # NOTE for rendering only, depends on 3D model self.edges = cube_edges self.edge_scale = 0.1 * self.scale # NOTE for rendering only, depends on 3D model self.edge_color = np.float32([0.8, 0.7, 0.5]) # NOTE for rendering only # TODO make some of these parameters come from XML # NOTE Mark generated child actors (corners and edges) as transient, to prevent them from being exported in XML # Add spheres at cube corners (vertices) with appropriate color; also add color markers for vertex, colorName in zip(self.vertices, self.vertex_colors): vertexActor = Actor(self.actor.renderer, isTransient=True) vertexActor.components['Transform'] = Transform( translation=vertex, scale=self.vertex_scale, actor=vertexActor) vertexActor.components['Material'] = Material( color=colors_by_name[colorName], actor=vertexActor) vertexActor.components['Mesh'] = Mesh.getMesh( src="SmallSphere.obj", actor=vertexActor) self.actor.children.append(vertexActor) marker = ColorMarker(self, colorName) marker.worldPos = vertex self.markers.append(marker) # Add edges for u, v in self.edges: if u < len(self.vertices) and v < len( self.vertices ) and self.vertices[u] is not None and self.vertices[ v] is not None: # sanity check midPoint = (self.vertices[u] + self.vertices[v]) / 2.0 diff = self.vertices[v] - self.vertices[u] mag = np.linalg.norm(diff, ord=2) xy_mag = hypot(diff[0], diff[1]) #zx_mag = hypot(diff[2], diff[0]) rotation = np.degrees( np.float32([ atan2(diff[1], diff[0]), acos(diff[1] / mag), 0 ])) if (mag != 0 and xy_mag != 0) else np.float32( [0.0, 0.0, 0.0]) #print "u: ", self.vertices[u], ", v: ", self.vertices[v], ", v-u: ", diff, ", mag: ", mag, ", rot:", rotation edgeActor = Actor(self.actor.renderer, isTransient=True) edgeActor.components['Transform'] = Transform( translation=midPoint, rotation=rotation, scale=self.edge_scale, actor=edgeActor) edgeActor.components['Material'] = Material( color=self.edge_color, actor=edgeActor) edgeActor.components['Mesh'] = Mesh.getMesh( src="CubeEdge.obj", actor=edgeActor ) # TODO fix Z-fighting issue and use CubeEdge_cylinder.obj self.actor.children.append(edgeActor)
def createRadialTree(self, fanout, depth, spread, isRoot=False): if depth <= 0: return None # * Create this node (an actor) treeNode = Actor(self.actor.renderer, isTransient=True) # * Attach children if depth > 1 if depth > 1: if isRoot: # ** Pick all random directions first, to ensure a good spread, and then generate children childVectors = np.float32( [[-1, -1, -1], [1, -1, -1], [1, 1, -1], [-1, 1, -1], [-1, -1, 1], [1, -1, 1], [1, 1, 1], [-1, 1, 1]] ) # NOTE these canonical directions are same as cube vertices! # ** Perturb child vectors, and compute unit direction vectors perturbation = np.random.normal(scale=1.0, size=childVectors.shape) #print "RadialTree.__init__(): Child:-\norig. vectors:\n", childVectors, "\nperturbation :\n", perturbation childVectors += perturbation #print "pert. vectors:\n", childVectors childNorms = np.apply_along_axis( lambda vec: np.linalg.norm(vec, ord=2), 1, childVectors) #print "child norms:\n", childNorms childUnits = childVectors / childNorms[:, np.newaxis] # ** Use child unit vectors one by one to create fanout first-level children numChildren = fanout if fanout <= childUnits.shape[ 0] else childUnits.shape[ 0] # NOTE assert/enforce: actual fanout <= childUnits.shape[0] # TODO randomly pick from child unit vectors without replacement? for unit in childUnits[0:numChildren]: translation = self.treeEdgeLength * unit phi = np.arctan2(-unit[2], unit[0]) theta = np.arcsin(unit[1]) rotation = np.degrees( np.float32([0, phi, theta]) ) # NOTE random X-axis rotation can be added (but won't make any difference): np.random.uniform(-pi, pi) #print "RadialTree.__init__(): Child:-\nunit:", unit, "[ norm = ", np.linalg.norm(unit, ord=2), "]\ntranslation:", translation, "\nrotation:", rotation childNode = self.createRadialTree( np.random.random_integers(3, 4), depth - 1, spread) # recurse down, decreasing depth childNode.components['Transform'] = Transform( translation=translation, rotation=rotation, actor=childNode ) # NOTE scaling will accumulate, so use scale = 1 (default) childNode.components['Material'] = Material( color=self.edgeColor, actor=childNode) childNode.components['Mesh'] = Mesh.getMesh( src=self.treeEdgeModelFile, actor=childNode) treeNode.children.append(childNode) else: while len(treeNode.children) < fanout: # ** Pick a random direction for creating a new child spread_rad = np.radians(spread) phi = np.random.uniform( -spread_rad, spread_rad) # rotation around Y axis theta = np.random.uniform( -spread_rad, spread_rad) # rotation around Z axis rotation = np.degrees(np.float32([ 0.0, phi, theta ])) # this will serve as orientation for the tree edge # TODO pick a random length; scale X axis accordingly (how? flatten tree hierarchy? pick from discrete lengths and use different models accordingly?) # ** Compute relative position of new child (in cartesian coordinates) and normalized unit vector translation = np.float32([ self.treeEdgeLength * cos(theta) * cos(phi), self.treeEdgeLength * sin(theta), -self.treeEdgeLength * cos(theta) * sin(phi) ]) norm = np.linalg.norm(translation, ord=2) unit = translation / norm # TODO check closeness condition (too close to existing nodes? parent? - need absolute coordinates for that!) # ** Generate and add child (with nested tree) childNode = self.createRadialTree( np.random.random_integers(3, 4), depth - 1, spread) # recurse down, decreasing depth childNode.components['Transform'] = Transform( translation=translation, rotation=rotation, actor=childNode ) # NOTE scaling will accumulate, so use scale = 1 (default) childNode.components['Material'] = Material( color=self.edgeColor, actor=childNode) childNode.components['Mesh'] = Mesh.getMesh( src=self.treeEdgeModelFile, actor=childNode) treeNode.children.append(childNode) return treeNode