def notify_in_use(self, user, portal_instance, portal_object): if self.supports_landing_shoo: routing_surface = None exit_location = portal_instance.there_exit if exit_location.routing_surface.type == SurfaceType.SURFACETYPE_OBJECT: exit_height = terrain.get_terrain_height( exit_location.position.x, exit_location.position.z, routing_surface=exit_location.routing_surface) routing_surface = exit_location.routing_surface landing_points = [] for (there_start, there_end, back_start, back_end, _) in self.get_portal_locations(portal_object): for portal_location in (there_start, there_end, back_start, back_end): if portal_location.routing_surface.type == SurfaceType.SURFACETYPE_OBJECT: portal_height = terrain.get_terrain_height( portal_location.position.x, portal_location.position.z, routing_surface=portal_location.routing_surface ) if math.isclose(portal_height, exit_height): landing_points.append(portal_location.position) polygon = Polygon(landing_points) polygon = polygon.get_convex_hull() polygon = inflate_polygon( polygon, _PortalTypeDataStairs.STAIR_SHOO_POLYGON_PADDING) UserFootprintHelper.force_move_sims_in_polygon( polygon, routing_surface, exclude=(user, ))
def _generate_clusters(self): with self._caching(): del self._clusters[:] objects = [set(self._get_objects_gen())] all_rejects = set() while objects: clusters = self._get_clusters(objects.pop()) for cluster in clusters: polygon = Polygon([obj.position for obj in cluster]) centroid = polygon.centroid() facing_rejects = [] for obj in list(cluster): if self.facing_angle is not None: interval = interval_from_facing_angle(vector3_angle(centroid - obj.position), self.facing_angle + self.FACING_EPSILON) facing = vector3_angle(obj.forward) is_facing = facing in interval else: is_facing = True if not is_facing: if not vector3_almost_equal_2d(centroid, obj.position, epsilon=0.01): cluster.remove(obj) facing_rejects.append(obj) if len(cluster) >= self.minimum_size: rejected_sets = self._generate_cluster(centroid, cluster) for rejected_set in itertools.chain((facing_rejects,), rejected_sets): unused_rejects = set(obj for obj in rejected_set if obj not in all_rejects) all_rejects.update(unused_rejects) if len(unused_rejects) >= self.minimum_size: objects.append(unused_rejects) self._rejects = [reject for reject in all_rejects if not any(reject in cluster for cluster in self._clusters)]
def _get_cluster_polygon(self, position, objects): hull_points = [position] for obj in objects: if obj.parts: for part in obj.parts: hull_points.append(part.position) else: hull_points.append(obj.position) else: hull_points.append(obj.position) polygon = Polygon(hull_points) polygon = polygon.get_convex_hull() if len(polygon) == 2 or polygon.too_thin or polygon.too_small: sorted_x = sorted(hull_points, key=lambda p: p.x) sorted_z = sorted(hull_points, key=lambda p: p.z) delta_x = sorted_x[-1].x - sorted_x[0].x delta_z = sorted_z[-1].z - sorted_z[0].z extents = sorted_x if delta_x > delta_z else sorted_z a = extents[0] b = extents[-1] polygon = build_rectangle_from_two_points_and_radius(a, b, self.radius_buffer) else: polygon = sims4.geometry.inflate_polygon(polygon, self.radius_buffer) compound_polygon = sims4.geometry.CompoundPolygon([polygon]) return compound_polygon
def get_waypoint_constraints_gen(self, routing_agent, waypoint_count): zone_id = services.current_zone_id() object_constraints = defaultdict(list) if self.object_tag_generator is not None: object_tag_generator = self.object_tag_generator(WaypointContext(self._sim), None) for constraint in itertools.chain((object_tag_generator.get_start_constraint(),), object_tag_generator.get_waypoint_constraints_gen(routing_agent, MAX_INT32)): level = constraint.routing_surface.secondary_id block_id = get_block_id(zone_id, constraint.average_position, level) object_constraints[block_id].append(constraint) plex_id = services.get_plex_service().get_active_zone_plex_id() or plex_enums.INVALID_PLEX_ID block_data = get_all_block_polygons(plex_id) polygons = defaultdict(list) if self._routing_surface.secondary_id == 0: polygons[0] = self._get_polygons_for_lot() for (block_id, (polys, level)) in block_data.items(): if level != self._routing_surface.secondary_id: continue polygon = CompoundPolygon([Polygon(list(reversed(p))) for p in polys]) if not polygon.area(): continue polygons[block_id].append((polygon, self._routing_surface)) if not polygons: return False yield final_constraints = self._get_waypoint_constraints_from_polygons(polygons, object_constraints, waypoint_count) final_constraints = self.apply_water_constraint(final_constraints) yield from final_constraints
def get_plex_polygons(self, level): zone_id = services.current_zone_id() if zone_id not in self._zone_to_master_map: logger.error("Can't get polygons for a non-plex: {}", zone_id) return [] (_, plex_id) = self._zone_to_master_map[zone_id] blocks = build_buy.get_plex_outline(plex_id, level) polygons = [] for block in blocks: logger.assert_log( len(block) == 1, 'Plex has cutouts. get_plex_polygons needs to be updated. Zone: {}, Level: {}', zone_id, level) vertices = list(reversed(block[0])) polygon = Polygon(vertices) polygons.append(polygon) return polygons
def _get_polygons_for_lot(self): lot = services.active_lot() return [(CompoundPolygon(Polygon(list(reversed(lot.corners)))), self._routing_surface)]
def __new__(cls, corners: Tuple[CommonVector3]) -> 'CommonPolygon': return Polygon(corners)