| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- # ##########################################################
- # FlatCAM: 2D Post-processing for Manufacturing #
- # File Author: Marius Adrian Stanciu (c) #
- # Date: 3/10/2019 #
- # MIT Licence #
- # ##########################################################
- from shapely.geometry import LineString
- from shapely.affinity import rotate
- from ezdxf.math.vector import Vector as ezdxf_vector
- import logging
- log = logging.getLogger('base2')
- from appParsers.ParseFont import *
- from appParsers.ParseDXF_Spline import *
- def distance(pt1, pt2):
- return math.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
- def dxfpoint2shapely(point):
- geo = Point(point.dxf.location).buffer(0.01)
- return geo
- def dxfline2shapely(line):
- try:
- start = (line.dxf.start[0], line.dxf.start[1])
- stop = (line.dxf.end[0], line.dxf.end[1])
- except Exception as e:
- log.debug(str(e))
- return None
- geo = LineString([start, stop])
- return geo
- def dxfcircle2shapely(circle, n_points=100):
- ocs = circle.ocs()
- # if the extrusion attribute is not (0, 0, 1) then we have to change the coordinate system from OCS to WCS
- if circle.dxf.extrusion != (0, 0, 1):
- center_pt = ocs.to_wcs(circle.dxf.center)
- else:
- center_pt = circle.dxf.center
- radius = circle.dxf.radius
- geo = Point(center_pt).buffer(radius, int(n_points / 4))
- return geo
- def dxfarc2shapely(arc, n_points=100):
- # ocs = arc.ocs()
- # # if the extrusion attribute is not (0, 0, 1) then we have to change the coordinate system from OCS to WCS
- # if arc.dxf.extrusion != (0, 0, 1):
- # arc_center = ocs.to_wcs(arc.dxf.center)
- # start_angle = math.radians(arc.dxf.start_angle) + math.pi
- # end_angle = math.radians(arc.dxf.end_angle) + math.pi
- # dir = 'CW'
- # else:
- # arc_center = arc.dxf.center
- # start_angle = math.radians(arc.dxf.start_angle)
- # end_angle = math.radians(arc.dxf.end_angle)
- # dir = 'CCW'
- #
- # center_x = arc_center[0]
- # center_y = arc_center[1]
- # radius = arc.dxf.radius
- #
- # point_list = []
- #
- # if start_angle > end_angle:
- # start_angle += 2 * math.pi
- #
- # line_seg = int((n_points * (end_angle - start_angle)) / math.pi)
- # step_angle = (end_angle - start_angle) / float(line_seg)
- #
- # angle = start_angle
- # for step in range(line_seg + 1):
- # if dir == 'CCW':
- # x = center_x + radius * math.cos(angle)
- # y = center_y + radius * math.sin(angle)
- # else:
- # x = center_x + radius * math.cos(-angle)
- # y = center_y + radius * math.sin(-angle)
- # point_list.append((x, y))
- # angle += step_angle
- #
- #
- # log.debug("X = %.4f, Y = %.4f, Radius = %.4f, start_angle = %.1f, stop_angle = %.1f, step_angle = %.4f, dir=%s" %
- # (center_x, center_y, radius, start_angle, end_angle, step_angle, dir))
- #
- # geo = LineString(point_list)
- # return geo
- ocs = arc.ocs()
- # if the extrusion attribute is not (0, 0, 1) then we have to change the coordinate system from OCS to WCS
- if arc.dxf.extrusion != (0, 0, 1):
- arc_center = ocs.to_wcs(arc.dxf.center)
- start_angle = arc.dxf.start_angle + 180
- end_angle = arc.dxf.end_angle + 180
- dir = 'CW'
- else:
- arc_center = arc.dxf.center
- start_angle = arc.dxf.start_angle
- end_angle = arc.dxf.end_angle
- dir = 'CCW'
- center_x = arc_center[0]
- center_y = arc_center[1]
- radius = arc.dxf.radius
- point_list = []
- if start_angle > end_angle:
- start_angle = start_angle - 360
- angle = start_angle
- step_angle = float(abs(end_angle - start_angle) / n_points)
- while angle <= end_angle:
- if dir == 'CCW':
- x = center_x + radius * math.cos(math.radians(angle))
- y = center_y + radius * math.sin(math.radians(angle))
- else:
- x = center_x + radius * math.cos(math.radians(-angle))
- y = center_y + radius * math.sin(math.radians(-angle))
- point_list.append((x, y))
- angle += abs(step_angle)
- # in case the number of segments do not cover everything until the end of the arc
- if angle != end_angle:
- if dir == 'CCW':
- x = center_x + radius * math.cos(math.radians(end_angle))
- y = center_y + radius * math.sin(math.radians(end_angle))
- else:
- x = center_x + radius * math.cos(math.radians(- end_angle))
- y = center_y + radius * math.sin(math.radians(- end_angle))
- point_list.append((x, y))
- # log.debug("X = %.4f, Y = %.4f, Radius = %.4f, start_angle = %.1f, stop_angle = %.1f, step_angle = %.4f" %
- # (center_x, center_y, radius, start_angle, end_angle, step_angle))
- geo = LineString(point_list)
- return geo
- def dxfellipse2shapely(ellipse, ellipse_segments=100):
- # center = ellipse.dxf.center
- # start_angle = ellipse.dxf.start_param
- # end_angle = ellipse.dxf.end_param
- ocs = ellipse.ocs()
- # if the extrusion attribute is not (0, 0, 1) then we have to change the coordinate system from OCS to WCS
- if ellipse.dxf.extrusion != (0, 0, 1):
- center = ocs.to_wcs(ellipse.dxf.center)
- start_angle = ocs.to_wcs(ellipse.dxf.start_param)
- end_angle = ocs.to_wcs(ellipse.dxf.end_param)
- dir = 'CW'
- else:
- center = ellipse.dxf.center
- start_angle = ellipse.dxf.start_param
- end_angle = ellipse.dxf.end_param
- dir = 'CCW'
- # print("Dir = %s" % dir)
- major_axis = ellipse.dxf.major_axis
- ratio = ellipse.dxf.ratio
- points_list = []
- major_axis = Vector(list(major_axis))
- major_x = major_axis[0]
- major_y = major_axis[1]
- if start_angle >= end_angle:
- end_angle += 2.0 * math.pi
- line_seg = int((ellipse_segments * (end_angle - start_angle)) / math.pi)
- step_angle = abs(end_angle - start_angle) / float(line_seg)
- angle = start_angle
- for step in range(line_seg + 1):
- if dir == 'CW':
- major_dim = normalize_2(major_axis)
- minor_dim = normalize_2(Vector([ratio * k for k in major_axis]))
- vx = (major_dim[0] + major_dim[1]) * math.cos(angle)
- vy = (minor_dim[0] - minor_dim[1]) * math.sin(angle)
- x = center[0] + major_x * vx - major_y * vy
- y = center[1] + major_y * vx + major_x * vy
- angle += step_angle
- else:
- major_dim = normalize_2(major_axis)
- minor_dim = (Vector([ratio * k for k in major_dim]))
- vx = (major_dim[0] + major_dim[1]) * math.cos(angle)
- vy = (minor_dim[0] + minor_dim[1]) * math.sin(angle)
- x = center[0] + major_x * vx + major_y * vy
- y = center[1] + major_y * vx + major_x * vy
- angle += step_angle
- points_list.append((x, y))
- geo = LineString(points_list)
- return geo
- def dxfpolyline2shapely(polyline):
- final_pts = []
- pts = polyline.points()
- for i in pts:
- final_pts.append((i[0], i[1]))
- if polyline.is_closed:
- final_pts.append(final_pts[0])
- geo = LineString(final_pts)
- return geo
- def dxflwpolyline2shapely(lwpolyline):
- final_pts = []
- for point in lwpolyline:
- x, y, _, _, _ = point
- final_pts.append((x, y))
- if lwpolyline.closed:
- final_pts.append(final_pts[0])
- geo = LineString(final_pts)
- return geo
- def dxfsolid2shapely(solid):
- iterator = 0
- corner_list = []
- try:
- corner_list.append(solid[iterator])
- iterator += 1
- except Exception:
- return Polygon(corner_list)
- def dxfspline2shapely(spline):
- # for old version of ezdxf
- # with spline.edit_data() as spline_data:
- # ctrl_points = spline_data.control_points
- # try:
- # # required if using old version of ezdxf
- # knot_values = spline_data.knot_values
- # except AttributeError:
- # knot_values = spline_data.knots
- ctrl_points = spline.control_points
- knot_values = spline.knots
- is_closed = spline.closed
- degree = spline.dxf.degree
- x_list, y_list, _ = spline2Polyline(ctrl_points, degree=degree, closed=is_closed, segments=20, knots=knot_values)
- points_list = zip(x_list, y_list)
- geo = LineString(points_list)
- return geo
- def dxftrace2shapely(trace):
- iterator = 0
- corner_list = []
- try:
- corner_list.append(trace[iterator])
- iterator += 1
- except Exception:
- return Polygon(corner_list)
- def getdxfgeo(dxf_object):
- msp = dxf_object.modelspace()
- geos = get_geo(dxf_object, msp)
- # geo_block = get_geo_from_block(dxf_object)
- return geos
- def get_geo_from_insert(dxf_object, insert):
- geo_block_transformed = []
- phi = insert.dxf.rotation
- tr = insert.dxf.insert
- sx = insert.dxf.xscale
- sy = insert.dxf.yscale
- r_count = insert.dxf.row_count
- r_spacing = insert.dxf.row_spacing
- c_count = insert.dxf.column_count
- c_spacing = insert.dxf.column_spacing
- # print(phi, tr)
- # identify the block given the 'INSERT' type entity name
- block = dxf_object.blocks[insert.dxf.name]
- block_coords = (block.block.dxf.base_point[0], block.block.dxf.base_point[1])
- # get a list of geometries found in the block
- geo_block = get_geo(dxf_object, block)
- # iterate over the geometries found and apply any transformation found in the 'INSERT' entity attributes
- for geo in geo_block:
- # get the bounds of the geometry
- # minx, miny, maxx, maxy = geo.bounds
- if tr[0] != 0 or tr[1] != 0:
- geo = translate(geo, (tr[0] - block_coords[0]), (tr[1] - block_coords[1]))
- # support for array block insertions
- if r_count > 1:
- for r in range(r_count):
- geo_block_transformed.append(translate(geo, (tr[0] + (r * r_spacing) - block_coords[0]), 0))
- if c_count > 1:
- for c in range(c_count):
- geo_block_transformed.append(translate(geo, 0, (tr[1] + (c * c_spacing) - block_coords[1])))
- if sx != 1 or sy != 1:
- geo = scale(geo, sx, sy)
- if phi != 0:
- if isinstance(tr, str) and tr.lower() == 'c':
- tr = 'center'
- elif isinstance(tr, ezdxf_vector):
- tr = list(tr)
- geo = rotate(geo, phi, origin=tr)
- geo_block_transformed.append(geo)
- return geo_block_transformed
- def get_geo(dxf_object, container):
- # store shapely geometry here
- geo = []
- for dxf_entity in container:
- g = []
- # print("Entity", dxf_entity.dxftype())
- if dxf_entity.dxftype() == 'POINT':
- g = dxfpoint2shapely(dxf_entity,)
- elif dxf_entity.dxftype() == 'LINE':
- g = dxfline2shapely(dxf_entity,)
- elif dxf_entity.dxftype() == 'CIRCLE':
- g = dxfcircle2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'ARC':
- g = dxfarc2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'ELLIPSE':
- g = dxfellipse2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'LWPOLYLINE':
- g = dxflwpolyline2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'POLYLINE':
- g = dxfpolyline2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'SOLID':
- g = dxfsolid2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'TRACE':
- g = dxftrace2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'SPLINE':
- g = dxfspline2shapely(dxf_entity)
- elif dxf_entity.dxftype() == 'INSERT':
- g = get_geo_from_insert(dxf_object, dxf_entity)
- else:
- log.debug(" %s is not supported yet." % dxf_entity.dxftype())
- if g is not None:
- if type(g) == list:
- for subg in g:
- geo.append(subg)
- else:
- geo.append(g)
- return geo
- def getdxftext(exf_object, object_type, units=None):
- pass
- # def get_geo_from_block(dxf_object):
- # geo_block_transformed = []
- #
- # msp = dxf_object.modelspace()
- # # iterate through all 'INSERT' entities found in modelspace msp
- # for insert in msp.query('INSERT'):
- # phi = insert.dxf.rotation
- # tr = insert.dxf.insert
- # sx = insert.dxf.xscale
- # sy = insert.dxf.yscale
- # r_count = insert.dxf.row_count
- # r_spacing = insert.dxf.row_spacing
- # c_count = insert.dxf.column_count
- # c_spacing = insert.dxf.column_spacing
- #
- # # print(phi, tr)
- #
- # # identify the block given the 'INSERT' type entity name
- # print(insert.dxf.name)
- # block = dxf_object.blocks[insert.dxf.name]
- # block_coords = (block.block.dxf.base_point[0], block.block.dxf.base_point[1])
- #
- # # get a list of geometries found in the block
- # # store shapely geometry here
- # geo_block = []
- #
- # for dxf_entity in block:
- # g = []
- # # print("Entity", dxf_entity.dxftype())
- # if dxf_entity.dxftype() == 'POINT':
- # g = dxfpoint2shapely(dxf_entity, )
- # elif dxf_entity.dxftype() == 'LINE':
- # g = dxfline2shapely(dxf_entity, )
- # elif dxf_entity.dxftype() == 'CIRCLE':
- # g = dxfcircle2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'ARC':
- # g = dxfarc2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'ELLIPSE':
- # g = dxfellipse2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'LWPOLYLINE':
- # g = dxflwpolyline2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'POLYLINE':
- # g = dxfpolyline2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'SOLID':
- # g = dxfsolid2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'TRACE':
- # g = dxftrace2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'SPLINE':
- # g = dxfspline2shapely(dxf_entity)
- # elif dxf_entity.dxftype() == 'INSERT':
- # log.debug("Not supported yet.")
- # else:
- # log.debug("Not supported yet.")
- #
- # if g is not None:
- # if type(g) == list:
- # for subg in g:
- # geo_block.append(subg)
- # else:
- # geo_block.append(g)
- #
- # # iterate over the geometries found and apply any transformation found in the 'INSERT' entity attributes
- # for geo in geo_block:
- # if tr[0] != 0 or tr[1] != 0:
- # geo = translate(geo, (tr[0] - block_coords[0]), (tr[1] - block_coords[1]))
- #
- # # support for array block insertions
- # if r_count > 1:
- # for r in range(r_count):
- # geo_block_transformed.append(translate(geo, (tr[0] + (r * r_spacing) - block_coords[0]), 0))
- #
- # if c_count > 1:
- # for c in range(c_count):
- # geo_block_transformed.append(translate(geo, 0, (tr[1] + (c * c_spacing) - block_coords[1])))
- #
- # if sx != 1 or sy != 1:
- # geo = scale(geo, sx, sy)
- # if phi != 0:
- # geo = rotate(geo, phi, origin=tr)
- #
- # geo_block_transformed.append(geo)
- # return geo_block_transformed
|