def _check_collision(width, height, mechs, mech): tree = aabb.AABBTree() # Add edge bounding boxes for backboard. gripper_gap = 0.035 # so gripper doesn't collide with busybox base tree.add( aabb.AABB([(-width / 2.0, width / 2.0), (height / 2.0, height / 2.0 + 1)])) # top tree.add( aabb.AABB([(-width / 2.0, width / 2.0), (-height / 2.0 - 1, -height / 2.0 + gripper_gap) ])) # bottom tree.add( aabb.AABB([(-width / 2.0 - 1, -width / 2.0), (-height / 2.0, height / 2.0)])) # left tree.add( aabb.AABB([(width / 2.0, width / 2.0 + 1), (-height / 2.0, height / 2.0)])) # right # Get the bounding box for each existing mechanism. for ix, m in enumerate(mechs): if not m == mech: tree.add(m.get_bounding_box(), str(ix)) # Get the bounding box of the current mechanism and check overlap. if tree.does_overlap(mech.get_bounding_box()): return True else: return False
def removeSensor(self, index): #We remove the sensor from the list self.sensorList.pop(index) self.sensorNumber -= 1 #Now, we need to recreate the tree self.tree = aabbtree.AABBTree() for sensor in self.sensorList: self.tree.add(sensor["bbox"])
def main(): # Cross shapes cross_horiz_left = aabbtree.AABB([(-6, 1), (-1, 2)]) cross_vert_left = aabbtree.AABB([(-1, 1), (-15, 5)]) cross_horiz_right = aabbtree.AABB([(3, 10), (-2, 1)]) cross_vert_right = aabbtree.AABB([(3, 5), (-15, 5)]) # Box sets box_1 = aabbtree.AABB([(-21, -18), (-21, -18)]) box_2 = aabbtree.AABB([(-17, -14), (-21, -18)]) box_3 = aabbtree.AABB([(-16, -13), (-16, -13)]) box_4 = aabbtree.AABB([(-12, -9), (-16, -13)]) # Random boxes rand_1 = aabbtree.AABB([(-15, -13), (-2, 2)]) # Build tree tree = aabbtree.AABBTree() aabbs = [ box_3, cross_vert_right, box_1, cross_horiz_left, box_4, rand_1, cross_vert_left, box_2, cross_horiz_right ] for i, aabb in enumerate(aabbs): tree.add(aabb, i + 1) # Set up figure plt.clf() plt.close('all') fig = plt.figure() ax = plt.axes() ax.set_axis_off() ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) fig.add_axes(ax) # Plot tree contents plot_contents(tree) # Plot tree plot_tree(tree) # Format axes plt.axis('square') plt.xlim([-85, 11]) plt.ylim([-22, 7]) # Save figure docs_path = os.path.join(os.path.dirname(__file__), 'docs') fig_filename = os.path.join(docs_path, 'source', '_static', 'diagram.png') plt.savefig(fig_filename, dpi=300, bbox_inches='tight', pad_inches=0, transparent=True)
def __init__(self) -> None: #Structure self.sensor = [("groupIndex", np.int32), ("WtOMatrix", np.float32, 12), ("twoSided", np.bool8), ("color", np.float32, 3), ("exponent", np.float32)] #Attributes self.tree = aabbtree.AABBTree() self.sensorList = [] self.builder = bvhBuilder.BVHBuilder() self.sensorNumber = 0
def _leaf_cloud_positions_cuboid_avoid_overlap( n_leaves, l_horizontal, l_vertical, leaf_radius, n_attempts, rng ): """ Compute leaf positions for a cuboid-shaped leaf cloud (square footprint). This function also performs conservative collision checks to avoid leaf overlapping. This process might take a very long time, if the parameters specify a very dense leaf cloud. Consider using :func:`_leaf_cloud_positions_cuboid`. """ n_attempts = int(n_attempts) # For safety, ensure conversion to int # try placing the leaves such that they do not overlap by creating # axis-aligned bounding boxes and checking them for intersection positions = np.empty((n_leaves, 3)) tree = aabbtree.AABBTree() for i in range(n_leaves): for j in range(n_attempts): rand = rng.random(3) pos_candidate = [ rand[0] * l_horizontal - 0.5 * l_horizontal, rand[1] * l_horizontal - 0.5 * l_horizontal, rand[2] * l_vertical, ] aabb = aabbtree.AABB( [ (pos_candidate[0] - leaf_radius, pos_candidate[0] + leaf_radius), (pos_candidate[1] - leaf_radius, pos_candidate[1] + leaf_radius), (pos_candidate[2] - leaf_radius, pos_candidate[2] + leaf_radius), ] ) if i == 0: positions[i, :] = pos_candidate tree.add(aabb) break else: if not tree.does_overlap(aabb): positions[i, :] = pos_candidate tree.add(aabb) break else: raise RuntimeError( "unable to place all leaves: the specified canopy might be too dense" ) return positions
def __init__(self, sce=Scene()): # Type check assert type( sce ) == openalea.plantgl.scenegraph._pglsg.Scene, "Tree must be constructed with a PlantGL scene." # Structures # left BBox XY min and Max, both BBOx Z min and max, and right BBox XY min and Max self.firstInfos = [("n0xy", np.float32, 4), ("nz", np.float32, 4), ("n1xy", np.float32, 4)] # left child and right child index self.branch = self.firstInfos + [("c0idx", np.int32), ("c1idx", np.int32)] # primitive index, and primitive count self.leaf = self.firstInfos + [("idx", np.int32), ("pcount", np.int32)] # Attributes self.tree = aabbtree.AABBTree() self.scene = sce self.serializedNodes = 0
def position(self, domain, pos_dists={}, rng_seed=0, hold=[], max_attempts=10000, rtol='fit', verbose=False): """Position seeds in a domain This method positions the seeds within a domain. The "domain" should be a geometry instance from the :mod:`microstructpy.geometry` module. The "pos_dist" input is for phases with custom position distributions, the default being a uniform random distribution. For example: .. code-block:: python import scipy.stats mu = [0.5, -0.2] sigma = [[2.0, 0.3], [0.3, 0.5]] pos_dists = {2: scipy.stats.multivariate_normal(mu, sigma), 3: ['random', scipy.stats.norm(0, 1)] } Here, phases 0 and 1 have the default distribution, phase 2 has a bivariate normal position distribution, and phase 3 is uniform in the x and normally distributed in the y. Multivariate distributions are described in the multivariate section of the :mod:`scipy.stats` documentation. The position of certain seeds can be held fixed during the positioning process using the "hold" input. This should be a list of booleans, where False indicates a seed should not be held fixed and True indicates that it should be held fixed. The default behavior is to not hold any seeds fixed. The "rtol" parameter governs the relative overlap tolerable between seeds. Setting rtol to 0 means that there is no overlap, while a value of 1 means that one seed's center is on the edge of another seed. The default value is 'fit', which determines a tolerance between 0 and 1 based on the ratio of standard deviation to mean in grain volumes. Args: domain (from :mod:`microstructpy.geometry`): The domain of the microstructure. pos_dists (dict): *(optional)* Position distributions for each phase, formatted like the example above. Defaults to uniform random throughout the domain. rng_seed (int): *(optional)* Random number generator (RNG) seed for positioning the seeds. Should be a non-negative integer. hold (list or numpy.ndarray): *(optional)* List of booleans for holding the positions of seeds. Defaults to False for all seeds. max_attempts (int): *(optional)* Number of random trials before removing a seed from the list. Defaults to 10,000. rtol (str or float): *(optional)* The relative overlap tolerance between seeds. This parameter should be between 0 and 1. Using the 'fit' option, a function will determine the value for rtol based on the mean and standard deviation in seed volumes. verbose (bool): *(optional)* This option will print a running counter of how many seeds have been positioned. Defaults to False. """ # NOQA: E501 if len(hold) == 0: hold = [False for seed in self] # set the spatial distributions u_dist = [ scipy.stats.uniform(lb, ub - lb) for lb, ub in domain.sample_limits ] distribs = [] n_phases = max([s.phase for s in self]) + 1 for i in range(n_phases): distribs.append(pos_dists.get(i, u_dist)) # Add hold seeds n_seeds = len(self) tree = aabbtree.AABBTree() for i in range(n_seeds): if hold[i]: # add to tree aabb = aabbtree.AABB(self[i].geometry.limits) tree.add(aabb, i) positioned = np.array(hold) vols = np.array([s.volume for s in self]) i_sort = np.flip(np.argsort(vols)) posd_sort = positioned[i_sort] i_position = i_sort[~posd_sort] # allowable overlap, relative to radius cv = scipy.stats.variation(vols) if domain.n_dim == 2 and rtol == 'fit': numer = 0.362954 * cv * cv - 0.419069 * cv + .184959 denom = cv * cv - 1.05989 * cv + 0.365096 rtol = numer / denom elif rtol == 'fit': numer = 0.471115 * cv * cv - 0.602324 * cv + 0.297562 denom = cv * cv - 1.08469 * cv + 0.428216 rtol = numer / denom # position the remaining seeds i_reject = [] np.random.seed(rng_seed) n_samples = 100 for k, i in enumerate(i_position): if verbose: print(k + 1, 'of', len(i_position)) seed = self[i] pos_dist = distribs[seed.phase] searching = True n_attempts = 0 i_sample = 0 pts = sample_pos_within(pos_dist, n_samples, domain) while searching and n_attempts < max_attempts: pt = pts[i_sample] seed.position = pt n_attempts += 1 i_sample += 1 if i_sample == n_samples: pts = sample_pos_within(pos_dist, n_samples, domain) i_sample = 0 bkdwn = np.array(seed.breakdown) cens = bkdwn[:, :-1] rads = bkdwn[:, -1].reshape(-1, 1) aabb = aabbtree.AABB(seed.geometry.limits) olap_inds = tree.overlap_values(aabb, method='BFS') olap_seeds = self[olap_inds] clears = True for olap_seed in olap_seeds: o_bkdwn = np.array(olap_seed.breakdown) o_cens = o_bkdwn[:, :-1] o_rads = o_bkdwn[:, -1].reshape(1, -1) if len(rads) > 1: dists = distance.cdist(cens, o_cens) else: rel_pos = o_cens - cens rp2 = rel_pos * rel_pos dists = np.sqrt(np.sum(rp2, axis=1)) tol = rtol * np.minimum(rads, o_rads) total_dists = dists + tol - rads - o_rads if np.any(total_dists < 0): clears = False break searching = not clears if searching: i_reject.append(i) else: positioned[i] = True self[i] = seed # add to tree aabb = aabbtree.AABB(seed.geometry.limits) tree.add(aabb, i) keep_mask = np.array(n_seeds * [True]) keep_mask[i_reject] = False if ~np.all(keep_mask): reject_seeds = self[~keep_mask] f = 'seed_position_reject.log' reject_seeds.write(f) w_str = 'Seeds were removed from the seed list during positioning.' w_str += ' Their data has beeen written to ' + f + ' and their' w_str += ' indices were ' + str(i_reject) + '.' warnings.warn(w_str, RuntimeWarning) self.seeds = self[keep_mask].seeds
def find_overlaps_in_sources_sinks_agents( collected_sources_sinks_agent_states_geometries): # create aabbtree for fast distance lookup between agents tree = aabbtree.AABBTree() for source_sink_idx, states_geometries in enumerate( collected_sources_sinks_agent_states_geometries): agent_states = states_geometries[0] agent_geometries = states_geometries[1] for agent_idx, agent_state in enumerate(agent_states): agent_translated_polygon = agent_geometries[agent_idx].Translate( Point2d(agent_state[1], agent_state[2])) tmp = agent_translated_polygon.bounding_box bb = aabbtree.AABB([(tmp[0].x(), tmp[1].x()), (tmp[0].y(), tmp[1].y())]) tree.add(bb, (source_sink_idx, agent_idx)) # check for all agents in a source sink config collision with # agents in other sources sinks and track the collisions collisions = defaultdict(list) for source_sink_idx, states_geometries in enumerate( collected_sources_sinks_agent_states_geometries): agent_states = states_geometries[0] agent_geometries = states_geometries[1] for agent_idx, agent_state in enumerate(agent_states): agent_translated_polygon = agent_geometries[agent_idx].Translate( Point2d(agent_state[1], agent_state[2])) tmp = agent_translated_polygon.bounding_box bb = aabbtree.AABB([(tmp[0].x(), tmp[1].x()), ( tmp[0].y() , tmp[1].y())]) overlaps = tree.overlap_values(bb) for overlap in overlaps: if source_sink_idx == overlap[0]: if agent_idx == overlap[1]: continue else: raise ValueError("Something went wrong. \ We have colliding agent within one source sink configuration") key1 = "{}-{}".format(source_sink_idx, overlap[0]) key2 = "{}-{}".format(overlap[0], source_sink_idx, ) key = None if key1 in collisions: key = key1 elif key2 in collisions: key = key2 else: key = key1 pairwise_collisions = collisions[key] found = False for collision in pairwise_collisions: # exclude the case where this collision was already detected in a previous # run through the loop agent_desc1 = collision[0] if overlap[0] == agent_desc1[0] and overlap[1] == agent_desc1[1]: found = True if not found: agent_geometry_other = collected_sources_sinks_agent_states_geometries[overlap[0]][1][overlap[1]] agent_state_other = collected_sources_sinks_agent_states_geometries[overlap[0]][0][overlap[1]] agent_translated_polygon_other = agent_geometry_other.Translate( Point2d(agent_state_other[1], agent_state_other[2])) if Collide(agent_translated_polygon, agent_translated_polygon_other): pairwise_collisions.append(((source_sink_idx, agent_idx), overlap)) collisions[key] = pairwise_collisions return collisions