def from_dict(cls, data): """Create DetailedWindows from a dictionary. .. code-block:: python { "type": "DetailedWindows", "polygons": [((0.5, 0.5), (2, 0.5), (2, 2), (0.5, 2)), ((3, 1), (4, 1), (4, 2))] } """ assert data['type'] == 'DetailedWindows', \ 'Expected DetailedWindows dictionary. Got {}.'.format(data['type']) return cls( tuple( Polygon2D(tuple(Point2D.from_array(pt) for pt in poly)) for poly in data['polygons']))
def test_remove_vertices(): """Test the Mesh2D remove_vertices method.""" mesh = Mesh2D.from_grid(Point2D(1, 1), 8, 2, 0.25, 1) assert len(mesh.vertices) == 27 assert len(mesh.faces) == 16 assert mesh.area == 4 pattern_1 = [] for i in range(9): pattern_1.extend([True, True, False]) mesh_1, vert_pattern = mesh.remove_vertices(pattern_1) assert len(mesh_1.vertices) == 18 assert len(mesh_1.faces) == 8 assert mesh_1.area == 2 for face in mesh_1.faces: for i in face: mesh_1[i] # make sure all face indices reference current vertices
def test_linesegment2_init(): """Test the initalization of LineSegment2D objects and basic properties.""" pt = Point2D(2, 0) vec = Vector2D(0, 2) seg = LineSegment2D(pt, vec) str(seg) # test the string representation of the line segment assert seg.p == Point2D(2, 0) assert seg.v == Vector2D(0, 2) assert seg.p1 == Point2D(2, 0) assert seg.p2 == Point2D(2, 2) assert seg.midpoint == Point2D(2, 1) assert seg.point_at(0.25) == Point2D(2, 0.5) assert seg.point_at_length(1) == Point2D(2, 1) assert seg.length == 2 flip_seg = seg.flip() assert flip_seg.p == Point2D(2, 2) assert flip_seg.v == Vector2D(0, -2)
def test_scale(): """Test the Ray2D scale method.""" pt = Point2D(2, 2) vec = Vector2D(0, 2) ray = Ray2D(pt, vec) origin_1 = Point2D(0, 2) origin_2 = Point2D(1, 1) new_ray = ray.scale(2, origin_1) assert new_ray.p == Point2D(4, 2) assert new_ray.v == Point2D(0, 4) assert new_ray.v.magnitude == 4 new_ray = ray.scale(2, origin_2) assert new_ray.p == Point2D(3, 3) assert new_ray.v == Point2D(0, 4)
def test_scale(): """Test the LineSegment2D scale method.""" pt = Point2D(2, 2) vec = Vector2D(0, 2) seg = LineSegment2D(pt, vec) origin_1 = Point2D(0, 2) origin_2 = Point2D(1, 1) new_seg = seg.scale(2, origin_1) assert new_seg.p == Point2D(4, 2) assert new_seg.v == Point2D(0, 4) assert new_seg.length == 4 new_seg = seg.scale(2, origin_2) assert new_seg.p == Point2D(3, 3) assert new_seg.v == Point2D(0, 4)
def test_model_init(): """Test the initialization of Model objects and basic properties.""" pts_1 = (Point3D(0, 0, 3), Point3D(0, 10, 3), Point3D(10, 10, 3), Point3D(10, 0, 3)) pts_2 = (Point3D(10, 0, 3), Point3D(10, 10, 3), Point3D(20, 10, 3), Point3D(20, 0, 3)) pts_3 = (Point3D(0, 10, 3), Point3D(0, 20, 3), Point3D(10, 20, 3), Point3D(10, 10, 3)) pts_4 = (Point3D(10, 10, 3), Point3D(10, 20, 3), Point3D(20, 20, 3), Point3D(20, 10, 3)) room2d_1 = Room2D('Office1', Face3D(pts_1), 3) room2d_2 = Room2D('Office2', Face3D(pts_2), 3) room2d_3 = Room2D('Office3', Face3D(pts_3), 3) room2d_4 = Room2D('Office4', Face3D(pts_4), 3) story = Story('Office_Floor', [room2d_1, room2d_2, room2d_3, room2d_4]) story.solve_room_2d_adjacency(0.01) story.set_outdoor_window_parameters(SimpleWindowRatio(0.4)) story.multiplier = 4 building = Building('Office_Building', [story]) tree_canopy_geo1 = Face3D.from_regular_polygon(6, 6, Plane(o=Point3D(5, -10, 6))) tree_canopy_geo2 = Face3D.from_regular_polygon(6, 2, Plane(o=Point3D(-5, -10, 3))) tree_canopy = ContextShade('Tree_Canopy', [tree_canopy_geo1, tree_canopy_geo2]) model = Model('New_Development', [building], [tree_canopy]) str(model) # test the string representation of the object assert model.identifier == 'New_Development' assert model.display_name == 'New_Development' assert model.units == 'Meters' assert model.tolerance == 0.01 assert model.angle_tolerance == 1.0 assert len(model.buildings) == 1 assert isinstance(model.buildings[0], Building) assert len(model.context_shades) == 1 assert isinstance(model.context_shades[0], ContextShade) assert model.average_story_count == 4 assert model.average_story_count_above_ground == 4 assert model.average_height == 15 assert model.average_height_above_ground == 12 assert model.footprint_area == 100 * 4 assert model.floor_area == 100 * 4 * 4 assert model.exterior_wall_area == 60 * 4 * 4 assert model.exterior_aperture_area == 60 * 4 * 4 * 0.4 assert model.volume == 100 * 3 * 4 * 4 assert model.min.x == pytest.approx(-6.73, rel=1e-2) assert model.min.y == pytest.approx(-16, rel=1e-2) assert model.max == Point2D(20, 20)
def test_mesh2d_init_from_polygon_triangulated_concave(): """Test Mesh2D from_polygon_triangulated with a concave polygon.""" verts = (Point2D(0, 0), Point2D(2, 0), Point2D(2, 1), Point2D(1, 1), Point2D(1, 2), Point2D(0, 2)) polygon = Polygon2D(verts) mesh_1 = Mesh2D.from_polygon_triangulated(polygon) mesh_2 = Mesh2D.from_polygon_triangulated(polygon, False) assert len(mesh_1.vertices) == 6 assert len(mesh_2.vertices) == 12 assert len(mesh_1.faces) == len(mesh_2.faces) == 4 assert mesh_1.area == mesh_2.area == 3 assert mesh_1.min == mesh_2.min == Point2D(0, 0) assert mesh_1.max == mesh_2.max == Point2D(2, 2) assert mesh_1.center == mesh_2.center == Point2D(1, 1) assert mesh_1.centroid.x == mesh_2.centroid.x == pytest.approx(0.8333, rel=1e-2) assert mesh_1.centroid.y == mesh_2.centroid.y == pytest.approx(0.8333, rel=1e-2) assert len(mesh_1.face_areas) == len(mesh_2.face_areas) == 4 assert len(mesh_1.face_centroids) == len(mesh_2.face_centroids) == 4
def _compute_colored_mesh_array(hist_data, hist_data_stacked, bin_vecs, ytick_num, min_radius, max_radius, show_stack): """Compute a colored mesh from this object's histogram. Args: hist_data: Histogram of analysis values greater then zero. hist_data_stacked: Histogram of analysis values averaged by number of stacks. bin_vecs: Array of histogram bin edge vectors. ytick_num: Number of Y-axis intervals. min_radius: Minimum radius for windrose mesh. max_radius: Maximum radius for windrose mesh. show_stack: Boolean indicating if stacked histogram. Returns: A colored Mesh2D. """ # Default rose is a unit circle centered at origin. We can scale and translate # the resulting mesh. vec_cpt = (0, 0) # Compute histogram array hist_array = WindRose._histogram_array_radial(bin_vecs, vec_cpt, hist_data, hist_data_stacked, (min_radius, max_radius), show_stack) # Flatten and add coordinates if not show_stack: hist_array = ([v] for v in hist_array) # Make mesh hist_coords = [interval for bar in hist_array for interval in bar] mesh_array = [[Point2D.from_array(vec) for vec in vecs] for vecs in hist_coords] # Extract analysis values for color color_array = [ interval for bar in hist_data_stacked for interval in bar ] return mesh_array, color_array
def test_intersect_polygon_segments_zero_tolerance(): """Tests that the default tolerance of 0 does not update nearby polygons.""" pts0 = (Point2D(1, 0), Point2D(4, 0), Point2D(4, 1.99), Point2D(1, 1.99)) polygon0 = Polygon2D(pts0) pts1 = (Point2D(0, 2), Point2D(3, 2), Point2D(3, 4), Point2D(0, 4)) polygon1 = Polygon2D(pts1) polygon2, polygon3 = Polygon2D._intersect_polygon_segments( polygon0, polygon1) assert len(polygon2.segments) == 4 # No new points assert all([ polygon0.vertices[i] == polygon2.vertices[i] for i in range(len(polygon0.vertices)) ]) assert len(polygon3.segments) == 4 # No new points assert all([ polygon1.vertices[i] == polygon3.vertices[i] for i in range(len(polygon1.vertices)) ])
def test_arc2_init_radius(): """Test the initalization of Arc2D objects with a non-unit radius.""" pt = Point2D(2, 2) arc = Arc2D(pt, 2, math.pi, 0) assert arc.c == pt assert arc.r == 2 assert arc.a1 == math.pi assert arc.a2 == 0 assert arc.p1.x == pytest.approx(0, rel=1e-3) assert arc.p1.y == pytest.approx(2, rel=1e-3) assert arc.p2.x == pytest.approx(4, rel=1e-3) assert arc.p2.y == pytest.approx(2, rel=1e-3) assert arc.midpoint.x == pytest.approx(2, rel=1e-3) assert arc.midpoint.y == pytest.approx(0, rel=1e-3) assert arc.length == pytest.approx(2 * math.pi, rel=1e-3) assert arc.angle == pytest.approx(math.pi, rel=1e-3) assert arc.is_circle is False assert arc.is_inverted is True
def test_arc2_init_reveresed(): """Test the initalization of Arc2D objects with reversed direction.""" pt = Point2D(2, 0) arc = Arc2D(pt, 1, 1.5 * math.pi, 0.5 * math.pi) assert arc.c == pt assert arc.r == 1 assert arc.a1 == 1.5 * math.pi assert arc.a2 == 0.5 * math.pi assert arc.p1.x == pytest.approx(2, rel=1e-3) assert arc.p1.y == pytest.approx(-1, rel=1e-3) assert arc.p2.x == pytest.approx(2, rel=1e-3) assert arc.p2.y == pytest.approx(1, rel=1e-3) assert arc.midpoint.x == pytest.approx(3, rel=1e-3) assert arc.midpoint.y == pytest.approx(0, rel=1e-3) assert arc.length == pytest.approx(math.pi, rel=1e-3) assert arc.angle == pytest.approx(math.pi, rel=1e-3) assert arc.is_circle is False assert arc.is_inverted is True
def test_polygon2d_init_from_shape_with_hole(): """Test the initialization of Polygon2D from_shape_with_hole.""" bound_pts = [Point2D(0, 0), Point2D(4, 0), Point2D(4, 4), Point2D(0, 4)] hole_pts = [Point2D(1, 1), Point2D(3, 1), Point2D(3, 3), Point2D(1, 3)] polygon = Polygon2D.from_shape_with_hole(bound_pts, hole_pts) assert isinstance(polygon.vertices, tuple) assert len(polygon.vertices) == 10 for point in polygon.vertices: assert isinstance(point, Point2D) assert isinstance(polygon.segments, tuple) assert len(polygon.segments) == 10 for seg in polygon.segments: assert isinstance(seg, LineSegment2D) assert polygon.area == 12 assert polygon.perimeter == pytest.approx(26.828427, rel=1e-3) assert not polygon.is_clockwise assert not polygon.is_convex assert not polygon.is_self_intersecting
def _hour_polylines(self, y_vals, x_hr_dist): """Get a polyline from a lists of Y-coordinate values. Args: y_vals: A list of lists with each sublist having y values. x_hr_dist: The x distance moved by each cell of the mesh. Returns: polylines: A list of Polyline2D. """ plines = [] for month in range(len(y_vals)): verts = [] start_x = self._base_point.x + month * self._x_dim for hour in range(len(y_vals[0])): x_val = start_x + x_hr_dist * hour y_val = y_vals[month][hour] verts.append(Point2D(x_val, y_val)) plines.append(Polyline2D(verts)) return plines
def test_polygon2d_init_from_rectangle(): """Test the initialization of Polygon2D from_rectangle.""" polygon = Polygon2D.from_rectangle(Point2D(0, 0), Vector2D(0, 1), 2, 2) assert isinstance(polygon.vertices, tuple) assert len(polygon.vertices) == 4 for point in polygon.vertices: assert isinstance(point, Point2D) assert isinstance(polygon.segments, tuple) assert len(polygon.segments) == 4 for seg in polygon.segments: assert isinstance(seg, LineSegment2D) assert seg.length == 2 assert polygon.area == 4 assert polygon.perimeter == 8 assert not polygon.is_clockwise assert polygon.is_convex assert not polygon.is_self_intersecting
def test_reflect(): """Test the Point2D reflect method.""" pt_1 = Point2D(2, 2) origin_1 = Point2D(0, 1) origin_2 = Point2D(1, 1) normal_1 = Vector2D(0, 1) normal_2 = Vector2D(-1, 1).normalize() assert pt_1.reflect(normal_1, origin_1) == Point2D(2, 0) assert pt_1.reflect(normal_1, origin_2) == Point2D(2, 0) assert pt_1.reflect(normal_2, origin_2) == Point2D(2, 2) test_1 = pt_1.reflect(normal_2, origin_1) assert test_1.x == pytest.approx(1, rel=1e-3) assert test_1.y == pytest.approx(3, rel=1e-3)
def point3d_to_stereographic(point, radius=100, origin=Point3D()): """Get a Point2D for a given Point3D using a stereographic projection. Args: point: A ladybug_geometry Point3D to be projected into 2D space via stereographic projection. radius: A positive number for the radius of the sphere on which the point exists. (Default: 100). origin: An optional ladybug_geometry Point3D representing the origin of the coordinate system in which the projection is happening. (eg. the center of the compass). """ # move the point to the world origin coords = ((point.x - origin.x), (point.y - origin.y), (point.z - origin.z)) # perform the stereographic projection while scaling it to the unit sphere proj_pt = (coords[0] / (radius + coords[2]), coords[1] / (radius + coords[2])) # move the point back to its original location and scale return Point2D(proj_pt[0] * radius + origin.x, proj_pt[1] * radius + origin.y)
def _normalize_contour(contour, tol): """ Consumes list of x,y coordinate tuples and returns list of Point2Ds. Args: contour: list of x,y tuples from contour. tol: Number for point equivalence tolerance. Return: list of Point2Ds of contour. """ contour = [Point2D(float(x), float(y)) for (x, y) in contour] normed_contour = [] for prev, point, next in _window(contour): normed_prev = (point - prev).normalize() normed_next = (next - point).normalize() if not point.is_equivalent(next, tol) or \ normed_prev.is_equivalent(normed_next, tol): normed_contour.append(point) return normed_contour
def test_closest_points_between_line(): """Test the LineSegement2D distance_to_point method.""" pt_1 = Point2D(2, 2) vec_1 = Vector2D(0, 2) seg_1 = LineSegment2D(pt_1, vec_1) pt_2 = Point2D(0, 3) vec_2 = Vector2D(1, 0) seg_2 = LineSegment2D(pt_2, vec_2) pt_3 = Point2D(0, 0) vec_3 = Vector2D(1, 1) seg_3 = LineSegment2D(pt_3, vec_3) assert seg_1.closest_points_between_line(seg_2) == (Point2D(2, 3), Point2D(1, 3)) assert seg_1.closest_points_between_line(seg_3) == (Point2D(2, 2), Point2D(1, 1)) assert seg_1.distance_to_line(seg_2) == 1 assert seg_1.distance_to_line(seg_3) == pytest.approx(1.41421, rel=1e-3)
def draw_analemma_and_arcs(sp, datetimes, radius, center_pt3d): """Draw analemma and day arc Rhino geometry. Args: sp: Sunpath object for which geometry will be drawn. datetimes: A list of datetimes, which will be used to get days if _annual_ is False. radius: Number for the radius of the sun path. center_pt3d: Point3D for the center of the sun path. Returns: analemma: List of Rhino curves for the analemmas daily: List of Rhino curves for the daily arcs. """ sp.daylight_saving_period = None # set here so analemmas aren't messed up center_pt, z = Point2D(center_pt3d.x, center_pt3d.y), center_pt3d.z if _annual_: if projection_ is None: analemma = [from_polyline3d(pline) for pline in sp.hourly_analemma_polyline3d( center_pt3d, radius, True, solar_time_)] daily = [from_arc3d(arc) for arc in sp.monthly_day_arc3d(center_pt3d, radius)] else: analemma = [from_polyline2d(pline, z) for pline in sp.hourly_analemma_polyline2d( projection_, center_pt, radius, True, solar_time_)] daily = [from_polyline2d(arc, z) for arc in sp.monthly_day_polyline2d( projection_, center_pt3d, radius)] else: analemma = [] # No Analemmas for a daily sun path doys = set(dt.doy for dt in datetimes) dates = [Date.from_doy(doy) for doy in doys] if projection_ is None: daily = [from_arc3d(sp.day_arc3d(dat.month, dat.day, center_pt3d, radius)) for dat in dates] else: daily = [] for dat in dates: pline = sp.day_polyline2d(dat.month, dat.day, projection_, center_pt, radius) daily.append(from_polyline2d(pline, z)) return analemma, daily
def flip(self, seg_length): """Flip the direction of the windows along a segment. This is needed since windows can exist asymmetrically across the wall segment and operations like reflecting the Room2D across a plane will require the window parameters to be flipped to remain in the same place. Args: seg_length: The length of the segment along which the parameters are being flipped. """ # set values derived from the property of the segment normal = Vector2D(1, 0) origin = Point2D(seg_length / 2, 0) # loop through the polygons and reflect them across the midplane of the wall new_polygons = [] for polygon in self.polygons: new_verts = tuple( pt.reflect(normal, origin) for pt in polygon.vertices) new_polygons.append(Polygon2D(tuple(reversed(new_verts)))) return DetailedWindows(new_polygons)
def test_remove_faces_only(): """Test the Mesh2D remove_faces method.""" mesh = Mesh2D.from_grid(Point2D(1, 1), 8, 2, 0.25, 1) assert len(mesh.vertices) == 27 assert len(mesh.faces) == 16 assert mesh.area == 4 pattern_1 = [] for i in range(4): pattern_1.extend([True, False, False, False]) mesh_1 = mesh.remove_faces_only(pattern_1) assert len(mesh_1.vertices) == 27 assert len(mesh_1.faces) == 4 assert mesh_1.area == 1 pattern_2 = [] for i in range(8): pattern_2.extend([True, False]) mesh_2 = mesh.remove_faces_only(pattern_2) assert len(mesh_2.vertices) == 27 assert len(mesh_2.faces) == 8 assert mesh_2.area == 2
def from_epw(cls, epw_file, legend_parameters=None, base_point=Point2D(), x_dim=1, y_dim=1500, min_temperature=-20, max_temperature=50, max_humidity_ratio=0.03, use_ip=False): """Create a psychrometric chart object using the data in an epw file. Args: epw_file: Full path to epw weather file. legend_parameters: An optional LegendParameter object to change the display of the PsychrometricChart. (Default: None). base_point: A Point2D to be used as a starting point to generate the geometry of the plot. (Default: (0, 0)). x_dim: A number to set the X dimension of each degree of temperature on the chart. (Default: 1). y_dim: A number to set the Y dimension of a unity humidity ratio on the chart. Note that most maximum humidity ratios are around 0.03. (Default: 1500). min_temperature: An integer for the minimum temperature on the chart in degrees. This should be celsius if use_ip is False and fahrenheit if use_ip is True. (Default: -20; suitable for celsius). max_temperature: An integer for the maximum temperature on the chart in degrees. This should be celsius if use_ip is False and fahrenheit if use_ip is True. (Default: 50; suitable for celsius). max_humidity_ratio: A value for the maximum humidity ratio in kg water / kg air. (Default: 0.03). use_ip: Boolean to note whether temperature values should be plotted in Fahrenheit instead of Celsius. (Default: False). """ epw = EPW(epw_file) pressure = epw.atmospheric_station_pressure.average return cls(epw.dry_bulb_temperature, epw.relative_humidity, pressure, legend_parameters, base_point, x_dim, y_dim, min_temperature, max_temperature, max_humidity_ratio, use_ip)
def _compute_hour_line_pts(self, hour_labels): """Compute the points for the hour lines and labels.""" st_hr = self.analysis_period.st_hour end_hr = self.analysis_period.end_hour + 1 t_step = self.analysis_period.timestep _hour_points = [] _hour_text = [] last_hr = 0 for hr in hour_labels: if st_hr <= hr <= end_hr: pt_y = self.base_point.y + (hr - st_hr) * self.y_dim * t_step pt = Point2D(self._container.min_point.x, pt_y) _hour_points.append(pt) hr_val = hr if hr <= 12 else hr - 12 am_pm = 'PM' if 12 <= hr < 24 else 'AM' if hr_val == 0: hr_val = 12 _hour_text.append('{} {}'.format(hr_val, am_pm)) last_hr = hr if self.analysis_period.timestep > 1 and last_hr == end_hr: _hour_points.pop(-1) _hour_text.pop(-1) return _hour_points, _hour_text
def infinite_line2d_intersection(seg1, seg2): """Intersects two line2D assuming they are infinite. This method computes the linear equation from the segments. Then solves the linear system to find the intersection for both: A * x = C x = A^-1 * C """ # Compute the A,B coefficients seg1_3d = Point3D(*(seg1.p2 - seg1.p1).to_array(), 0) seg2_3d = Point3D(*(seg2.p2 - seg2.p1).to_array(), 0) z = Point3D(0, 0, 1) norm1 = seg1_3d.cross(z) norm2 = seg2_3d.cross(z) norm1 = norm1 / norm1.magnitude norm2 = norm2 / norm2.magnitude # Simplify naming for the A matrix (linear equation coefficeints) _a, _b, _c, _d = norm1.x, norm1.y, norm2.x, norm2.y # Substitute point in each line to solve for C array c1 = (_a * seg1.p2.x) + (_b * seg1.p2.y) c2 = (_c * seg2.p2.x) + (_d * seg2.p2.y) # Check the determinate det = (_a * _d) - (_b * _c) if abs(det) < 1e-10: return # Solve for x my multiplying Ainv by C x = [(_d / det * c1) + (-_b / det * c2), (-_c / det * c1) + (_a / det * c2)] intersection_pt = Point2D.from_array(x) return intersection_pt
def test_mesh2d_init_from_polygon_triangulated(): """Test the initalization of Mesh2D from_polygon_triangulated.""" verts = (Point2D(0, 0), Point2D(0, 2), Point2D(2, 2), Point2D(4, 0)) polygon = Polygon2D(verts) mesh = Mesh2D.from_polygon_triangulated(polygon) assert len(mesh.vertices) == 4 assert len(mesh.faces) == 2 assert mesh.area == 6 assert mesh.min == Point2D(0, 0) assert mesh.max == Point2D(4, 2) assert mesh.center == Point2D(2, 1) assert mesh.centroid.x == pytest.approx(1.56, rel=1e-2) assert mesh.centroid.y == pytest.approx(0.89, rel=1e-2) assert len(mesh.face_areas) == 2 assert mesh.face_areas[0] == 2 assert mesh.face_areas[1] == 4 assert len(mesh.face_centroids) == 2 assert mesh._is_color_by_face is False assert mesh.colors is None
def test_reflect(): """Test the Mesh2D reflect method.""" pts = (Point2D(1, 1), Point2D(1, 2), Point2D(2, 2), Point2D(2, 1), Point2D(3, 1)) mesh = Mesh2D(pts, [(0, 1, 2, 3), (2, 3, 4)]) origin_1 = Point2D(1, 0) normal_1 = Vector2D(1, 0) normal_2 = Vector2D(-1, -1).normalize() test_1 = mesh.reflect(normal_1, origin_1) assert test_1[0].x == pytest.approx(1, rel=1e-3) assert test_1[0].y == pytest.approx(1, rel=1e-3) assert test_1[2].x == pytest.approx(0, rel=1e-3) assert test_1[2].y == pytest.approx(2, rel=1e-3) assert mesh.area == test_1.area assert len(mesh.vertices) == len(test_1.vertices) assert len(mesh.faces) == len(test_1.faces) test_1 = mesh.reflect(normal_2, Point2D(0, 0)) assert test_1[0].x == pytest.approx(-1, rel=1e-3) assert test_1[0].y == pytest.approx(-1, rel=1e-3) assert test_1[2].x == pytest.approx(-2, rel=1e-3) assert test_1[2].y == pytest.approx(-2, rel=1e-3) assert mesh.area == test_1.area assert len(mesh.vertices) == len(test_1.vertices) assert len(mesh.faces) == len(test_1.faces) test_2 = mesh.reflect(normal_2, origin_1) assert test_2[0].x == pytest.approx(0, rel=1e-3) assert test_2[0].y == pytest.approx(0, rel=1e-3) assert test_2[2].x == pytest.approx(-1, rel=1e-3) assert test_2[2].y == pytest.approx(-1, rel=1e-3) assert mesh.area == test_2.area assert len(mesh.vertices) == len(test_2.vertices) assert len(mesh.faces) == len(test_2.faces)
def test_rotate(): """Test the Mesh2D rotate method.""" pts = (Point2D(0, 0), Point2D(0, 2), Point2D(2, 2), Point2D(2, 0), Point2D(4, 0)) mesh = Mesh2D(pts, [(0, 1, 2, 3), (2, 3, 4)]) origin_1 = Point2D(1, 1) test_1 = mesh.rotate(math.pi, origin_1) assert test_1[0].x == pytest.approx(2, rel=1e-3) assert test_1[0].y == pytest.approx(2, rel=1e-3) assert test_1[2].x == pytest.approx(0, rel=1e-3) assert test_1[2].y == pytest.approx(0, rel=1e-3) assert mesh.area == test_1.area assert len(mesh.vertices) == len(test_1.vertices) assert len(mesh.faces) == len(test_1.faces) test_2 = mesh.rotate(math.pi/2, origin_1) assert test_2[0].x == pytest.approx(2, rel=1e-3) assert test_2[0].y == pytest.approx(0, rel=1e-3) assert test_2[2].x == pytest.approx(0, rel=1e-3) assert test_2[2].y == pytest.approx(2, rel=1e-3) assert mesh.area == test_2.area assert len(mesh.vertices) == len(test_2.vertices) assert len(mesh.faces) == len(test_2.faces)
if north_ is not None: # process the north_ try: north_ = math.degrees( to_vector2d(north_).angle_clockwise(Vector2D(0, 1))) except AttributeError: # north angle instead of vector north_ = float(north_) assert -360.0 <= north_ <= 360.0, 'The north orientation must be greater ' \ 'then -360 and less then 360 to plot the wind rose. ' \ 'Got: {}'.format(north_) else: north_ = 0.0 # set default values for the chart dimensions _center_pt_ = to_point3d( _center_pt_) if _center_pt_ is not None else Point3D() center_pt_2d = Point2D(_center_pt_.x, _center_pt_.y) # set defaults frequency hours and distance so chart is same scale as other LB plots if _freq_hours_ is None: _freq_hours_ = 50.0 if _freq_dist_ is None: _freq_dist_ = 5.0 / conversion_to_meters() # set default show_freq and _show_calmrose_ _show_calmrose_ = False if _show_calmrose_ is None else _show_calmrose_ _show_freq_ = True if _show_freq_ is None else _show_freq_ # set up empty lists of objects to be filled all_wind_avg_val = [] all_wind_frequency = [] all_windrose_lines = []
def rectangle_plan(width, length, floor_to_floor_height, perimeter_offset, story_count, orientation_angle, outdoor_roof, ground_floor, units, tolerance, output_file): """Create a model with a rectangular floor plan.\n Note that the resulting Rooms in the model won't have any windows or solved adjacencies and the edit commands should be used for this purpose.\n \n Args:\n width: Number for the width of the plan (in the X direction).\n depth: Number for the depth of the plan (in the Y direction).\n floor_to_floor_height: Number for the height of each floor of the model (in the Z direction). """ try: unique_id = str(uuid.uuid4())[:8] # unique identifier for the rooms # create the geometry of the rooms for the first floor footprint = Face3D.from_rectangle(width, length) if perimeter_offset != 0: # use the straight skeleton methods assert perimeter_offset > 0, 'perimeter_offset cannot be less than than 0.' try: footprint = [] base = Polygon2D.from_rectangle(Point2D(), Vector2D(0, 1), width, length) sub_polys_perim, sub_polys_core = perimeter_core_subpolygons( polygon=base, distance=perimeter_offset, tol=tolerance) for s_poly in sub_polys_perim + sub_polys_core: sub_face = Face3D( [Point3D(pt.x, pt.y, 0) for pt in s_poly]) footprint.append(sub_face) except RuntimeError as e: footprint = [Face3D.from_rectangle(width, length)] else: footprint = [Face3D.from_rectangle(width, length)] first_floor = [ Polyface3D.from_offset_face(geo, floor_to_floor_height) for geo in footprint ] # rotate the geometries if an orientation angle is specified if orientation_angle != 0: angle, origin = math.radians(orientation_angle), Point3D() first_floor = [geo.rotate_xy(angle, origin) for geo in first_floor] # create the initial rooms for the first floor rmids = ['Room'] if len(first_floor) == 1 else [ 'Front', 'Right', 'Back', 'Left' ] if len(first_floor) == 5: rmids.append('Core') rooms = [] for polyface, rmid in zip(first_floor, rmids): rooms.append( Room.from_polyface3d('{}_{}'.format(rmid, unique_id), polyface)) # if there are multiple stories, duplicate the first floor rooms if story_count != 1: all_rooms = [] for i in range(story_count): for room in rooms: new_room = room.duplicate() new_room.add_prefix('Floor{}'.format(i + 1)) m_vec = Vector3D(0, 0, floor_to_floor_height * i) new_room.move(m_vec) all_rooms.append(new_room) rooms = all_rooms # assign adiabatic boundary conditions if requested if not outdoor_roof and ad_bc: for room in rooms[-len(first_floor):]: room[-1].boundary_condition = ad_bc # make the roof adiabatic if not ground_floor and ad_bc: for room in rooms[:len(first_floor)]: room[0].boundary_condition = ad_bc # make the floor adiabatic # create the model object model_id = 'Rectangle_Plan_Model_{}'.format(unique_id) model = Model(model_id, rooms, units=units, tolerance=tolerance, angle_tolerance=1) # write the model out to the file or stdout output_file.write(json.dumps(model.to_dict())) except Exception as e: _logger.exception( 'Rectangle plan model creation failed.\n{}'.format(e)) sys.exit(1) else: sys.exit(0)
def segment_mesh_2d(self): """A Ladybug Mesh2D for the legend colors.""" _o = self.legend_parameters.base_plane.o return self._segment_mesh_2d(Point2D(_o.x, _o.y))