Example #1
0
 def test_ray2d_intersect_with_vertical_and_horizontal(self):
     ray1 = ConstructionRay((-10, 10), (10, 10))
     ray2 = ConstructionRay((5, 0), (5, 20))
     point = ray1.intersect(ray2)
     assert point.y == 10
     assert point.x == 5
     assert point.isclose(Vec3(5.0, 10.0), abs_tol=1e-4)
Example #2
0
    def test_ray2d_intersect(self):
        ray1 = ConstructionRay((10, 1), (20, 10))
        ray2 = ConstructionRay((17, -7), (-10, 3))

        point = ray1.intersect(ray2)
        assert point.isclose(Vec3(5.7434, -2.8309), abs_tol=1e-4)
        assert ray1.is_parallel(ray2) is False
Example #3
0
 def test_ray2d_angle(self):
     ray = ConstructionRay((10, 10), angle=HALF_PI)
     assert ray._is_vertical is True
     ray = ConstructionRay((10, 10), angle=0)
     assert ray._is_horizontal is True
     ray = ConstructionRay((10, 10), angle=math.pi / 4)
     assert math.isclose(ray._slope, 1.0)
Example #4
0
 def test_ray2d_intersect_with_vertical(self):
     ray1 = ConstructionRay((10, 1), (10, -7))
     ray2 = ConstructionRay((-10, 3), (17, -7))
     point = ray1.intersect(ray2)
     assert point.x == 10
     assert point.isclose(Vec3(10.0, -4.4074), abs_tol=1e-4)
     with pytest.raises(ArithmeticError):
         _ = ray1.yof(1)
Example #5
0
 def ray(v1, v2):
     if v1.isclose(v2):
         # vertices too close to define a ray, offset ray is parallel to segment:
         angle = (stations[segment].vertex -
                  stations[segment + 1].vertex).angle
         return ConstructionRay(v1, angle)
     else:
         return ConstructionRay(v1, v2)
Example #6
0
 def test_init_with_angle(self):
     point = (10, 10)
     ray = ConstructionRay(point, angle=0)
     ray_normal = ray.orthogonal(point)
     assert ray_normal._is_vertical is True
     ray = ConstructionRay(point, angle=-HALF_PI)
     assert ray._is_horizontal is False
     assert ray._is_vertical is True
def test_intersect_ray_pass():
    circle = ConstructionCircle((10.0, 10.0), 3)
    ray1_hor = ConstructionRay((10.0, 15.0), angle=0)
    ray2_hor = ConstructionRay((10.0, 5.0), angle=0)
    ray1_vert = ConstructionRay((5.0, 10.0), angle=HALF_PI)
    ray2_vert = ConstructionRay((15.0, 10.0), angle=-HALF_PI)
    ray3 = ConstructionRay((13.24, 14.95), angle=0.3992)
    assert len(circle.intersect_ray(ray1_hor)) == 0
    assert len(circle.intersect_ray(ray2_hor)) == 0
    assert len(circle.intersect_ray(ray1_vert)) == 0
    assert len(circle.intersect_ray(ray2_vert)) == 0
    assert len(circle.intersect_ray(ray3)) == 0
Example #8
0
    def test_two_close_horizontal_rays(self):
        p1 = (39340.75302672016, 32489.73349764998)
        p2 = (39037.75302672119, 32489.73349764978)
        p3 = (38490.75302672015, 32489.73349764997)

        ray1 = ConstructionRay(p1, p2)
        ray2 = ConstructionRay(p2, p3)
        assert ray1.is_horizontal is True
        assert ray2.is_horizontal is True
        assert ray1.is_parallel(ray2) is True
        assert (
            math.isclose(ray1.slope, ray2.slope) is False
        ), "Only slope testing is not sufficient"
Example #9
0
 def test_ray2d_parallel(self):
     ray1 = ConstructionRay((17, -8), (-10, 2))
     ray2 = ConstructionRay((-10, 3), (17, -7))
     ray3 = ConstructionRay((-10, 4), (17, -6))
     assert ray2.is_parallel(ray3) is True
     assert ray1.is_parallel(ray3) is True
     with pytest.raises(ParallelRaysError):
         _ = ray2.intersect(ray3)
Example #10
0
 def intersect(ray1: ConstructionRay, ray2: ConstructionRay,
               default: Vec2) -> Vec2:
     """ Intersect two rays but take parallel rays into account. """
     try:
         v = ray1.intersect(ray2)
     except ParallelRaysError:
         v = default
     return v
 def test_diagonal_ray(self, circle):
     ray_slope = ConstructionRay((5, 5), (16, 12))
     cross_points = circle.intersect_ray(ray_slope)
     assert len(cross_points) == 2
     p1, p2 = cross_points
     if p1[0] > p2[0]:
         p1, p2 = p2, p1
     assert p1.isclose((8.64840, 7.3217), abs_tol=1e-4)
     assert p2.isclose((12.9986, 10.0900), abs_tol=1e-4)
 def test_vertical_ray(self, circle):
     ray_vert = ConstructionRay((8.5, 10.0), angle=HALF_PI)
     cross_points = circle.intersect_ray(ray_vert)
     assert len(cross_points) == 2
     p1, p2 = cross_points
     if p1[1] > p2[1]:
         p1, p2 = p2, p1
     assert p1.isclose((8.5, 7.4019), abs_tol=1e-4)
     assert p2.isclose((8.5, 12.5981), abs_tol=1e-4)
 def test_horizontal_ray(self, circle):
     ray_hor = ConstructionRay((10, 8.5), angle=0.0)
     cross_points = circle.intersect_ray(ray_hor)
     assert len(cross_points) == 2
     p1, p2 = cross_points
     if p1[0] > p2[0]:
         p1, p2 = p2, p1
     assert p1.isclose((7.4019, 8.5), abs_tol=1e-4)
     assert p2.isclose((12.5981, 8.5), abs_tol=1e-4)
Example #14
0
 def intersect(ray1: ConstructionRay, ray2: ConstructionRay,
               default: Vec2) -> Vec2:
     """Intersect two rays but take parallel rays into account."""
     # check for nearly parallel rays pi/100 ~1.8 degrees
     if ray1.direction.angle_between(ray2.direction) < 0.031415:
         return default
     try:
         return ray1.intersect(ray2)
     except ParallelRaysError:
         return default
 def test_horizontal_ray_through_mid_point(self, circle):
     ray_hor = ConstructionRay((10, 10), angle=0)
     cross_points = circle.intersect_ray(ray_hor)
     assert len(cross_points) == 2
     p1, p2 = cross_points
     if p1[0] > p2[0]:
         p1, p2 = p2, p1
     # print (p1[0], p1[1], p2[0], p2[1])
     assert p1.isclose((7, 10), abs_tol=1e-5)
     assert p2.isclose((13, 10), abs_tol=1e-5)
 def test_vertical_ray_through_mid_point(self, circle):
     ray_vert = ConstructionRay((10, 10), angle=HALF_PI)
     cross_points = circle.intersect_ray(ray_vert)
     assert len(cross_points) == 2
     p1, p2 = cross_points
     if p1[1] > p2[1]:
         p1, p2 = p2, p1
     # print (p1[0], p1[1], p2[0], p2[1])
     assert p1.isclose((10, 7), abs_tol=1e-5)
     assert p2.isclose((10, 13), abs_tol=1e-5)
 def test_diagonal_ray_through_mid_point(self, circle):
     ray_slope = ConstructionRay((10, 10), angle=HALF_PI / 2)
     cross_points = circle.intersect_ray(ray_slope)
     assert len(cross_points) == 2
     p1, p2 = cross_points
     if p1[0] > p2[0]:
         p1, p2 = p2, p1
     # print (p1[0], p1[1], p2[0], p2[1])
     assert p1.isclose((7.8787, 7.8787), abs_tol=1e-4)
     assert p2.isclose((12.1213, 12.1213), abs_tol=1e-4)
Example #18
0
 def _setup(self) -> None:
     """
     Calc setup values and determines the point order of the dimension line points.
     """
     self.measure_points = [Vec3(point) for point in self.measure_points]
     dimlineray = ConstructionRay(self.dimlinepos,
                                  angle=radians(self.angle))
     self.dimline_points = [
         self._get_point_on_dimline(point, dimlineray)
         for point in self.measure_points
     ]
     self.point_order = self._indices_of_sorted_points(self.dimline_points)
     self._build_vectors()
 def test_touch(testnum, x, y, _angle, abs_tol=1e-6):
     result = True
     ray = ConstructionRay((x, y), angle=_angle)
     points = circle.intersect_ray(ray, abs_tol=abs_tol)
     if len(points) != 1:
         result = False
     else:
         point = points[0]
         # print ("{0}: x= {1:.{places}f} y= {2:.{places}f} : x'= {3:.{places}f} y' = {4:.{places}f}".format(testnum, x, y, point[0], point[1], places=places))
         if not isclose(point[0], x, abs_tol=abs_tol):
             result = False
         if not isclose(point[1], y, abs_tol=abs_tol):
             result = False
     return result
Example #20
0
 def test_bisectrix(self):
     ray1 = ConstructionRay((10, 10), angle=math.pi / 3)
     ray2 = ConstructionRay((3, -5), angle=math.pi / 2)
     ray3 = ConstructionRay((1, 1), angle=math.pi / 3)
     a = ray1.bisectrix(ray2)
     assert math.isclose(a._angle, 1.309, abs_tol=1e-4)
     assert math.isclose(a.yof(7), 12.80385, abs_tol=1e-4)
     with pytest.raises(ParallelRaysError):
         _ = ray1.bisectrix(ray3)
Example #21
0
def test_intersect_ray_intersect():
    circle = ConstructionCircle((10., 10.), 3)
    ray_vert = ConstructionRay((8.5, 10.), angle=HALF_PI)
    cross_points = circle.intersect_ray(ray_vert)
    assert len(cross_points) == 2
    p1, p2 = cross_points
    if p1[1] > p2[1]: p1, p2 = p2, p1
    assert is_close_points(p1, (8.5, 7.4019), abs_tol=1e-4) is True
    assert is_close_points(p2, (8.5, 12.5981), abs_tol=1e-4) is True

    ray_hor = ConstructionRay((10, 8.5), angle=0.)
    cross_points = circle.intersect_ray(ray_hor)
    assert len(cross_points) == 2
    p1, p2 = cross_points
    if p1[0] > p2[0]: p1, p2 = p2, p1
    assert is_close_points(p1, (7.4019, 8.5), abs_tol=1e-4) is True
    assert is_close_points(p2, (12.5981, 8.5), abs_tol=1e-4) is True

    ray_slope = ConstructionRay((5, 5), (16, 12))
    cross_points = circle.intersect_ray(ray_slope)
    assert len(cross_points) == 2
    p1, p2 = cross_points
    if p1[0] > p2[0]: p1, p2 = p2, p1
    assert is_close_points(p1, (8.64840, 7.3217), abs_tol=1e-4) is True
    assert is_close_points(p2, (12.9986, 10.0900), abs_tol=1e-4) is True

    # ray with slope through midpoint
    ray_slope = ConstructionRay((10, 10), angle=HALF_PI / 2)
    cross_points = circle.intersect_ray(ray_slope)
    assert len(cross_points) == 2
    p1, p2 = cross_points
    if p1[0] > p2[0]: p1, p2 = p2, p1
    # print (p1[0], p1[1], p2[0], p2[1])
    assert is_close_points(p1, (7.8787, 7.8787), abs_tol=1e-4) is True
    assert is_close_points(p2, (12.1213, 12.1213), abs_tol=1e-4) is True

    # horizontal ray through midpoint
    ray_hor = ConstructionRay((10, 10), angle=0)
    cross_points = circle.intersect_ray(ray_hor)
    assert len(cross_points) == 2
    p1, p2 = cross_points
    if p1[0] > p2[0]: p1, p2 = p2, p1
    # print (p1[0], p1[1], p2[0], p2[1])
    assert is_close_points(p1, (7, 10), abs_tol=1e-5) is True
    assert is_close_points(p2, (13, 10), abs_tol=1e-5) is True

    # vertical ray through midpoint
    ray_vert = ConstructionRay((10, 10), angle=HALF_PI)
    cross_points = circle.intersect_ray(ray_vert)
    assert len(cross_points) == 2
    p1, p2 = cross_points
    if p1[1] > p2[1]: p1, p2 = p2, p1
    # print (p1[0], p1[1], p2[0], p2[1])
    assert is_close_points(p1, (10, 7), abs_tol=1e-5) is True
    assert is_close_points(p2, (10, 13), abs_tol=1e-5) is True
Example #22
0
def center_of_3points_arc(point1: "Vertex", point2: "Vertex",
                          point3: "Vertex") -> Vec3:
    """
    Calc center point of 3 point arc. ConstructionCircle is defined by 3 points on the circle: point1, point2 and point3.
    """
    ray1 = ConstructionRay(point1, point2)
    ray2 = ConstructionRay(point1, point3)
    midpoint1 = lerp(point1, point2)
    midpoint2 = lerp(point1, point3)
    center_ray1 = ray1.orthogonal(midpoint1)
    center_ray2 = ray2.orthogonal(midpoint2)
    return center_ray1.intersect(center_ray2)
Example #23
0
 def _get_point_on_dimline(point: "Vertex",
                           dimray: ConstructionRay) -> Vec3:
     """get the measure target point projection on the dimension line"""
     return dimray.intersect(dimray.orthogonal(point))
Example #24
0
    def __init__(self,
                 dimension: 'Dimension',
                 ucs: 'UCS' = None,
                 override: 'DimStyleOverride' = None):
        super().__init__(dimension, ucs, override)
        if self.text_movement_rule == 0:
            # moves the dimension line with dimension text, this makes no sense for ezdxf (just set `base` argument)
            self.text_movement_rule = 2

        self.oblique_angle = self.dimension.get_dxf_attrib(
            'oblique_angle', 90)  # type: float
        self.dim_line_angle = self.dimension.get_dxf_attrib('angle',
                                                            0)  # type: float
        self.dim_line_angle_rad = math.radians(
            self.dim_line_angle)  # type: float
        self.ext_line_angle = self.dim_line_angle + self.oblique_angle  # type: float
        self.ext_line_angle_rad = math.radians(
            self.ext_line_angle)  # type: float

        # text is aligned to dimension line
        self.text_rotation = self.dim_line_angle  # type: float
        if self.text_halign in (
                3, 4
        ):  # text above extension line, is always aligned with extension lines
            self.text_rotation = self.ext_line_angle

        self.ext1_line_start = Vec2(self.dimension.dxf.defpoint2)
        self.ext2_line_start = Vec2(self.dimension.dxf.defpoint3)

        ext1_ray = ConstructionRay(self.ext1_line_start,
                                   angle=self.ext_line_angle_rad)
        ext2_ray = ConstructionRay(self.ext2_line_start,
                                   angle=self.ext_line_angle_rad)
        dim_line_ray = ConstructionRay(self.dimension.dxf.defpoint,
                                       angle=self.dim_line_angle_rad)

        self.dim_line_start = dim_line_ray.intersect(ext1_ray)  # type: Vec2
        self.dim_line_end = dim_line_ray.intersect(ext2_ray)  # type: Vec2
        self.dim_line_center = self.dim_line_start.lerp(
            self.dim_line_end)  # type: Vec2

        if self.dim_line_start == self.dim_line_end:
            self.dim_line_vec = Vec2.from_angle(self.dim_line_angle_rad)
        else:
            self.dim_line_vec = (self.dim_line_end -
                                 self.dim_line_start).normalize()  # type: Vec2

        # set dimension defpoint to expected location - 3D vertex required!
        self.dimension.dxf.defpoint = Vector(self.dim_line_start)

        self.measurement = (self.dim_line_end -
                            self.dim_line_start).magnitude  # type: float
        self.text = self.text_override(
            self.measurement * self.dim_measurement_factor)  # type: str

        # only for linear dimension in multi point mode
        self.multi_point_mode = override.pop('multi_point_mode', False)

        # 1 .. move wide text up
        # 2 .. move wide text down
        # None .. ignore
        self.move_wide_text = override.pop('move_wide_text',
                                           None)  # type: bool

        # actual text width in drawing units
        self.dim_text_width = 0  # type: float

        # arrows
        self.required_arrows_space = 2 * self.arrow_size + self.text_gap  # type: float
        self.arrows_outside = self.required_arrows_space > self.measurement  # type: bool

        # text location and rotation
        if self.text:
            # text width and required space
            self.dim_text_width = self.text_width(self.text)  # type: float
            if self.dim_tolerance:
                self.dim_text_width += self.tol_text_width

            elif self.dim_limits:
                # limits show the upper and lower limit of the measurement as stacked values
                # and with the size of tolerances
                measurement = self.measurement * self.dim_measurement_factor
                self.measurement_upper_limit = measurement + self.tol_maximum
                self.measurement_lower_limit = measurement - self.tol_minimum
                self.tol_text_upper = self.format_tolerance_text(
                    self.measurement_upper_limit)
                self.tol_text_lower = self.format_tolerance_text(
                    self.measurement_lower_limit)
                self.tol_text_width = self.tolerance_text_width(
                    max(len(self.tol_text_upper), len(self.tol_text_lower)))

                # only limits are displayed so:
                self.dim_text_width = self.tol_text_width

            if self.multi_point_mode:
                # ezdxf has total control about vertical text position in multi point mode
                self.text_vertical_position = 0.

            if self.text_valign == 0 and abs(
                    self.text_vertical_position) < 0.7:
                # vertical centered text needs also space for arrows
                required_space = self.dim_text_width + 2 * self.arrow_size
            else:
                required_space = self.dim_text_width
            self.is_wide_text = required_space > self.measurement

            if not self.force_text_inside:
                # place text outside if wide text and not forced inside
                self.text_outside = self.is_wide_text
            elif self.is_wide_text and self.text_halign < 3:
                # center wide text horizontal
                self.text_halign = 0

            # use relative text shift to move wide text up or down in multi point mode
            if self.multi_point_mode and self.is_wide_text and self.move_wide_text:
                shift_value = self.text_height + self.text_gap
                if self.move_wide_text == 1:  # move text up
                    self.text_shift_v = shift_value
                    if self.vertical_placement == -1:  # text below dimension line
                        # shift again
                        self.text_shift_v += shift_value
                elif self.move_wide_text == 2:  # move text down
                    self.text_shift_v = -shift_value
                    if self.vertical_placement == 1:  # text above dimension line
                        # shift again
                        self.text_shift_v -= shift_value

            # get final text location - no altering after this line
            self.text_location = self.get_text_location()  # type: Vec2

            # text rotation override
            rotation = self.text_rotation  # type: float
            if self.user_text_rotation is not None:
                rotation = self.user_text_rotation
            elif self.text_outside and self.text_outside_horizontal:
                rotation = 0
            elif self.text_inside and self.text_inside_horizontal:
                rotation = 0
            self.text_rotation = rotation

            self.text_box = TextBox(center=self.text_location,
                                    width=self.dim_text_width,
                                    height=self.text_height,
                                    angle=self.text_rotation,
                                    gap=self.text_gap * .75)
            if self.text_has_leader:
                p1, p2, *_ = self.text_box.corners
                self.leader1, self.leader2 = order_leader_points(
                    self.dim_line_center, p1, p2)
                # not exact what BricsCAD (AutoCAD) expect, but close enough
                self.dimension.dxf.text_midpoint = self.leader1
            else:
                # write final text location into DIMENSION entity
                self.dimension.dxf.text_midpoint = self.text_location
Example #25
0
def profile_construction_ray_init_once(count=COUNT):
    ray1 = ConstructionRay(p1=P1, p2=P2)
    ray2 = ConstructionRay(p1=P3, p2=P4)
    for _ in range(count):
        ray1.intersect(ray2)
Example #26
0
 def test_ray2d_parallel_vertical(self):
     ray1 = ConstructionRay((10, 1), (10, -7))
     ray2 = ConstructionRay((11, 0), angle=HALF_PI)
     ray3 = ConstructionRay((12, -10), (12, 7))
     ray4 = ConstructionRay((0, 0), (1, 1))
     ray5 = ConstructionRay((0, 0), angle=0)
     with pytest.raises(ParallelRaysError):
         _ = ray1.intersect(ray3)
     assert ray1.is_parallel(ray3) is True
     assert ray1.is_parallel(ray2) is True
     assert ray2.is_parallel(ray2) is True
     assert ray1.is_parallel(ray4) is False
     assert ray2.is_parallel(ray4) is False
     assert ray3.is_parallel(ray4) is False
     assert ray1.is_parallel(ray5) is False
     assert ray2.is_parallel(ray5) is False
     assert ray3.is_parallel(ray5) is False
     # vertical rays can't calc a y-value
     with pytest.raises(ArithmeticError):
         _ = ray1.yof(-1.0)
Example #27
0
 def test_ray2d_normal_horizontal(self):
     ray = ConstructionRay((10, 10), (20, 10))  # horizontal line
     ortho = ray.orthogonal((3, 3))
     point = ray.intersect(ortho)
     assert point.isclose(Vec3(3, 10))
Example #28
0
 def test_ray2d_normal_vertical(self):
     ray = ConstructionRay((10, 1), (10, -7))  # vertical line
     ortho = ray.orthogonal((3, 3))
     point = ray.intersect(ortho)
     assert point.isclose(Vec3(10, 3))
Example #29
0
    def __init__(
        self,
        dimension: "Dimension",
        ucs: "UCS" = None,
        override: "DimStyleOverride" = None,
    ):
        super().__init__(dimension, ucs, override)
        measurement = self.measurement
        if measurement.text_movement_rule == 0:
            # moves the dimension line with dimension text, this makes no sense
            # for ezdxf (just set `base` argument)
            measurement.text_movement_rule = 2

        self.oblique_angle: float = self.dimension.get_dxf_attrib(
            "oblique_angle", 90)
        self.dim_line_angle: float = self.dimension.get_dxf_attrib("angle", 0)
        self.dim_line_angle_rad: float = math.radians(self.dim_line_angle)
        self.ext_line_angle: float = self.dim_line_angle + self.oblique_angle
        self.ext_line_angle_rad: float = math.radians(self.ext_line_angle)

        # text is aligned to dimension line
        measurement.text_rotation = self.dim_line_angle
        # text above extension line, is always aligned with extension lines
        if measurement.text_halign in (3, 4):
            measurement.text_rotation = self.ext_line_angle

        self.ext1_line_start = Vec2(self.dimension.dxf.defpoint2)
        self.ext2_line_start = Vec2(self.dimension.dxf.defpoint3)

        ext1_ray = ConstructionRay(self.ext1_line_start,
                                   angle=self.ext_line_angle_rad)
        ext2_ray = ConstructionRay(self.ext2_line_start,
                                   angle=self.ext_line_angle_rad)
        dim_line_ray = ConstructionRay(self.dimension.dxf.defpoint,
                                       angle=self.dim_line_angle_rad)

        self.dim_line_start: Vec2 = dim_line_ray.intersect(ext1_ray)
        self.dim_line_end: Vec2 = dim_line_ray.intersect(ext2_ray)
        self.dim_line_center: Vec2 = self.dim_line_start.lerp(
            self.dim_line_end)

        if self.dim_line_start == self.dim_line_end:
            self.dim_line_vec = Vec2.from_angle(self.dim_line_angle_rad)
        else:
            self.dim_line_vec = (self.dim_line_end -
                                 self.dim_line_start).normalize()

        # set dimension defpoint to expected location - 3D vertex required!
        self.dimension.dxf.defpoint = Vec3(self.dim_line_start)

        raw_measurement = (self.dim_line_end - self.dim_line_start).magnitude
        measurement.update(raw_measurement)

        # only for linear dimension in multi point mode
        self.multi_point_mode = self.dim_style.pop("multi_point_mode", False)

        # 1 .. move wide text up
        # 2 .. move wide text down
        # None .. ignore
        self.move_wide_text: Optional[bool] = self.dim_style.pop(
            "move_wide_text", None)

        # actual text width in drawing units
        self._total_text_width: float = 0

        # arrows
        self.required_arrows_space: float = (2 * self.arrows.arrow_size +
                                             measurement.text_gap)
        self.arrows_outside: bool = (self.required_arrows_space >
                                     raw_measurement)

        # text location and rotation
        if measurement.text:
            # text width and required space
            self._total_text_width = self.total_text_width()
            if self.tol.has_limits:
                # limits show the upper and lower limit of the measurement as
                # stacked values and with the size of tolerances
                self.tol.update_limits(self.measurement.value)

            if self.multi_point_mode:
                # ezdxf has total control about vertical text position in multi
                # point mode
                measurement.text_vertical_position = 0.0

            if (measurement.text_valign == 0
                    and abs(measurement.text_vertical_position) < 0.7):
                # vertical centered text needs also space for arrows
                required_space = (self._total_text_width +
                                  2 * self.arrows.arrow_size)
            else:
                required_space = self._total_text_width
            measurement.is_wide_text = required_space > raw_measurement

            if not measurement.force_text_inside:
                # place text outside if wide text and not forced inside
                measurement.text_is_outside = measurement.is_wide_text
            elif measurement.is_wide_text and measurement.text_halign < 3:
                # center wide text horizontal
                measurement.text_halign = 0

            # use relative text shift to move wide text up or down in multi
            # point mode
            if (self.multi_point_mode and measurement.is_wide_text
                    and self.move_wide_text):
                shift_value = measurement.text_height + measurement.text_gap
                if self.move_wide_text == 1:  # move text up
                    measurement.text_shift_v = shift_value
                    if (measurement.vertical_placement == -1
                        ):  # text below dimension line
                        # shift again
                        measurement.text_shift_v += shift_value
                elif self.move_wide_text == 2:  # move text down
                    measurement.text_shift_v = -shift_value
                    if (measurement.vertical_placement == 1
                        ):  # text above dimension line
                        # shift again
                        measurement.text_shift_v -= shift_value

            # get final text location - no altering after this line
            measurement.text_location = self.get_text_location()

            # text rotation override
            rotation: float = measurement.text_rotation
            if measurement.user_text_rotation is not None:
                rotation = measurement.user_text_rotation
            elif (measurement.text_is_outside
                  and measurement.text_outside_horizontal):
                rotation = 0.0
            elif (measurement.text_is_inside
                  and measurement.text_inside_horizontal):
                rotation = 0.0
            measurement.text_rotation = rotation

            text_box = self.init_text_box()
            self.geometry.set_text_box(text_box)
            if measurement.has_leader:
                p1, p2, *_ = text_box.corners
                self.leader1, self.leader2 = order_leader_points(
                    self.dim_line_center, p1, p2)
                # not exact what BricsCAD (AutoCAD) expect, but close enough
                self.dimension.dxf.text_midpoint = self.leader1
            else:
                # write final text location into DIMENSION entity
                self.dimension.dxf.text_midpoint = measurement.text_location
Example #30
0
 def test_ray2d_normal(self):
     ray = ConstructionRay((-10, 3), (17, -7))
     ortho = ray.orthogonal((3, 3))
     point = ray.intersect(ortho)
     assert point.isclose(Vec3(1.4318, -1.234), abs_tol=1e-4)