Beispiel #1
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[Vec3]:
    """ Returns a random 3D path as iterable of :class:`~ezdxf.math.Vec3`
    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 Vec3((rnd(max_), rnd(max_), rnd(max_)))

    walker = Vec3()
    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 = Vec3.from_angle(heading_angle, length)
        pitch_angle = rnd_perlin(max_pitch, walker)
        walker += Matrix44.x_rotate(pitch_angle).transform(next_step)
        yield walker
Beispiel #2
0
    def tangent(self, t: float) -> Vec3:
        """
        Get tangent at distance `t` as :class.`Vec3` object.

        """
        angle = t**2 / (2. * self.curvature_powers[2])
        return Vec3.from_angle(angle)
Beispiel #3
0
    def to_ocs_angle_rad(self, angle: float) -> float:
        """Transforms `angle` from current UCS to the parent coordinate system
        (most likely the WCS) including the transformation to the OCS
        established by the extrusion vector :attr:`UCS.uz`.

        Args:
            angle: in UCS in radians

        """
        return self.ucs_direction_to_ocs_direction(Vec3.from_angle(angle)).angle
Beispiel #4
0
def linear_measurement(p1: Vec3,
                       p2: Vec3,
                       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 = Vec3.from_angle(angle)
        measurement_direction = ocs.to_wcs(ocs_direction)
    else:
        # angle in WCS xy-plane
        measurement_direction = Vec3.from_angle(angle)

    t1 = measurement_direction.project(p1)
    t2 = measurement_direction.project(p2)
    return (t2 - t1).magnitude
Beispiel #5
0
def cubic_bezier_arc_parameters(start_angle: float,
                                end_angle: float,
                                segments: int = 1) -> Sequence[Vec3]:
    """ 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 = Vec3.from_angle(
            angle) if end_point is None else end_point
        angle += segment_angle
        end_point = Vec3.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
Beispiel #6
0
 def transform_angle(self, angle: float) -> float:
     """ Returns angle (in radians) from old OCS transformed into new OCS.
     """
     return self.transform_direction(
         Vec3.from_angle(angle)).angle % math.tau