Exemple #1
0
def get_draw_angles(start: float, end: float, extrusion: Vector):
    if extrusion.isclose(Z_AXIS):
        return start, end
    else:
        ocs = OCS(extrusion)
        s = ocs.to_wcs(Vector.from_angle(start))
        e = ocs.to_wcs(Vector.from_angle(end))
        return normalize_angle(e.angle), normalize_angle(s.angle)
Exemple #2
0
def random_3d_path(steps: int = 100,
                   max_step_size: float = 1.0,
                   max_heading: float = math.pi / 2.0,
                   max_pitch: float = math.pi / 8.0,
                   retarget: int = 20) -> Iterable[Vector]:
    """
    Returns a random 3D path as iterable of :class:`~ezdxf.math.Vector` objects.

    Args:
        steps: count of vertices to generate
        max_step_size: max step size
        max_heading: limit heading angle change per step to ± max_heading/2, rotation about the z-axis in radians
        max_pitch: limit pitch angle change per step to ± max_pitch/2, rotation about the x-axis in radians
        retarget: specifies steps before changing global walking target

    """
    max_ = max_step_size * steps

    def next_global_target():
        return Vector((rnd(max_), rnd(max_), rnd(max_)))

    walker = Vector()
    target = next_global_target()
    for i in range(steps):
        if i % retarget == 0:
            target = target + next_global_target()
        angle = (target - walker).angle
        length = max_step_size * random.random()
        heading_angle = angle + rnd_perlin(max_heading, walker)
        next_step = Vector.from_angle(heading_angle, length)
        pitch_angle = rnd_perlin(max_pitch, walker)
        walker += Matrix44.x_rotate(pitch_angle).transform(next_step)
        yield walker
Exemple #3
0
def linear_measurement(p1: Vector, p2: Vector, angle: float = 0, ocs: 'OCS' = None) -> float:
    """ Returns distance from `p1` to `p2` projected onto ray defined by `angle`, `angle` in radians in the xy-plane.
    """
    if ocs is not None and ocs.uz != (0, 0, 1):
        p1 = ocs.to_wcs(p1)
        p2 = ocs.to_wcs(p2)
        # angle in OCS xy-plane
        ocs_direction = Vector.from_angle(angle)
        measurement_direction = ocs.to_wcs(ocs_direction)
    else:
        # angle in WCS xy-plane
        measurement_direction = Vector.from_angle(angle)

    t1 = measurement_direction.project(p1)
    t2 = measurement_direction.project(p2)
    return (t2 - t1).magnitude
Exemple #4
0
    def tangent(self, t: float) -> Vector:
        """
        Get tangent at distance `t` as Vector() object.

        """
        angle = t ** 2 / (2. * self.curvature_powers[2])
        return Vector.from_angle(angle)
Exemple #5
0
def cubic_bezier_arc_parameters(
        start_angle: float, end_angle: float,
        segments: int = 1) -> Sequence[Vector]:
    """ Yields cubic Bézier-curve parameters for a circular 2D arc with center
    at (0, 0) and a radius of 1 in the form of [start point, 1. control point,
    2. control point, end point].

    Args:
        start_angle: start angle in radians
        end_angle: end angle in radians (end_angle > start_angle!)
        segments: count of Bèzier-curve segments, at least one segment for each
            quarter (pi/2)

    """
    if segments < 1:
        raise ValueError('Invalid argument segments (>= 1).')
    delta_angle = end_angle - start_angle
    if delta_angle > 0:
        arc_count = max(math.ceil(delta_angle / math.pi * 2.0), segments)
    else:
        raise ValueError('Delta angle from start- to end angle has to be > 0.')

    segment_angle = delta_angle / arc_count
    tangent_length = TANGENT_FACTOR * math.tan(segment_angle / 4.0)

    angle = start_angle
    end_point = None
    for _ in range(arc_count):
        start_point = Vector.from_angle(
            angle) if end_point is None else end_point
        angle += segment_angle
        end_point = Vector.from_angle(angle)
        control_point_1 = start_point + (
            -start_point.y * tangent_length, start_point.x * tangent_length)
        control_point_2 = end_point + (
            end_point.y * tangent_length, -end_point.x * tangent_length)
        yield start_point, control_point_1, control_point_2, end_point
Exemple #6
0
def cubic_bezier_arc_parameters(start_angle: float,
                                end_angle: float,
                                segments: int = 1):
    """
    Yields cubic Bezier curve parameters for a circular 2D arc with center at (0, 0) and a radius of 1
    in the form of [start point, 1. control point, 2. control point, end point].

    Args:
        start_angle: start angle in radians
        end_angle: end angle in radians (end_angle > start_angle!)
        segments: count of segments, at least one segment for each quarter (pi/2)

    """
    # Source: https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves
    if segments < 1:
        raise ValueError('Invalid argument segments (>= 1).')
    delta_angle = end_angle - start_angle
    if delta_angle > 0:
        arc_count = max(math.ceil(delta_angle / math.pi * 2.0), segments)
    else:
        raise ValueError('Delta angle from start- to end angle has to be > 0.')

    segment_angle = delta_angle / arc_count
    tangent_length = 4.0 / 3.0 * math.tan(segment_angle / 4.0)

    angle = start_angle
    end_point = None
    for _ in range(arc_count):
        start_point = Vector.from_angle(
            angle) if end_point is None else end_point
        angle += segment_angle
        end_point = Vector.from_angle(angle)
        control_point_1 = start_point + (-start_point.y * tangent_length,
                                         start_point.x * tangent_length)
        control_point_2 = end_point + (end_point.y * tangent_length,
                                       -end_point.x * tangent_length)
        yield start_point, control_point_1, control_point_2, end_point