Example #1
0
    def _useful_polygon(self, ply_piece=None):
        # Internal function to get a polygon representing the section of a
        # ply piece that overlaps with the useful area of the cone (between s2
        # and s3). Additionally, return the points on s2 and s3 separately.
        if ply_piece is None:
            ply_piece = self.base_piece
        # Re-use cached value if possible, for performance
        if ply_piece in self._useful_polygon_cache:
            return self._useful_polygon_cache[ply_piece]

        P1, P2, P3, P4 = ply_piece.polygon.points()
        phi_nom = ply_piece.phi_nom
        L1 = Line2D.from_points(P1, P2)
        L3 = Line2D.from_points(P3, P4)
        points = []

        # Define a quick helper function that will be useful later
        def make_intersection(L, s):
            return L.intersection_circle_near(s,
                                              Point2D.from_polar(s, phi_nom))

        # Add the intersection with s2 near P1
        if P1.norm() > self.cg.s2:
            # P1 is inside the useful area, add it as well
            L4 = Line2D.from_points(P4, P1)
            points.append(make_intersection(L4, self.cg.s2))
            points.append(P1)
        else:
            # P1 is outside the useful area
            points.append(make_intersection(L1, self.cg.s2))

        # Add the intersection points with s3
        pts_on_s3 = (make_intersection(L1, self.cg.s3),
                     make_intersection(L3, self.cg.s3))
        points.extend(pts_on_s3)

        # Add the intersection with s2 near P4
        if P4.norm() > self.cg.s2:
            # P4 is inside the useful area, add it as well
            points.append(P4)
            L4 = Line2D.from_points(P4, P1)
            points.append(make_intersection(L4, self.cg.s2))
        else:
            # P4 is outside the useful area
            points.append(make_intersection(L3, self.cg.s2))

        pts_on_s2 = (points[0], points[-1])
        retval = (Polygon2D(points), pts_on_s2, pts_on_s3)
        self._useful_polygon_cache[ply_piece] = retval
        return retval
Example #2
0
    def _useful_polygon(self, ply_piece=None):
        # Internal function to get a polygon representing the section of a
        # ply piece that overlaps with the useful area of the cone (between s2
        # and s3). Additionally, return the points on s2 and s3 separately.
        if ply_piece is None:
            ply_piece = self.base_piece
        # Re-use cached value if possible, for performance
        if ply_piece in self._useful_polygon_cache:
            return self._useful_polygon_cache[ply_piece]

        P1, P2, P3, P4 = ply_piece.polygon.points()
        phi_nom = ply_piece.phi_nom
        L1 = Line2D.from_points(P1, P2)
        L3 = Line2D.from_points(P3, P4)
        points = []

        # Define a quick helper function that will be useful later
        def make_intersection(L, s):
            return L.intersection_circle_near(s, Point2D.from_polar(s, phi_nom))

        # Add the intersection with s2 near P1
        if P1.norm() > self.cg.s2:
            # P1 is inside the useful area, add it as well
            L4 = Line2D.from_points(P4, P1)
            points.append(make_intersection(L4, self.cg.s2))
            points.append(P1)
        else:
            # P1 is outside the useful area
            points.append(make_intersection(L1, self.cg.s2))

        # Add the intersection points with s3
        pts_on_s3 = (make_intersection(L1, self.cg.s3),
                     make_intersection(L3, self.cg.s3))
        points.extend(pts_on_s3)

        # Add the intersection with s2 near P4
        if P4.norm() > self.cg.s2:
            # P4 is inside the useful area, add it as well
            points.append(P4)
            L4 = Line2D.from_points(P4, P1)
            points.append(make_intersection(L4, self.cg.s2))
        else:
            # P4 is outside the useful area
            points.append(make_intersection(L3, self.cg.s2))

        pts_on_s2 = (points[0], points[-1])
        retval = (Polygon2D(points), pts_on_s2, pts_on_s3)
        self._useful_polygon_cache[ply_piece] = retval
        return retval
Example #3
0
    def construct_single_ply_piece(self, fraction=1.0):
        """Construct a ply piece for shape A (trapezium)"""
        th_nom = np.radians(self.fiber_angle)
        # Step 1: Define origin line L0
        origin_point = Point2D(self.starting_position, 0.0)
        L0 = Line2D.from_point_angle(origin_point, th_nom )
        # Step 2: Define line L2, perpendicular to L0, tangent to circle s4
        tangent_point = Point2D.from_polar(self.cg.s4, th_nom)
        L2 = Line2D.from_point_angle(tangent_point, th_nom + np.pi/2)
        P0 = L0.intersection_line(L2)

        # Step 3: Position P2 and P3 based on max_width and eccentricity
        P2_dist = self.max_width * self.eccentricity
        P3_dist = self.max_width * (1 - self.eccentricity)
        P2 = P0 + Point2D.from_polar(P2_dist, L2.angle())
        P3 = P0 + Point2D.from_polar(P3_dist, L2.angle() + np.pi)

        # Step 4: Calculate a rough estimate of the spanned angle
        delta_phi_1 = (P2.angle() - P0.angle())
        delta_phi_2 = (P0.angle() - P3.angle())
        ip_L0_s2 = L0.intersection_circle_near(self.cg.s2, origin_point)
        ip_L0_s4 = L0.intersection_circle_near(self.cg.s4, origin_point)

        ratio = 0.0
        REQ_RATIO = 2.0
        # Step 5: Iterate until the ratio of spanned angles on s4 and s2 is (nearly) correct
        while abs(ratio - REQ_RATIO) > TOL:
            delta_phi_on_s2 = REQ_RATIO * (delta_phi_1 + delta_phi_2)
            ip_L1_s2 = ip_L0_s2.rotate(REQ_RATIO * delta_phi_1)
            ip_L3_s2 = ip_L0_s2.rotate(-REQ_RATIO * delta_phi_2)
            L1 = Line2D.from_points(ip_L1_s2, P2)
            L3 = Line2D.from_points(ip_L3_s2, P3)
            ip_L1_s4 = L1.intersection_circle_near(self.cg.s4, P0)
            ip_L3_s4 = L3.intersection_circle_near(self.cg.s4, P0)
            delta_phi_1 = ip_L1_s4.angle() - ip_L0_s4.angle()
            delta_phi_2 = ip_L0_s4.angle() - ip_L3_s4.angle()
            delta_phi_on_s4 = delta_phi_1 + delta_phi_2
            ratio = delta_phi_on_s2 / delta_phi_on_s4

        # Redefine P2 and P3 if needed (for rest pieces)
        if fraction != 1.0:
            ip_L1_s2 = ip_L1_s2.rotate((fraction - 1.0) * delta_phi_1)
            ip_L3_s2 = ip_L3_s2.rotate((1.0 - fraction) * delta_phi_2)
            # Apply an additional rotation to avoid having more than one overlap
            ip_L3_s2 = ip_L3_s2.rotate(delta_phi_1 + delta_phi_2)
            ip_L1_s4 = ip_L1_s4.rotate((fraction - 1.0) * delta_phi_1)
            ip_L3_s4 = ip_L3_s4.rotate((1.0 - fraction) * delta_phi_2)
            L1 = Line2D.from_points(ip_L1_s2, ip_L1_s4)
            L3 = Line2D.from_points(ip_L3_s2, ip_L3_s4)
            delta_phi_1 *= fraction
            delta_phi_2 *= fraction

        # Step 6: redefine P1 to P4 as the intersection points
        L4 = Line2D.from_point_angle(Point2D(0.0, 0.0), L2.angle())
        P1 = L1.intersection_line(L4)
        P2 = L2.intersection_line(L1)
        P3 = L3.intersection_line(L2)
        P4 = L4.intersection_line(L3)

        # Step 7: Return the final ply piece
        return PlyPiece(Polygon2D((P1, P2, P3, P4)), 0.0, -delta_phi_2, delta_phi_1)
Example #4
0
    def effective_area(self, ply_piece=None, max_angle_dev=2.0):
        """Get the effective area of a single ply piece. This is the area on
        useful section of the cone, where the deviation of the fiber angle
        is less than a given maximum.

        Parameters
        ----------
        ply_piece : :class:`PlyPiece`, optional
            Ply piece to get the effective area for. If not set, the base
            piece is used.
        max_angle_dev : float, optional
            Maximum deviation from the nominal fiber angle to consider
            the material 'effective'. In degrees.

        Returns
        -------
        out : tuple
            2-tuple, where ``out[0]`` is the effective surface area and
            ``out[1]`` is the corresponding polygon.

        Notes
        -----
        Note that the polygon has straight edges, while the calculation of
        the effective area takes into account that some edges of the effective
        area may be arc sections.

        """
        if ply_piece is None:
            ply_piece = self.base_piece
        poly, pts_on_s2, pts_on_s3 = self._useful_polygon(ply_piece)
        # Construct lines through those corner points of the polygon,
        # that are on s2/s3. They will be useful later
        line_s2 = Line2D.from_points(*pts_on_s2)
        line_s3 = Line2D.from_points(*pts_on_s3)

        # Lines to cut away the non-effective area
        cut_line_1 = Line2D.from_point_angle(Point2D(0., 0.),
            ply_piece.phi_nom - np.radians(max_angle_dev))
        cut_line_2 = Line2D.from_point_angle(Point2D(0., 0.),
            ply_piece.phi_nom + np.pi + np.radians(max_angle_dev))
        # Slice the polygon, with some corrections
        for cut_line in (cut_line_1, cut_line_2):
            outp = []
            for p in poly.slice_line(cut_line).points():
                # Polygon intersection can result in points that are not
                # exactly on circles s2/s3, while they should be. Correct that.
                if cut_line.distance_point(p) < TOL:
                    if line_s2.distance_point(p) < TOL:
                        p = cut_line.intersection_circle_near(self.cg.s2, p)
                    elif line_s3.distance_point(p) < TOL:
                        p = cut_line.intersection_circle_near(self.cg.s3, p)
                outp.append(p)
            poly = Polygon2D(outp)

        # Calculate area
        area = poly.area()
        # Correct polygon area for arc sections s2/s3, if needed
        pts_on_s2 = [p for p in poly.points() if abs(p.norm() - self.cg.s2) < TOL]
        if len(pts_on_s2) >= 2:
            angles = [p.angle() for p in pts_on_s2]
            area -= circle_segment_area(self.cg.s2, max(angles) - min(angles))
        pts_on_s3 = [p for p in poly.points() if abs(p.norm() - self.cg.s3) < TOL]
        if len(pts_on_s3) >= 2:
            angles = [p.angle() for p in pts_on_s3]
            area += circle_segment_area(self.cg.s3, max(angles) - min(angles))

        return area, poly
Example #5
0
    def construct_single_ply_piece(self, fraction=1.0):
        """Construct a ply piece for shape A (trapezium)"""
        th_nom = np.radians(self.fiber_angle)
        # Step 1: Define origin line L0
        origin_point = Point2D(self.starting_position, 0.0)
        L0 = Line2D.from_point_angle(origin_point, th_nom)
        # Step 2: Define line L2, perpendicular to L0, tangent to circle s4
        tangent_point = Point2D.from_polar(self.cg.s4, th_nom)
        L2 = Line2D.from_point_angle(tangent_point, th_nom + np.pi / 2)
        P0 = L0.intersection_line(L2)

        # Step 3: Position P2 and P3 based on max_width and eccentricity
        P2_dist = self.max_width * self.eccentricity
        P3_dist = self.max_width * (1 - self.eccentricity)
        P2 = P0 + Point2D.from_polar(P2_dist, L2.angle())
        P3 = P0 + Point2D.from_polar(P3_dist, L2.angle() + np.pi)

        # Step 4: Calculate a rough estimate of the spanned angle
        delta_phi_1 = (P2.angle() - P0.angle())
        delta_phi_2 = (P0.angle() - P3.angle())
        ip_L0_s2 = L0.intersection_circle_near(self.cg.s2, origin_point)
        ip_L0_s4 = L0.intersection_circle_near(self.cg.s4, origin_point)

        ratio = 0.0
        REQ_RATIO = 2.0
        # Step 5: Iterate until the ratio of spanned angles on s4 and s2 is (nearly) correct
        while abs(ratio - REQ_RATIO) > TOL:
            delta_phi_on_s2 = REQ_RATIO * (delta_phi_1 + delta_phi_2)
            ip_L1_s2 = ip_L0_s2.rotate(REQ_RATIO * delta_phi_1)
            ip_L3_s2 = ip_L0_s2.rotate(-REQ_RATIO * delta_phi_2)
            L1 = Line2D.from_points(ip_L1_s2, P2)
            L3 = Line2D.from_points(ip_L3_s2, P3)
            ip_L1_s4 = L1.intersection_circle_near(self.cg.s4, P0)
            ip_L3_s4 = L3.intersection_circle_near(self.cg.s4, P0)
            delta_phi_1 = ip_L1_s4.angle() - ip_L0_s4.angle()
            delta_phi_2 = ip_L0_s4.angle() - ip_L3_s4.angle()
            delta_phi_on_s4 = delta_phi_1 + delta_phi_2
            ratio = delta_phi_on_s2 / delta_phi_on_s4

        # Redefine P2 and P3 if needed (for rest pieces)
        if fraction != 1.0:
            ip_L1_s2 = ip_L1_s2.rotate((fraction - 1.0) * delta_phi_1)
            ip_L3_s2 = ip_L3_s2.rotate((1.0 - fraction) * delta_phi_2)
            # Apply an additional rotation to avoid having more than one overlap
            ip_L3_s2 = ip_L3_s2.rotate(delta_phi_1 + delta_phi_2)
            ip_L1_s4 = ip_L1_s4.rotate((fraction - 1.0) * delta_phi_1)
            ip_L3_s4 = ip_L3_s4.rotate((1.0 - fraction) * delta_phi_2)
            L1 = Line2D.from_points(ip_L1_s2, ip_L1_s4)
            L3 = Line2D.from_points(ip_L3_s2, ip_L3_s4)
            delta_phi_1 *= fraction
            delta_phi_2 *= fraction

        # Step 6: redefine P1 to P4 as the intersection points
        L4 = Line2D.from_point_angle(Point2D(0.0, 0.0), L2.angle())
        P1 = L1.intersection_line(L4)
        P2 = L2.intersection_line(L1)
        P3 = L3.intersection_line(L2)
        P4 = L4.intersection_line(L3)

        # Step 7: Return the final ply piece
        return PlyPiece(Polygon2D((P1, P2, P3, P4)), 0.0, -delta_phi_2,
                        delta_phi_1)
Example #6
0
    def effective_area(self, ply_piece=None, max_angle_dev=2.0):
        """Get the effective area of a single ply piece. This is the area on
        useful section of the cone, where the deviation of the fiber angle
        is less than a given maximum.

        Parameters
        ----------
        ply_piece : :class:`PlyPiece`, optional
            Ply piece to get the effective area for. If not set, the base
            piece is used.
        max_angle_dev : float, optional
            Maximum deviation from the nominal fiber angle to consider
            the material 'effective'. In degrees.

        Returns
        -------
        out : tuple
            2-tuple, where ``out[0]`` is the effective surface area and
            ``out[1]`` is the corresponding polygon.

        Notes
        -----
        Note that the polygon has straight edges, while the calculation of
        the effective area takes into account that some edges of the effective
        area may be arc sections.

        """
        if ply_piece is None:
            ply_piece = self.base_piece
        poly, pts_on_s2, pts_on_s3 = self._useful_polygon(ply_piece)
        # Construct lines through those corner points of the polygon,
        # that are on s2/s3. They will be useful later
        line_s2 = Line2D.from_points(*pts_on_s2)
        line_s3 = Line2D.from_points(*pts_on_s3)

        # Lines to cut away the non-effective area
        cut_line_1 = Line2D.from_point_angle(
            Point2D(0., 0.), ply_piece.phi_nom - np.radians(max_angle_dev))
        cut_line_2 = Line2D.from_point_angle(
            Point2D(0., 0.),
            ply_piece.phi_nom + np.pi + np.radians(max_angle_dev))
        # Slice the polygon, with some corrections
        for cut_line in (cut_line_1, cut_line_2):
            outp = []
            for p in poly.slice_line(cut_line).points():
                # Polygon intersection can result in points that are not
                # exactly on circles s2/s3, while they should be. Correct that.
                if cut_line.distance_point(p) < TOL:
                    if line_s2.distance_point(p) < TOL:
                        p = cut_line.intersection_circle_near(self.cg.s2, p)
                    elif line_s3.distance_point(p) < TOL:
                        p = cut_line.intersection_circle_near(self.cg.s3, p)
                outp.append(p)
            poly = Polygon2D(outp)

        # Calculate area
        area = poly.area()
        # Correct polygon area for arc sections s2/s3, if needed
        pts_on_s2 = [
            p for p in poly.points() if abs(p.norm() - self.cg.s2) < TOL
        ]
        if len(pts_on_s2) >= 2:
            angles = [p.angle() for p in pts_on_s2]
            area -= circle_segment_area(self.cg.s2, max(angles) - min(angles))
        pts_on_s3 = [
            p for p in poly.points() if abs(p.norm() - self.cg.s3) < TOL
        ]
        if len(pts_on_s3) >= 2:
            angles = [p.angle() for p in pts_on_s3]
            area += circle_segment_area(self.cg.s3, max(angles) - min(angles))

        return area, poly