Esempio n. 1
0
    def from_polygon(cls, polygon, slav):
        """Construct a LAV from a list of point coordinates representing a polygon.

        Args:
            polygon: list of points (tuple of x,y coordinates).
            slav: SLAV (a set of circular lists of active vertices).
            tol: tolerance for point equality.

        Returns:
            LAV (single circular list of active vertices).
        """
        lav = cls(slav)
        for prev, point, next in _window(polygon):
            lav._len += 1
            vertex = _LAVertex(point,
                               LineSegment2D.from_end_points(prev, point),
                               LineSegment2D.from_end_points(point, next),
                               tol=slav.tol)
            vertex.lav = lav
            if lav.head is None:
                lav.head = vertex
                vertex.prev = vertex.next = vertex
            else:
                vertex.next = lav.head
                vertex.prev = lav.head.prev
                vertex.prev.next = vertex
                lav.head.prev = vertex
        return lav
    def intersect_graph_with_segment(self, segment):
        """Update graph with intersection of partial segment that crosses through polygon.

        Args:
            segment: LineSegment2D to intersect. Does not need to be contained within
            polygon.
        """
        int_key_lst = []

        for node in self.ordered_nodes:

            # Convert graph edge to trimming segment
            next_node = node.adj_lst[0]
            trim_seg = LineSegment2D.from_end_points(node.pt, next_node.pt)
            int_pt = intersection2d.intersect_line2d_infinite(
                trim_seg, segment)

            # Add intersection point as new node in graph
            if int_pt:
                int_key = self.insert_node(node,
                                           int_pt,
                                           next_node,
                                           exterior=False)
                int_key_lst.append(int_key)

        # Add intersection edges
        if len(int_key_lst) == 2:
            # Typical case with convex cases
            # Make edge between intersection nodes
            n1, n2 = self.node(int_key_lst[0]), self.node(int_key_lst[1])
            self.add_node(n1.pt, [n2.pt], exterior=False)
            self.add_node(n2.pt, [n1.pt], exterior=False)

        elif len(int_key_lst) > 2:
            # Edge case with concave geometry creates multiple intersections
            # Sort distance and add adjacency
            n = self.node(int_key_lst[0])
            distances = [(0, 0.0)]

            for i, k in enumerate(int_key_lst[1:]):
                distance = LineSegment2D.from_end_points(
                    n.pt,
                    self.node(k).pt).length
                distances.append((i + 1, distance))

            distances = sorted(distances, key=lambda t: t[1])

            for i in range(len(distances) - 1):
                k1, k2 = distances[i][0], distances[i + 1][0]
                n1, n2 = self.node(int_key_lst[k1]), self.node(int_key_lst[k2])

                # Add bidirection so the min cycle works
                self.add_node(n1.pt, [n2.pt], exterior=False)
                self.add_node(n2.pt, [n1.pt], exterior=False)
def test_join_segments_disconnected():
    """Test the join_segments method with diconnected polylines."""
    pts = (Point2D(0, 0), Point2D(2, 0), Point2D(2, 2), Point2D(0, 2))
    extra_pts = (Point2D(3, 3), Point2D(4, 3), Point2D(4, 4), Point2D(3, 4))

    l_segs = (LineSegment2D.from_end_points(extra_pts[0], extra_pts[1]),
              LineSegment2D.from_end_points(pts[0], pts[1]),
              LineSegment2D.from_end_points(pts[2], pts[3]),
              LineSegment2D.from_end_points(extra_pts[3], extra_pts[2]))
    p_lines = Polyline2D.join_segments(l_segs, 0.01)
    assert len(p_lines) == 4
def test_to_from_array():
    """Test to/from array method"""
    test_line = LineSegment2D.from_end_points(Point2D(2, 0), Point2D(2, 2))
    line_array = ((2, 0), (2, 2))

    assert test_line == LineSegment2D.from_array(line_array)

    line_array = ((2, 0), (2, 2))
    test_line = LineSegment2D.from_end_points(Point2D(2, 0), Point2D(2, 2))

    assert test_line.to_array() == line_array

    test_line_2 = LineSegment2D.from_array(test_line.to_array())
    assert test_line == test_line_2
Esempio n. 5
0
    def _compute_enthalpy_range(self):
        """Compute the values for enthalpy range and lines."""
        # constants used throughout the calculation
        low_y = self.base_point.y + 1e-6
        up_y = self.hr_y_value(self._max_humidity_ratio)
        border, sat_line = self.chart_border, self._saturation_line
        all_enthalpies, ref_temp = tuple(range(0, 160, 10)), 0
        enth_lbl = all_enthalpies
        if self.use_ip:
            enth_lbl = tuple(range(0, 65, 5))
            all_enthalpies = self.ENTH_TYPE.to_unit(enth_lbl, 'kJ/kg',
                                                    'Btu/lb')
            ref_temp = self.TEMP_TYPE.to_unit([0], 'C', 'F')[0]

        # loop through the enthalpies and compute the lines of constant enthalpy
        enth_range, enth_lines = [], []
        for i, enthalpy in enumerate(all_enthalpies):
            st_db = db_temp_from_enth_hr(enthalpy, 0.0, ref_temp)
            end_db = db_temp_from_enth_hr(enthalpy, 0.03, ref_temp)
            if self.use_ip:
                st_db, end_db = self.TEMP_TYPE.to_unit((st_db, end_db), 'F',
                                                       'C')
            enth_line = LineSegment2D.from_end_points(
                Point2D(self.t_x_value(st_db), low_y),
                Point2D(self.t_x_value(end_db), up_y))
            border_ints = border.intersect_line_ray(enth_line)
            if len(border_ints) == 2:
                enth_range.append(enth_lbl[i])
                seg = LineSegment2D.from_end_points(border_ints[0],
                                                    border_ints[1])
                enth_lines.append(seg)
            else:
                sat_ints = sat_line.intersect_line_ray(enth_line)
                if len(sat_ints) != 0:
                    enth_range.append(enth_lbl[i])
                    if len(border_ints) == 1:
                        seg = LineSegment2D.from_end_points(
                            border_ints[0], sat_ints[0])
                    else:
                        seg = LineSegment2D.from_end_points(
                            enth_line.p, sat_ints[0])
                    enth_lines.append(seg)

        # set the properties on this class
        self._enth_range = enth_range
        self._enth_lines = enth_lines
Esempio n. 6
0
 def ticks_from_angles(self, angles, factor=0.3):
     """Get a list of Linesegment2Ds from a list of angles between 0 and 360."""
     pts_in = self.label_points_from_angles(angles, 0)
     pts_out = self.label_points_from_angles(angles, factor)
     return [
         LineSegment2D.from_end_points(pi, po)
         for pi, po in zip(pts_in, pts_out)
     ]
Esempio n. 7
0
def to_polyline2d(polyline):
    """Ladybug Polyline2D from a Rhino PolyLineCurve.

    A LineSegment2D will be returned if the input polyline has only two points.
    """
    pts = [to_point2d(polyline.Point(i)) for i in range(polyline.PointCount)]
    return Polyline2D(pts) if len(pts) != 2 else LineSegment2D.from_end_points(
        *pts)
Esempio n. 8
0
def _split_polygon_graph(node1,
                         node2,
                         distance,
                         poly_graph,
                         tol,
                         recurse_limit=3000,
                         print_recurse=False):
    """Split the PolygonDirectedGraph by an edge offset at a distance.

    Args:
        node1: A node defining the edge to offset for splitting. If the graph
            defines a counter-clockwise polygon, this node should represent
            the left hand-most point.
        node2: A node defining the edge to offset for splitting. If the graph
            defines a counter-clockwise polygon, this node should represent
            the right hand-most point.
        distance: The distance to offset the splitting edge, in model units.
        poly_graph: A PolygonDirectedGraph representing a single polygon.
        tol: Tolerance for point equivalence.
        recurse_limit: optional parameter to limit the number of cycles looking for
            polygons in skeleton graph. (Default: 3000).
        print_recurse: optional boolean to print cycle loop cycles, for
            debugging. (Default: False).

    Returns:
        A list of nodes representing the split polygon adjacent to the exterior
        edge defined by node1 and node2.
    """

    ext_seg = LineSegment2D.from_end_points(node1.pt, node2.pt)

    # Compute normal facing into the polygon
    ext_arr = ext_seg.v.to_array()
    ext_seg_v = Vector3D(ext_arr[0], ext_arr[1], 0)
    normal = ext_seg_v.cross(Vector3D(0, 0, -1)).normalize() * distance

    # Move segment by normal to get offset segment
    offset_seg = ext_seg.move(normal)

    poly_graph = PolygonDirectedGraph.from_point_array(
        [n.pt for n in poly_graph], tol=tol)
    poly_graph.outer_root_key = poly_graph.ordered_nodes[0].key

    # Update graph by intersecting offset segment with other edges
    poly_graph.intersect_graph_with_segment(offset_seg)

    # Get the minimum cycle. Since we start at the exterior edge, this will
    # return the perimeter offset.
    root_node = poly_graph.node(poly_graph.outer_root_key)
    next_node = root_node.adj_lst[0]

    split_poly_nodes = poly_graph.min_ccw_cycle(root_node,
                                                next_node,
                                                recurse_limit=recurse_limit,
                                                print_recurse=print_recurse)

    return split_poly_nodes
Esempio n. 9
0
def test_connector_dict_methods():
    """Test the ElectricalConnector to/from dict methods."""
    geo = LineSegment2D.from_end_points(Point2D(0, 0), Point2D(100, 0))
    wire = Wire('OH AL 2/0 A')
    connector = ElectricalConnector('Connector_1', geo, [wire])

    connector_dict = connector.to_dict()
    new_connector = ElectricalConnector.from_dict(connector_dict)
    assert connector_dict == new_connector.to_dict()
Esempio n. 10
0
 def rh_label_points(self):
     """Get a tuple of Point2Ds for the relative humidity labels on the chart."""
     last_sgs = (LineSegment2D.from_end_points(p[-2], p[-1])
                 for p in self._rh_lines)
     last_dirs = (seg.v.reverse().normalize() * (self._x_dim * 2)
                  for seg in last_sgs)
     move_vec = (Vector2D(vec.x - (self._x_dim * 0.4), vec.y)
                 for vec in last_dirs)
     return tuple(pl[-1].move(vec)
                  for pl, vec in zip(self._rh_lines, move_vec))
def test_init_from_endpoints():
    """Test the initialization of LineSegment2D from end points."""
    pt_1 = Point2D(2, 0)
    pt_2 = Point2D(2, 2)
    seg = LineSegment2D.from_end_points(pt_1, pt_2)

    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.length == 2
Esempio n. 12
0
 def hr_lines(self):
     """Get a tuple of LineSegment2Ds for the humidity ratio labels on the chart."""
     hr_lines, xmax = [], self._x_range[-1]
     for hr, y in zip(self._hr_range, self._y_range):
         tmin = db_temp_from_rh_hr(100, hr, self.average_pressure)
         tmin = self.TEMP_TYPE.to_unit([tmin], 'F',
                                       'C')[0] if self.use_ip else tmin
         xmin = self.t_x_value(tmin)
         xmin = xmin if xmin > self.base_point.x else self.base_point.x
         l_seg = LineSegment2D.from_end_points(Point2D(xmax, y),
                                               Point2D(xmin, y))
         hr_lines.append(l_seg)
     return hr_lines
Esempio n. 13
0
    def __init__(self, polygon, holes, tol):
        self.tol = tol
        contours = [_normalize_contour(polygon, tol)]
        contours.extend([_normalize_contour(hole, tol) for hole in holes])

        self._lavs = [_LAV.from_polygon(contour, self) for contour in contours]

        # Store original polygon edges for calculating split events
        self._original_edges = [
            _OriginalEdge(
                LineSegment2D.from_end_points(vertex.prev.point, vertex.point),
                vertex.prev.bisector, vertex.bisector)
            for vertex in chain.from_iterable(self._lavs)
        ]
Esempio n. 14
0
def test_connector_init():
    """Test the initialization of ElectricalConnector and basic properties."""
    geo = LineSegment2D.from_end_points(Point2D(0, 0), Point2D(100, 0))
    wire = Wire('OH AL 2/0 A')
    connector = ElectricalConnector('Connector_1', geo, [wire])
    str(connector)  # test the string representation

    assert connector.identifier == 'Connector_1'
    assert connector.geometry == geo
    assert len(connector) == 1
    assert len(connector.wires) == 1
    assert connector.wires[0] == wire
    assert connector[0] == wire
    assert connector.wire_ids == ['OH AL 2/0 A']
Esempio n. 15
0
    def _compute_wb_range(self):
        """Compute the values for wet bulb range and lines."""
        # constants used throughout the calculation
        low_y, border = self.base_point.y - 1e-6, self.chart_border
        all_wbs = wb_c = tuple(
            range(self._min_temperature, self._max_temperature, 5))
        if self.use_ip:
            wb_c = self.TEMP_TYPE.to_unit(wb_c, 'C', 'F')

        # loop through the wet bulb and compute the lines of constant wet bulb
        wb_range, wb_lines = [], []
        for i, wb in enumerate(wb_c):
            st_db = db_temp_and_hr_from_wb_rh(wb, 0, self._average_pressure)[0]
            end_db, end_hr = db_temp_and_hr_from_wb_rh(wb, 100,
                                                       self._average_pressure)
            if self.use_ip:
                st_db, end_db = self.TEMP_TYPE.to_unit((st_db, end_db), 'F',
                                                       'C')
            enth_line = LineSegment2D.from_end_points(
                Point2D(self.t_x_value(st_db), low_y),
                Point2D(self.t_x_value(end_db), self.hr_y_value(end_hr)))
            border_ints = border.intersect_line_ray(enth_line)
            if len(border_ints) == 2:
                wb_range.append(all_wbs[i])
                seg = LineSegment2D.from_end_points(border_ints[0],
                                                    border_ints[1])
                wb_lines.append(seg)
            elif len(border_ints) == 1:
                wb_range.append(all_wbs[i])
                seg = LineSegment2D.from_end_points(border_ints[0],
                                                    enth_line.p2)
                wb_lines.append(seg)

        # set the properties on this class
        self._wb_range = wb_range
        self._wb_lines = wb_lines
Esempio n. 16
0
    def temperature_lines(self):
        """Get a tuple of LineSegment2Ds for the temperature labels on the chart."""
        # get the Y-values for the top of the temperature lines
        hr_vals = (humid_ratio_from_db_rh(t, 100, self.average_pressure)
                   for t in self._temp_range)
        top_y = []
        for hr in hr_vals:
            y_val = self.hr_y_value(hr) if hr < self._max_humidity_ratio \
                else self.hr_y_value(self._max_humidity_ratio)
            top_y.append(y_val)

        t_lines = []  # create the array of line segments
        for x_val, y_val in zip(self._x_range, top_y):
            l_seg = LineSegment2D.from_end_points(
                Point2D(x_val, self._base_point.y), Point2D(x_val, y_val))
            t_lines.append(l_seg)
        return t_lines
def _offset_bisector(seg1, seg2, distance):
    """ Calculates the magnitude of the offset bisector."""

    p1 = infinite_line2d_intersection(seg1, seg2)

    # Normal offset outward
    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)

    # Get offset
    off1 = seg1.move((norm1 / norm1.magnitude) * distance)
    off2 = seg2.move((norm2 / norm2.magnitude) * distance)
    p2 = infinite_line2d_intersection(off1, off2)
    if p1 is None or p2 is None:
        return

    return LineSegment2D.from_end_points(p1, p2)
Esempio n. 18
0
def test_connector_transform():
    """Test the ElectricalConnector transform methods."""
    geo = LineSegment2D.from_end_points(Point2D(0, 0), Point2D(100, 0))
    wire = Wire('OH AL 2/0 A')
    connector = ElectricalConnector('Connector_1', geo, [wire])

    new_connector = connector.duplicate()
    new_connector.move(Vector3D(100, 0))
    assert new_connector.geometry.p1 == Point2D(100, 0)

    new_connector = connector.duplicate()
    new_connector.rotate_xy(90, Point3D())
    assert new_connector.geometry.p2.y == pytest.approx(100, rel=1e-3)

    new_connector = connector.duplicate()
    new_connector.reflect(Plane(n=Vector3D(1, 0)))
    assert new_connector.geometry.p2.x == pytest.approx(-100, rel=1e-3)

    new_connector = connector.duplicate()
    new_connector.scale(0.5)
    assert new_connector.geometry.p2.x == pytest.approx(50, rel=1e-3)
def test_join_segments():
    """Test the join_segments method."""
    pts = (Point2D(0, 0), Point2D(2, 0), Point2D(2, 2), Point2D(0, 2))
    l_segs = (LineSegment2D.from_end_points(pts[0], pts[1]),
              LineSegment2D.from_end_points(pts[1], pts[2]),
              LineSegment2D.from_end_points(pts[2], pts[3]),
              LineSegment2D.from_end_points(pts[3], pts[0]))
    p_lines = Polyline2D.join_segments(l_segs, 0.01)
    assert len(p_lines) == 1
    assert isinstance(p_lines[0], Polyline2D)
    assert len(p_lines[0]) == 5
    assert p_lines[0].is_closed(0.01)

    l_segs = (LineSegment2D.from_end_points(pts[0], pts[1]),
              LineSegment2D.from_end_points(pts[2], pts[3]),
              LineSegment2D.from_end_points(pts[1], pts[2]),
              LineSegment2D.from_end_points(pts[3], pts[0]))
    p_lines = Polyline2D.join_segments(l_segs, 0.01)
    assert len(p_lines) == 1
    assert isinstance(p_lines[0], Polyline2D)
    assert len(p_lines[0]) == 5
    assert p_lines[0].is_closed(0.01)

    l_segs = (LineSegment2D.from_end_points(pts[0], pts[1]),
              LineSegment2D.from_end_points(pts[1], pts[2]),
              LineSegment2D.from_end_points(pts[0], pts[3]),
              LineSegment2D.from_end_points(pts[3], pts[2]))
    p_lines = Polyline2D.join_segments(l_segs, 0.01)
    assert len(p_lines) == 1
    assert isinstance(p_lines[0], Polyline2D)
    assert len(p_lines[0]) == 5
    assert p_lines[0].is_closed(0.01)
Esempio n. 20
0
            if 'geometry' in geo and geo['geometry']['type'] in geo_types
        ]
        if not all_to_bldg:  # exclude anything with a Building key
            geo_data = [
                geo for geo in geo_data if 'type' not in geo['properties']
                or geo['properties']['type'] != 'Building'
            ]

        # convert all of the geoJSON data into Rhino geometry
        other_geo = []
        for geo_dat in geo_data:
            if geo_dat['geometry']['type'] == 'LineString':
                coords = lon_lat_to_polygon(geo_dat['geometry']['coordinates'],
                                            origin_lon_lat, convert_facs)
                pts = tuple(Point2D.from_array(pt) for pt in coords)
                line = LineSegment2D.from_end_points(pts[0], pts[1]) \
                    if len(pts) == 2 else Polyline2D(pts)
                if con_fac != 1:
                    line = line.scale(con_fac, pt)
                if len(pts) == 2:
                    other_geo.append(from_linesegment2d(line))
                else:
                    other_geo.append(from_polyline2d(line))
            else:  # is's a polygon
                coords = lon_lat_to_polygon(
                    geo_dat['geometry']['coordinates'][0], origin_lon_lat,
                    convert_facs)
                pts = tuple(Point2D.from_array(pt) for pt in coords)
                poly = Polyline2D(pts)
                if con_fac != 1:
                    poly = poly.scale(con_fac, pt)
Esempio n. 21
0
def to_linesegment2d(line):
    """Ladybug LineSegment2D from Rhino LineCurve."""
    return LineSegment2D.from_end_points(to_point2d(line.PointAtStart),
                                         to_point2d(line.PointAtEnd))
def test_join_segments_multiple_pline():
    """Test the join_segments method with multiple polylines."""
    pts = (Point2D(0, 0), Point2D(2, 0), Point2D(2, 2), Point2D(0, 2))
    extra_pts = (Point2D(3, 3), Point2D(4, 3), Point2D(4, 4), Point2D(3, 4))
    l_segs = (LineSegment2D.from_end_points(extra_pts[0], extra_pts[1]),
              LineSegment2D.from_end_points(pts[0], pts[1]),
              LineSegment2D.from_end_points(pts[1], pts[2]),
              LineSegment2D.from_end_points(pts[0], pts[3]),
              LineSegment2D.from_end_points(pts[3], pts[2]))
    p_lines = Polyline2D.join_segments(l_segs, 0.01)
    assert len(p_lines) == 2

    l_segs = (LineSegment2D.from_end_points(extra_pts[0], extra_pts[1]),
              LineSegment2D.from_end_points(pts[0], pts[1]),
              LineSegment2D.from_end_points(pts[1], pts[2]),
              LineSegment2D.from_end_points(pts[0], pts[3]),
              LineSegment2D.from_end_points(pts[3], pts[2]),
              LineSegment2D.from_end_points(extra_pts[2], extra_pts[3]),
              LineSegment2D.from_end_points(extra_pts[1], extra_pts[2]),
              LineSegment2D.from_end_points(extra_pts[0], extra_pts[3]))
    p_lines = Polyline2D.join_segments(l_segs, 0.01)
    assert len(p_lines) == 2
    for p_line in p_lines:
        assert isinstance(p_line, Polyline2D)
        assert len(p_line) == 5
        assert p_line.is_closed(0.01)