Пример #1
0
def test_basic_arc2():
    origin = (0, 0, 0)
    xdir = (1, 0, 0)
    normal = (0, -1, 0)

    p1 = np.array([-150, 100])
    p2 = np.array([-74, 81])
    p3 = np.array([-20, 0])
    radius = 40

    v1 = unit_vector(p2 - p1)
    v2 = unit_vector(p2 - p3)

    alpha = angle_between(v1, v2)
    s = radius / np.sin(alpha / 2)

    dir_eval = np.cross(v1, v2)

    if dir_eval < 0:
        theta = -alpha / 2
    else:
        theta = alpha / 2

    A = p2 - v1 * s

    center = linear_2dtransform_rotate(p2, A, np.rad2deg(theta))
    start = intersect_line_circle((p1, p2), center, radius)
    end = intersect_line_circle((p3, p2), center, radius)

    vc1 = np.array([start[0], start[1], 0.0]) - np.array([center[0], center[1], 0.0])
    vc2 = np.array([end[0], end[1], 0.0]) - np.array([center[0], center[1], 0.0])

    arbp = angle_between(vc1, vc2)

    if dir_eval < 0:
        gamma = arbp / 2
    else:
        gamma = -arbp / 2
    midp = linear_2dtransform_rotate(center, start, np.rad2deg(gamma))
    glob_c = local_2_global_points([center], origin, xdir, normal)[0]
    glob_s = local_2_global_points([start], origin, xdir, normal)[0]
    glob_e = local_2_global_points([end], origin, xdir, normal)[0]
    glob_midp = local_2_global_points([midp], origin, xdir, normal)[0]

    res_center = (-98.7039754, 0.0, 45.94493759)
    res_start = (-89.00255040102925, 0, 84.75063760025732)
    res_end = (-65.4219636289688, 0, 68.1329454434532)
    res_midp = (-75.66203793182973, 0, 78.64156001325857)

    for r, e in zip(res_start, glob_s):
        assert roundoff(r, 5) == roundoff(e, 5)

    for r, e in zip(res_end, glob_e):
        assert roundoff(r, 4) == roundoff(e, 4)

    for r, e in zip(res_midp, glob_midp):
        assert roundoff(r, 4) == roundoff(e, 4)

    for r, e in zip(res_center, glob_c):
        assert roundoff(r, 4) == roundoff(e, 4)
Пример #2
0
    def extrusion_area(self):
        from ada.core.vector_utils import calc_yvec, intersect_calc, is_parallel

        area_points = []
        vpo = [np.array(p) for p in self.points]
        p2 = None
        yvec = None
        prev_xvec = None
        prev_yvec = None
        zvec = np.array([0, 0, 1])

        # Inner line
        for p1, p2 in zip(vpo[:-1], vpo[1:]):
            xvec = p2 - p1
            yvec = unit_vector(calc_yvec(xvec, zvec))
            new_point = p1 + yvec * (self._thickness / 2) + yvec * self.offset
            if prev_xvec is not None:
                if is_parallel(xvec, prev_xvec) is False:
                    prev_p = area_points[-1]
                    # next_point = p2 + yvec * (self._thickness / 2) + yvec * self.offset
                    # c_p = prev_yvec * (self._thickness / 2) + prev_yvec * self.offset
                    AB = prev_xvec
                    CD = xvec
                    s, t = intersect_calc(prev_p, new_point, AB, CD)
                    sAB = prev_p + s * AB
                    new_point = sAB
            area_points.append(new_point)
            prev_xvec = xvec
            prev_yvec = yvec

        # Add last point
        area_points.append((p2 + yvec * (self._thickness / 2) + yvec * self.offset))
        area_points.append((p2 - yvec * (self._thickness / 2) + yvec * self.offset))

        reverse_points = []
        # Outer line
        prev_xvec = None
        prev_yvec = None
        for p1, p2 in zip(vpo[:-1], vpo[1:]):
            xvec = p2 - p1
            yvec = unit_vector(calc_yvec(xvec, zvec))
            new_point = p1 - yvec * (self._thickness / 2) + yvec * self.offset
            if prev_xvec is not None:
                if is_parallel(xvec, prev_xvec) is False:
                    prev_p = reverse_points[-1]
                    c_p = prev_yvec * (self._thickness / 2) - prev_yvec * self.offset
                    new_point -= c_p
            reverse_points.append(new_point)
            prev_xvec = xvec
            prev_yvec = yvec

        reverse_points.reverse()
        area_points += reverse_points

        new_points = []
        for p in area_points:
            new_points.append(tuple([float(c) for c in p]))

        return new_points
Пример #3
0
    def get_segment_props(self, wall_segment):
        """

        :param wall_segment:
        :return:
        """
        if wall_segment > len(self._segments):
            raise ValueError(f"Wall segment id should be equal or less than {len(self._segments)}")

        p1, p2 = self._segments[wall_segment]
        xvec = unit_vector(np.array(p2) - np.array(p1))
        zvec = np.array([0, 0, 1])
        yvec = unit_vector(np.cross(zvec, xvec))

        return xvec, yvec, zvec
Пример #4
0
def generate_ifc_cylinder_geom(shape: PrimCyl, f):
    """Create IfcExtrudedAreaSolid from primitive PrimCyl"""
    p1 = shape.p1
    p2 = shape.p2
    r = shape.r

    vec = np.array(p2) - np.array(p1)
    uvec = unit_vector(vec)
    vecdir = to_real(uvec)

    cr_dir = np.array([0, 0, 1])

    if vector_length(abs(uvec) - abs(cr_dir)) == 0.0:
        cr_dir = np.array([1, 0, 0])

    perp_dir = np.cross(uvec, cr_dir)

    if vector_length(perp_dir) == 0.0:
        raise ValueError("Perpendicular dir cannot be zero")

    create_ifc_placement(f, to_real(p1), vecdir, to_real(perp_dir))

    opening_axis_placement = create_ifc_placement(f, to_real(p1), vecdir,
                                                  to_real(perp_dir))

    depth = vector_length(vec)
    profile = f.createIfcCircleProfileDef("AREA", shape.name, None, r)
    return create_ifcextrudedareasolid(f, profile, opening_axis_placement, Z,
                                       depth)
Пример #5
0
    def local_x(self) -> np.ndarray:
        if self._local_x is not None:
            return self._local_x

        el = self.elset.members[0]

        if self.type == ElemType.LINE:
            vec = unit_vector(el.nodes[-1].p - el.nodes[0].p)
        elif self.type == ElemType.SHELL:
            vec = unit_vector(el.nodes[1].p - el.nodes[0].p)
        else:
            from ada.core.constants import X

            vec = np.array(X, dtype=float)

        self._local_x = np.round(np.where(abs(vec) == 0, 0, vec), 8)

        return self._local_x
Пример #6
0
def add_hinge_prop_to_elem(elem: Elem, members, hinges_global, xvec,
                           yvec) -> None:
    """Add hinge property to element from sesam FEM file"""
    from ada.fem.elements import Hinge, HingeProp

    if len(elem.nodes) > 2:
        raise ValueError(
            "This algorithm was not designed for more than 2 noded elements")

    for i, x in enumerate(members):
        if i >= len(elem.nodes):
            break
        if x == 0:
            continue
        if x not in hinges_global.keys():
            raise ValueError("fixno not found!")
        opt, trano, a1, a2, a3, a4, a5, a6 = hinges_global[x]
        n = elem.nodes[i]
        if trano > 0:
            csys = None
        else:
            csys = Csys(
                f"el{elem.id}_hinge{i + 1}_csys",
                coords=([
                    unit_vector(xvec) + n.p,
                    unit_vector(yvec) + n.p, n.p
                ]),
                parent=elem.parent,
            )
        dofs_origin = [1, 2, 3, 4, 5, 6]
        dofs = [
            int(x) for x, i in zip(dofs_origin, (a1, a2, a3, a4, a5, a6))
            if int(i) != 0
        ]
        end = Hinge(retained_dofs=dofs, csys=csys, fem_node=n)
        if i == 0:
            elem.hinge_prop = HingeProp(end1=end)
        else:
            elem.hinge_prop = HingeProp(end2=end)
Пример #7
0
 def xvec_e(self) -> np.ndarray:
     """Local X-vector (including eccentricities)"""
     if self.e1 is not None:
         p1 = np.array([
             float(x) + float(self.e1[i]) for i, x in enumerate(self.n1.p)
         ])
     else:
         p1 = self.n1.p
     if self.e2 is not None:
         p2 = np.array([
             float(x) + float(self.e2[i]) for i, x in enumerate(self.n2.p)
         ])
     else:
         p2 = self.n2.p
     return unit_vector(p2 - p1)
Пример #8
0
        def modify_beam(bm: Beam, new_nodes) -> Beam:
            n1, n2 = new_nodes

            n1_2_n2_vector = unit_vector(n2.p - n1.p)
            beam_vector = bm.xvec.round(decimals=Settings.precision)

            if is_parallel(n1_2_n2_vector, bm.xvec) and not is_null_vector(
                    n1_2_n2_vector, bm.xvec):
                n1, n2 = n2, n1
            elif not is_parallel(n1_2_n2_vector, bm.xvec):
                raise ValueError(
                    f"Unit vector error. Beam.xvec: {beam_vector}, nodes unit_vec: {-1 * n1_2_n2_vector}"
                )

            bm.n1, bm.n2 = n1, n2
            return bm
Пример #9
0
def read_line_section(elem: Elem, fem: FEM, mat: Material, geono, d, lcsysd,
                      hinges_global, eccentricities):
    transno = str_to_int(d["transno"])
    sec = fem.parent.sections.get_by_id(geono)
    n1, n2 = elem.nodes
    v = n2.p - n1.p
    if vector_length(v) == 0.0:
        xvec = [1, 0, 0]
    else:
        xvec = unit_vector(v)
    zvec = lcsysd[transno]
    crossed = np.cross(zvec, xvec)
    ma = max(abs(crossed))
    yvec = tuple([roundoff(x / ma, 3) for x in crossed])

    fix_data = str_to_int(d["fixno"])
    ecc_data = str_to_int(d["eccno"])

    members = None
    if d["members"] is not None:
        members = [
            str_to_int(x) for x in d["members"].replace("\n", " ").split()
        ]

    if fix_data == -1:
        add_hinge_prop_to_elem(elem, members, hinges_global, xvec, yvec)

    if ecc_data == -1:
        add_ecc_to_elem(elem, members, eccentricities, fix_data)

    fem_set = FemSet(sec.name, [elem],
                     "elset",
                     metadata=dict(internal=True),
                     parent=fem)
    fem.sets.add(fem_set, append_suffix_on_exist=True)
    fem_sec = FemSection(
        sec_id=geono,
        name=sec.name,
        sec_type=ElemType.LINE,
        elset=fem_set,
        section=sec,
        local_z=zvec,
        local_y=yvec,
        material=mat,
        parent=fem,
    )
    return fem_sec
Пример #10
0
    def local_z(self) -> np.ndarray:
        """Local Z describes the up vector of the cross section"""
        if self._local_z is not None:
            return self._local_z

        if self.type == ElemType.LINE:
            n1, n2 = self.elset.members[0].nodes[0], self.elset.members[0].nodes[-1]
            v = n2.p - n1.p
            if vector_length(v) == 0.0:
                logging.error(f"Element {self.elset.members[0].id} has zero length")
                xvec = [1, 0, 0]
            else:
                xvec = unit_vector(v)
            self._local_z = calc_zvec(xvec, self.local_y)
        elif self.type == ElemType.SHELL:
            self._local_z = normal_to_points_in_plane([n.p for n in self.elset.members[0].nodes])
        else:
            from ada.core.constants import Z

            self._local_z = np.array(Z, dtype=float)

        return self._local_z
Пример #11
0
    def _init_orientation(self, angle=None, up=None) -> None:
        xvec = unit_vector(self.n2.p - self.n1.p)
        tol = 1e-3
        zvec = calc_zvec(xvec)
        gup = np.array(zvec)

        if up is None:
            if angle != 0.0 and angle is not None:
                from pyquaternion import Quaternion

                my_quaternion = Quaternion(axis=xvec, degrees=angle)
                rot_mat = my_quaternion.rotation_matrix
                up = np.array([
                    roundoff(x) if abs(x) != 0.0 else 0.0
                    for x in np.matmul(gup, np.transpose(rot_mat))
                ])
            else:
                up = np.array(
                    [roundoff(x) if abs(x) != 0.0 else 0.0 for x in gup])
            yvec = calc_yvec(xvec, up)
        else:
            if (len(up) == 3) is False:
                raise ValueError("Up vector must be length 3")
            if vector_length(xvec - up) < tol:
                raise ValueError(
                    "The assigned up vector is too close to your beam direction"
                )
            yvec = calc_yvec(xvec, up)
            # TODO: Fix improper calculation of angle (e.g. xvec = [1,0,0] and up = [0,1,0] should be 270?
            rad = angle_between(up, yvec)
            angle = np.rad2deg(rad)
            up = np.array(up)

        # lup = np.cross(xvec, yvec)
        self._xvec = xvec
        self._yvec = np.array([roundoff(x) for x in yvec])
        self._up = up
        self._angle = angle
Пример #12
0
    def local_y(self) -> np.ndarray:
        """Local y describes the cross vector of the beams X and Z axis"""
        if self._local_y is not None:
            return self._local_y

        if self.type == ElemType.LINE:
            el = self.elset.members[0]
            n1, n2 = el.nodes[0], el.nodes[-1]
            v = n2.p - n1.p
            if vector_length(v) == 0.0:
                raise ValueError(f'Element "{el}" has no length. UNable to calculate y-vector')

            xvec = unit_vector(v)

            # See https://en.wikipedia.org/wiki/Cross_product#Coordinate_notation for order of cross product
            vec = calc_yvec(xvec, self.local_z)
        elif self.type == ElemType.SHELL:
            vec = calc_yvec(self.local_x, self.local_z)
        else:
            vec = calc_yvec(self.local_x, self.local_z)

        self._local_y = np.where(abs(vec) == 0, 0, vec)

        return self._local_y
Пример #13
0
def sweep_pipe(edge, xvec, r, wt, geom_repr=ElemType.SOLID):
    if geom_repr not in [ElemType.SOLID, ElemType.SHELL]:
        raise ValueError("Sweeping pipe must be either 'solid' or 'shell'")

    t = TopologyExplorer(edge)
    points = [v for v in t.vertices()]
    point = BRep_Tool_Pnt(points[0])
    # x, y, z = point.X(), point.Y(), point.Z()
    direction = gp_Dir(*unit_vector(xvec).astype(float).tolist())

    # pipe
    makeWire = BRepBuilderAPI_MakeWire()
    makeWire.Add(edge)
    makeWire.Build()
    wire = makeWire.Wire()
    try:
        if geom_repr == ElemType.SOLID:
            i = make_circular_sec_face(point, direction, r - wt)
            elbow_i = BRepOffsetAPI_MakePipe(wire, i).Shape()
            o = make_circular_sec_face(point, direction, r)
            elbow_o = BRepOffsetAPI_MakePipe(wire, o).Shape()
        else:
            elbow_i = None
            o = make_circular_sec_wire(point, direction, r)
            elbow_o = BRepOffsetAPI_MakePipe(wire, o).Shape()
    except RuntimeError as e:
        logging.error(f'Pipe sweep failed: "{e}"')
        return wire
    if geom_repr == ElemType.SOLID:
        boolean_result = BRepAlgoAPI_Cut(elbow_o, elbow_i).Shape()
        if boolean_result.IsNull():
            logging.debug("Boolean returns None")
    else:
        boolean_result = elbow_o

    return boolean_result
Пример #14
0
    def __init__(
        self,
        points2d=None,
        origin=None,
        normal=None,
        xdir=None,
        points3d=None,
        flip_normal=False,
        tol=1e-3,
        is_closed=True,
        parent=None,
        debug=False,
    ):
        self._tol = tol
        self._parent = parent
        self._is_closed = is_closed
        self._debug = debug

        from ada.core.vector_utils import (
            is_clockwise,
            normal_to_points_in_plane,
            unit_vector,
        )

        if points2d is None and points3d is None:
            raise ValueError("Either points2d or points3d must be set")

        if points2d is not None:
            self._placement = Placement(origin, xdir=xdir, zdir=normal)
            points3d = self._from_2d_points(points2d)
        else:
            normal = normal_to_points_in_plane([np.array(x[:3]) for x in points3d])
            p1 = np.array(points3d[0][:3]).astype(float)
            p2 = np.array(points3d[1][:3]).astype(float)
            origin = p1
            xdir = unit_vector(p2 - p1)
            self._placement = Placement(origin, xdir=xdir, zdir=normal)
            points2d = self._from_3d_points(points3d)

        if is_clockwise(points2d) is False:
            if is_closed:
                points2d = [points2d[0]] + [p for p in reversed(points2d[1:])]
                points3d = [points3d[0]] + [p for p in reversed(points3d[1:])]
            else:
                points2d = [p for p in reversed(points2d)]
                points3d = [p for p in reversed(points3d)]

        self._points3d = points3d
        self._points2d = points2d

        if flip_normal:
            self.placement.zdir *= -1

        self._seg_list = None
        self._seg_index = None
        self._face = None
        self._wire = None
        self._edges = None
        self._seg_global_points = None
        self._nodes = None
        self._ifc_elem = None
        self._local2d_to_polycurve(points2d, tol)
Пример #15
0
def make_cylinder_from_points(p1, p2, r, t=None):
    vec = unit_vector(np.array(p2) - np.array(p1))
    l = vector_length(np.array(p2) - np.array(p1))
    return make_cylinder(p1, vec, l, r, t)
Пример #16
0
    def _build_pipe(self):
        from ada.core.curve_utils import make_arc_segment

        segs = []
        for p1, p2 in zip(self.points[:-1], self.points[1:]):
            if vector_length(p2.p - p1.p) == 0.0:
                logging.info("skipping zero length segment")
                continue
            segs.append([p1, p2])
        segments = segs

        seg_names = Counter(prefix=self.name + "_")

        # Make elbows and adjust segments
        props = dict(section=self.section,
                     material=self.material,
                     parent=self,
                     units=self.units)
        angle_tol = 1e-1
        len_tol = _Settings.point_tol if self.units == "m" else _Settings.point_tol * 1000
        for i, (seg1, seg2) in enumerate(zip(segments[:-1], segments[1:])):
            p11, p12 = seg1
            p21, p22 = seg2
            vlen1 = vector_length(seg1[1].p - seg1[0].p)
            vlen2 = vector_length(seg2[1].p - seg2[0].p)

            if vlen1 < len_tol or vlen2 == len_tol:
                logging.error(
                    f'Segment Length is below point tolerance for unit "{self.units}". Skipping'
                )
                continue

            xvec1 = unit_vector(p12.p - p11.p)
            xvec2 = unit_vector(p22.p - p21.p)
            a = angle_between(xvec1, xvec2)
            res = True if abs(abs(a) - abs(np.pi)) < angle_tol or abs(
                abs(a) - 0.0) < angle_tol else False

            if res is True:
                self._segments.append(
                    PipeSegStraight(next(seg_names), p11, p12, **props))
            else:
                if p12 != p21:
                    logging.error("No shared point found")

                if i != 0 and len(self._segments) > 0:
                    pseg = self._segments[-1]
                    prev_p = (pseg.p1.p, pseg.p2.p)
                else:
                    prev_p = (p11.p, p12.p)
                try:
                    seg1, arc, seg2 = make_arc_segment(
                        prev_p[0], prev_p[1], p22.p,
                        self.pipe_bend_radius * 0.99)
                except ValueError as e:
                    logging.error(
                        f"Error: {e}"
                    )  # , traceback: "{traceback.format_exc()}"')
                    continue
                except RuntimeError as e:
                    logging.error(
                        f"Error: {e}"
                    )  # , traceback: "{traceback.format_exc()}"')
                    continue

                if i == 0 or len(self._segments) == 0:
                    self._segments.append(
                        PipeSegStraight(next(seg_names),
                                        Node(seg1.p1, units=self.units),
                                        Node(seg1.p2, units=self.units),
                                        **props))
                else:
                    if len(self._segments) == 0:
                        continue
                    pseg = self._segments[-1]
                    pseg.p2 = Node(seg1.p2, units=self.units)

                self._segments.append(
                    PipeSegElbow(
                        next(seg_names) + "_Elbow",
                        Node(seg1.p1, units=self.units),
                        Node(p21.p, units=self.units),
                        Node(seg2.p2, units=self.units),
                        arc.radius,
                        **props,
                        arc_seg=arc,
                    ))
                self._segments.append(
                    PipeSegStraight(next(seg_names),
                                    Node(seg2.p1, units=self.units),
                                    Node(seg2.p2, units=self.units), **props))