def offset_polyline(polyline, distance, normal=[0.0, 0.0, 1.0], tol=1e-6): """Offset a polyline by a distance. Parameters ---------- polyline : list of point The XYZ coordinates of the vertices of a polyline. distance : float or list of tuples of floats The offset distance as float. A single value determines a constant offset globally. Alternatively, pairs of local offset values per line segment can be used to create variable offsets. Distance > 0: offset to the "left", distance < 0: offset to the "right". normal : vector The normal of the offset plane. Returns ------- offset polyline : list of point The XYZ coordinates of the resulting polyline. """ if not is_item_iterable(distance): distance = [distance] distances = iterable_like(polyline, distance, distance[-1]) segments = offset_segments(polyline, distances, normal) offset = [segments[0][0]] for s1, s2 in pairwise(segments): point = intersect(s1, s2, tol) offset.append(point) offset.append(segments[-1][1]) return offset
def offset_line(line, distance, normal=[0.0, 0.0, 1.0]): """Offset a line by a distance. Parameters ---------- line : tuple Two points defining the line. distances : float or list of floats The offset distance as float. A single value determines a constant offset. Alternatively, two offset values for the start and end point of the line can be used to a create variable offset. normal : vector The normal of the offset plane. Returns ------- offset line : tuple Two points defining the offset line. Notes ----- The offset direction is chosen such that if the line were along the positve X axis and the normal of the offset plane is along the positive Z axis, the offset line is in the direction of the postive Y axis. Examples -------- .. code-block:: python line = [(0.0, 0.0, 0.0), (3.0, 3.0, 0.0)] distance = 0.2 # constant offset line_offset = offset_line(line, distance) print(line_offset) distance = [0.2, 0.1] # variable offset line_offset = offset_line(line, distance) print(line_offset) """ a, b = line ab = subtract_vectors(b, a) direction = normalize_vector(cross_vectors(normal, ab)) if not is_item_iterable(distance): distance = [distance] distances = list(iterable_like(line, distance, distance[-1])) u = scale_vector(direction, distances[0]) v = scale_vector(direction, distances[1]) c = add_vectors(a, u) d = add_vectors(b, v) return c, d
def offset_polygon(polygon, distance, tol=1e-6): """Offset a polygon (closed) by a distance. Parameters ---------- polygon : sequence[point] | :class:`compas.geometry.Polygon` The XYZ coordinates of the corners of the polygon. The first and last coordinates must not be identical. distance : float | list[tuple[float, float]] The offset distance as float. A single value determines a constant offset globally. A list of pairs of local offset values per line segment can be used to create variable offsets. tol : float, optional A tolerance value for intersection calculations. Returns ------- list[[float, float, float]] The XYZ coordinates of the corners of the offset polygon. The first and last coordinates are identical. Notes ----- The offset direction is determined by the normal of the polygon. If the polygon is in the XY plane and the normal is along the positive Z axis, positive offset distances will result in an offset towards the inside of the polygon. The algorithm works also for spatial polygons that do not perfectly fit a plane. Examples -------- >>> """ normal = normal_polygon(polygon) if not is_item_iterable(distance): distance = [distance] distances = iterable_like(polygon, distance, distance[-1]) polygon = polygon + polygon[:1] segments = offset_segments(polygon, distances, normal) offset = [] for s1, s2 in pairwise(segments[-1:] + segments): point = intersect(s1, s2, tol) offset.append(point) return offset
def offset_polyline(polyline, distance, normal=[0.0, 0.0, 1.0], tol=1e-6): """Offset a polyline by a distance. Parameters ---------- polyline : sequence[point] | :class:`compas.geometry.Polyline` The XYZ coordinates of the vertices of a polyline. distance : float | list[tuple[float, float]] The offset distance as float. A single value determines a constant offset globally. Alternatively, pairs of local offset values per line segment can be used to create variable offsets. normal : [float, float, float] | :class:`compas.geometry.Vector`, optional The normal of the offset plane. tol : float, optional A tolerance value for intersection calculations. Returns ------- list[[float, float, float]] The XYZ coordinates of the resulting polyline. Notes ----- The offset direction is determined by the provided normal vector. If the polyline is in the XY plane and the normal is along the positive Z axis, positive offset distances will result in counterclockwise offsets, and negative values in clockwise direction. Examples -------- >>> """ if not is_item_iterable(distance): distance = [distance] distances = iterable_like(polyline, distance, distance[-1]) segments = offset_segments(polyline, distances, normal) offset = [segments[0][0]] for s1, s2 in pairwise(segments): point = intersect(s1, s2, tol) offset.append(point) offset.append(segments[-1][1]) return offset
def offset_line(line, distance, normal=[0.0, 0.0, 1.0]): """Offset a line by a distance. Parameters ---------- line : [point, point] | :class:`compas.geometry.Line` A line defined by two points. distances : float or list[float] The offset distance as float. A single value determines a constant offset. A list of two offset values can be used to a create variable offset at the start and end. normal : [float, float, float] | :class:`compas.geometry.Vector`, optional The normal of the offset plane. Returns ------- tuple[[float, float, float], [float, float, float]] Two points defining the offset line. Notes ----- The offset direction is chosen such that if the line were along the positve X axis and the normal of the offset plane is along the positive Z axis, the offset line is in the direction of the postive Y axis. Examples -------- >>> """ a, b = line ab = subtract_vectors(b, a) direction = normalize_vector(cross_vectors(normal, ab)) if not is_item_iterable(distance): distance = [distance] distances = list(iterable_like(line, distance, distance[-1])) u = scale_vector(direction, distances[0]) v = scale_vector(direction, distances[1]) c = add_vectors(a, u) d = add_vectors(b, v) return c, d
def offset_polygon(polygon, distance, tol=1e-6): """Offset a polygon (closed) by a distance. Parameters ---------- polygon : list of point The XYZ coordinates of the corners of the polygon. The first and last coordinates must not be identical. distance : float or list of float The offset distance as float. A single value determines a constant offset globally. Alternatively, pairs of local offset values per line segment can be used to create variable offsets. Distance > 0: offset to the outside, distance < 0: offset to the inside. Returns ------- offset polygon : list of point The XYZ coordinates of the corners of the offset polygon. The first and last coordinates are identical. Notes ----- The offset direction is determined by the normal of the polygon. If the polygon is in the XY plane and the normal is along the positive Z axis, positive offset distances will result in an offset towards the inside of the polygon. The algorithm works also for spatial polygons that do not perfectly fit a plane. Examples -------- .. code-block:: python polygon = [ (0.0, 0.0, 0.0), (3.0, 0.0, 1.0), (3.0, 3.0, 2.0), (1.5, 1.5, 2.0), (0.0, 3.0, 1.0), (0.0, 0.0, 0.0) ] distance = 0.5 # constant offset polygon_offset = offset_polygon(polygon, distance) print(polygon_offset) distance = [ (0.1, 0.2), (0.2, 0.3), (0.3, 0.4), (0.4, 0.3), (0.3, 0.1) ] # variable offset polygon_offset = offset_polygon(polygon, distance) print(polygon_offset) """ normal = normal_polygon(polygon) if not is_item_iterable(distance): distance = [distance] distances = iterable_like(polygon, distance, distance[-1]) polygon = polygon + polygon[:1] segments = offset_segments(polygon, distances, normal) offset = [] for s1, s2 in pairwise(segments[-1:] + segments): point = intersect(s1, s2, tol) offset.append(point) return offset