1. Anuncie Aqui ! Entre em contato fdantas@4each.com.br

[Python] Drawing offset of dxf files using matplotlib and shapely

Discussão em 'Python' iniciado por Stack, Setembro 13, 2024.

  1. Stack

    Stack Membro Participativo

    I'm trying to draw external offset of the entities from dxf file. But i've got an issue with arcs. My code looks like:

    def load_dxf(self, filename):
    self.ax.clear()
    self.draw_grid()

    doc = ezdxf.readfile(filename)
    msp = doc.modelspace()
    self.entities = list(msp)

    for entity in msp:
    if entity.dxftype() == 'LINE':
    self.draw_line(entity)
    elif entity.dxftype() == 'CIRCLE':
    self.draw_circle(entity)
    elif entity.dxftype() == 'ARC':
    self.draw_arc(entity)
    elif entity.dxftype() == 'LWPOLYLINE':
    self.draw_lwpolyline(entity)
    elif entity.dxftype() == 'POLYLINE':
    self.draw_polyline(entity)
    elif entity.dxftype() == 'TEXT':
    self.draw_text(entity)

    self.ax.set_aspect('equal', 'box')
    self.fig.tight_layout()
    self.canvas.draw()

    def draw_line(self, entity):
    start = entity.dxf.start
    end = entity.dxf.end
    color = self.get_color_for_layer(entity.dxf.layer)
    self.ax.plot([start.x, end.x], [start.y, end.y], color=color)

    def draw_circle(self, entity):
    center = entity.dxf.center
    radius = entity.dxf.radius
    color = self.get_color_for_layer(entity.dxf.layer)
    circle = plt.Circle((center.x, center.y), radius, fill=False, color=color)
    self.ax.add_artist(circle)

    def draw_arc(self, entity):
    center = entity.dxf.center
    radius = entity.dxf.radius
    start_angle = entity.dxf.start_angle
    end_angle = entity.dxf.end_angle
    color = self.get_color_for_layer(entity.dxf.layer)

    if end_angle < start_angle:
    end_angle += 360

    theta = np.linspace(np.radians(start_angle), np.radians(end_angle), 100)
    x = center.x + radius * np.cos(theta)
    y = center.y + radius * np.sin(theta)
    self.ax.plot(x, y, color=color)

    def draw_lwpolyline(self, entity):
    points = entity.get_points()
    if not points:
    return

    x = [p[0] for p in points if len(p) > 0]
    y = [p[1] for p in points if len(p) > 1]

    if not y:
    y = [0] * len(x)

    min_len = min(len(x), len(y))
    x = x[:min_len]
    y = y[:min_len]

    if x and y:
    color = self.get_color_for_layer(entity.dxf.layer)
    self.ax.plot(x, y, color=color)

    def draw_polyline(self, entity):
    points = list(entity.points())
    if not points:
    return

    x = [p[0] for p in points if len(p) > 0]
    y = [p[1] for p in points if len(p) > 1]

    if not y:
    y = [0] * len(x)

    min_len = min(len(x), len(y))
    x = x[:min_len]
    y = y[:min_len]

    if x and y:
    color = self.get_color_for_layer(entity.dxf.layer)
    self.ax.plot(x, y, color=color)

    def get_contour_entities(self):
    return [entity for entity in self.entities if entity.dxf.layer == "MILL-E"]

    def draw_outside_offset(self, offset=6.0):
    contour_entities = self.get_contour_entities()
    paths = []
    for entity in contour_entities:
    if entity.dxftype() == 'LINE':
    start = entity.dxf.start
    end = entity.dxf.end
    paths.append(LineString([start, end]))
    elif entity.dxftype() == 'CIRCLE':
    center = (entity.dxf.center.x, entity.dxf.center.y)
    radius = entity.dxf.radius
    circle = Point(center).buffer(radius)
    paths.append(circle)
    elif entity.dxftype() == 'ARC':
    center = (entity.dxf.center.x, entity.dxf.center.y)
    radius = entity.dxf.radius
    start_angle = np.radians(entity.dxf.start_angle)
    end_angle = np.radians(entity.dxf.end_angle)
    t = np.linspace(start_angle, end_angle, 300)
    x = center[0] + radius * np.cos(t)
    y = center[1] + radius * np.sin(t)
    paths.append(LineString(zip(x, y)))
    elif entity.dxftype() in ['LWPOLYLINE', 'POLYLINE']:
    points = entity.get_points()
    if entity.closed:
    paths.append(Polygon(points))
    else:
    paths.append(LineString(points))

    if not paths:
    print("No valid paths created from entities.")
    return None

    combined_path = unary_union(paths)

    offset_path = combined_path.buffer(offset, join_style=2, cap_style=1, mitre_limit=5.0, resolution=16)

    simplified_offset = offset_path.simplify(0.01)

    fixed_offset = self.fix_corners(simplified_offset)

    if fixed_offset.geom_type == 'Polygon':
    x, y = fixed_offset.exterior.xy

    line, = self.ax.plot(x, y, color='r', linewidth=1)
    elif fixed_offset.geom_type == 'MultiPolygon':
    for polygon in fixed_offset.geoms:
    x, y = polygon.exterior.xy
    line, = self.ax.plot(x, y, color='r', linewidth=1)

    self.canvas.draw()

    return fixed_offset

    def fix_corners(self, path, tolerance=0.1):
    if path.geom_type != 'Polygon':
    return path

    coords = list(path.exterior.coords)
    fixed_coords = []
    for i in range(len(coords) - 1):
    fixed_coords.append(coords)
    if i > 0 and i < len(coords) - 2:
    v1 = np.array(coords) - np.array(coords[i - 1])
    v2 = np.array(coords[i + 1]) - np.array(coords)
    angle = np.arctan2(np.cross(v1, v2), np.dot(v1, v2))
    if abs(angle) < tolerance:
    mid_point = ((coords[0] + coords[i + 1][0]) / 2, (coords[1] + coords[i + 1][1]) / 2)
    fixed_coords.append(mid_point)

    fixed_coords.append(coords[-1])
    return Polygon(fixed_coords)


    I'm testing it on simple shape but one of the corners is still wrong. Any idea why? Please look at the image attached, it will give you more idea of what i'm trying to achieve

    I'm expecting offset path follow my shape

    Continue reading...

Compartilhe esta Página