Beispiel #1
0
def _offset_loops_to_polygons(offset_loops):
    model = pycam.Geometry.Model.ContourModel()
    before = None
    for n_loop, loop in enumerate(offset_loops):
        lines = []
        _log.info("loop #%d has %d lines/arcs", n_loop, len(loop))
        for n_segment, item in enumerate(loop):
            _log.info("%d -> %s", n_segment, item)
            point, radius = item[:2]
            point = (point.x, point.y, 0.0)
            if before is not None:
                if radius == -1:
                    lines.append(Line(before, point))
                    _log.info("%d line %s to %s", n_segment, before, point)
                else:
                    _log.info("%d arc %s to %s r=%f", n_segment, before, point,
                              radius)
                    center, clock_wise = item[2:4]
                    center = (center.x, center.y, 0.0)
                    direction_before = (before[0] - center[0],
                                        before[1] - center[1], 0.0)
                    direction_end = (point[0] - center[0],
                                     point[1] - center[1], 0.0)
                    angles = [
                        180.0 * get_angle_pi((1.0, 0.0, 0.0), (0, 0.0, 0.0),
                                             direction, (0.0, 0.0, 1.0),
                                             pi_factor=True)
                        for direction in (direction_before, direction_end)
                    ]
                    if clock_wise:
                        angles.reverse()
                    points = get_points_of_arc(center, radius, angles[0],
                                               angles[1])
                    last_p = before
                    for p in points:
                        lines.append(Line(last_p, p))
                        last_p = p
            before = point
        for line in lines:
            if line.len > epsilon:
                model.append(line)
    return model.get_polygons()
Beispiel #2
0
def get_spiral_layer(minx, maxx, miny, maxy, z, line_distance, step_width,
                     grid_direction, start_position, rounded_corners, reverse):
    current_location = _get_position(minx, maxx, miny, maxy, z, start_position)
    if line_distance > 0:
        line_steps_x = math.ceil((float(maxx - minx) / line_distance))
        line_steps_y = math.ceil((float(maxy - miny) / line_distance))
        line_distance_x = (maxx - minx) / line_steps_x
        line_distance_y = (maxy - miny) / line_steps_y
        lines = get_spiral_layer_lines(minx, maxx, miny, maxy, z,
                                       line_distance_x, line_distance_y,
                                       grid_direction, start_position,
                                       current_location)
        if reverse:
            lines.reverse()
        # turn the lines into steps
        if rounded_corners:
            rounded_lines = []
            previous = None
            for index, (start, end) in enumerate(lines):
                radius = 0.5 * min(line_distance_x, line_distance_y)
                edge_vector = psub(end, start)
                # TODO: ellipse would be better than arc
                offset = pmul(pnormalized(edge_vector), radius)
                if previous:
                    start = padd(start, offset)
                    center = padd(previous, offset)
                    up_vector = pnormalized(
                        pcross(psub(previous, center), psub(start, center)))
                    north = padd(center, (1.0, 0.0, 0.0, 'v'))
                    angle_start = get_angle_pi(
                        north, center, previous, up_vector,
                        pi_factor=True) * 180.0
                    angle_end = get_angle_pi(
                        north, center, start, up_vector,
                        pi_factor=True) * 180.0
                    # TODO: remove these exceptions based on up_vector.z (get_points_of_arc does
                    #       not respect the plane, yet)
                    if up_vector[2] < 0:
                        angle_start, angle_end = -angle_end, -angle_start
                    arc_points = get_points_of_arc(center, radius, angle_start,
                                                   angle_end)
                    if up_vector[2] < 0:
                        arc_points.reverse()
                    for arc_index in range(len(arc_points) - 1):
                        p1_coord = arc_points[arc_index]
                        p2_coord = arc_points[arc_index + 1]
                        p1 = (p1_coord[0], p1_coord[1], z)
                        p2 = (p2_coord[0], p2_coord[1], z)
                        rounded_lines.append((p1, p2))
                if index != len(lines) - 1:
                    end = psub(end, offset)
                previous = end
                rounded_lines.append((start, end))
            lines = rounded_lines
        for start, end in lines:
            points = []
            if step_width is None:
                points.append(start)
                points.append(end)
            else:
                line = Line(start, end)
                if isiterable(step_width):
                    steps = step_width
                else:
                    steps = floatrange(0.0, line.len, inc=step_width)
                for step in steps:
                    next_point = padd(line.p1, pmul(line.dir, step))
                    points.append(next_point)
            if reverse:
                points.reverse()
            yield points
Beispiel #3
0
 def parse_arc(self, circle=False):
     start_line = self.line_number
     # the z-level defaults to zero (for 2D models)
     center = [None, None, 0]
     color = None
     radius = None
     if circle:
         angle_start = 0
         angle_end = 360
     else:
         angle_start = None
         angle_end = None
     key, value = self._read_key_value()
     while (key is not None) and (key != self.KEYS["MARKER"]):
         if key == self.KEYS["P1_X"]:
             center[0] = value
         elif key == self.KEYS["P1_Y"]:
             center[1] = value
         elif key == self.KEYS["P1_Z"]:
             center[2] = value
         elif key == self.KEYS["RADIUS"]:
             radius = value
         elif key == self.KEYS["ANGLE_START"]:
             angle_start = value
         elif key == self.KEYS["ANGLE_END"]:
             angle_end = value
         elif key == self.KEYS["COLOR"]:
             color = value
         else:
             pass
         key, value = self._read_key_value()
     end_line = self.line_number
     # The last lines were not used - they are just the marker for the next item.
     if key is not None:
         self._push_on_stack(key, value)
     if (None in center) or (None in (radius, angle_start, angle_end)):
         log.warn(
             "DXFImporter: Incomplete ARC definition between line %d and %d",
             start_line, end_line)
     else:
         if self._color_as_height and (color is not None):
             # use the color code as the z coordinate
             center[2] = float(color) / 255
         center = tuple(center)
         xy_point_coords = get_points_of_arc(center, radius, angle_start,
                                             angle_end)
         # Somehow the order of points seems to be the opposite of what is
         # expected.
         xy_point_coords.reverse()
         if len(xy_point_coords) > 1:
             for index in range(len(xy_point_coords) - 1):
                 p1 = xy_point_coords[index]
                 p1 = (p1[0], p1[1], center[2])
                 p2 = xy_point_coords[index + 1]
                 p2 = (p2[0], p2[1], center[2])
                 if p1 != p2:
                     self.lines.append(Line(p1, p2))
         else:
             log.warn(
                 "DXFImporter: Ignoring tiny ARC (between input line %d and %d): %s / %s "
                 "(%s - %s)", start_line, end_line, center, radius,
                 angle_start, angle_end)
Beispiel #4
0
 def __init__(self, stream, callback=None):
     self.letters = {}
     self.meta = {}
     self.callback = callback
     feeder = _LineFeeder(stream.readlines())
     while not feeder.is_empty():
         line = feeder.consume()
         if not line:
             # ignore
             pass
         elif line.startswith("#"):
             # comment or meta data
             content = line[1:].split(":", 1)
             if len(content) == 2:
                 key = content[0].lower().strip()
                 value = content[1].strip()
                 if key in self.META_KEYWORDS:
                     try:
                         if key != "encoding":
                             self.meta[key] = float(value)
                         else:
                             self.meta[key] = value
                     except ValueError:
                         raise _CXFParseError(
                             "Invalid meta information in line %d" %
                             feeder.get_index())
                 elif key in self.META_KEYWORDS_MULTI:
                     if key in self.meta:
                         self.meta[key].append(value)
                     else:
                         self.meta[key] = [value]
                 else:
                     # unknown -> ignore
                     pass
         elif line.startswith("["):
             # Update the GUI from time to time.
             # This is useful for the big unicode font.
             if self.callback and (len(self.letters) % 50 == 0):
                 self.callback()
             if (len(line) >= 3) and (line[2] == "]"):
                 # single character
                 for encoding in ("utf-8", "iso8859-1", "iso8859-15"):
                     try:
                         character = line[1].decode(encoding)
                         break
                     except UnicodeDecodeError:
                         pass
                 else:
                     raise _CXFParseError(
                         "Failed to decode character at line %d" %
                         feeder.get_index())
             elif (len(line) >= 6) and (line[5] == "]"):
                 # unicode character (e.g. "[1ae4]")
                 try:
                     character = chr(int(line[1:5], 16))
                 except ValueError:
                     raise _CXFParseError(
                         "Failed to parse unicode character at line %d" %
                         feeder.get_index())
             elif (len(line) > 3) and (line.find("]") > 2):
                 # read UTF8 (qcad 1 compatibility)
                 end_bracket = line.find("] ")
                 text = line[1:end_bracket]
                 character = text.decode("utf-8", errors="ignore")[0]
             else:
                 # unknown format
                 raise _CXFParseError(
                     "Failed to parse character at line %d" %
                     feeder.get_index())
             # parse the following lines up to the next empty line
             char_definition = []
             while not feeder.is_empty() and (len(feeder.get()) > 0):
                 line = feeder.consume()
                 # split the line after the first whitespace
                 type_def, coord_string = line.split(None, 1)
                 coords = [
                     float(value) for value in coord_string.split(",")
                 ]
                 if (type_def == "L") and (len(coords) == 4):
                     # line
                     p1 = (coords[0], coords[1], 0)
                     p2 = (coords[2], coords[3], 0)
                     char_definition.append(Line(p1, p2))
                 elif (type_def in ("A", "AR")) and (len(coords) == 5):
                     # arc
                     previous = None
                     center = (coords[0], coords[1], 0)
                     radius = coords[2]
                     start_angle, end_angle = coords[3], coords[4]
                     if type_def == "AR":
                         # reverse the arc
                         start_angle, end_angle = end_angle, start_angle
                     for p in get_points_of_arc(center, radius, start_angle,
                                                end_angle):
                         current = (p[0], p[1], 0)
                         if previous is not None:
                             char_definition.append(Line(previous, current))
                         previous = current
                 else:
                     raise _CXFParseError(
                         "Failed to read item coordinates in line %d" %
                         feeder.get_index())
             self.letters[character] = char_definition
         else:
             # unknown line format
             raise _CXFParseError(
                 "Failed to parse unknown content in line %d" %
                 feeder.get_index())