- finished adding the PDF import tool although it does not support all kinds of outputs from PDF printers. Microsoft PDF printer is not supported.

This commit is contained in:
Marius Stanciu
2019-04-21 04:43:49 +03:00
parent 52fceae054
commit 108f11eacf
3 changed files with 459 additions and 78 deletions

View File

@@ -7606,6 +7606,7 @@ class App(QtCore.QObject):
openers = { openers = {
'gerber': lambda fname: self.worker_task.emit({'fcn': self.open_gerber, 'params': [fname]}), 'gerber': lambda fname: self.worker_task.emit({'fcn': self.open_gerber, 'params': [fname]}),
'excellon': lambda fname: self.worker_task.emit({'fcn': self.open_excellon, 'params': [fname]}), 'excellon': lambda fname: self.worker_task.emit({'fcn': self.open_excellon, 'params': [fname]}),
'geometry': lambda fname: self.worker_task.emit({'fcn': self.import_dxf, 'params': [fname]}),
'cncjob': lambda fname: self.worker_task.emit({'fcn': self.open_gcode, 'params': [fname]}), 'cncjob': lambda fname: self.worker_task.emit({'fcn': self.open_gcode, 'params': [fname]}),
'project': self.open_project, 'project': self.open_project,
'svg': self.import_svg, 'svg': self.import_svg,

View File

@@ -9,6 +9,10 @@ CAD program, and create G-Code for Isolation routing.
================================================= =================================================
20.04.2019
- finished adding the PDF import tool although it does not support all kinds of outputs from PDF printers. Microsoft PDF printer is not supported.
19.04.2019 19.04.2019
- started to work on PDF import tool - started to work on PDF import tool

View File

@@ -7,29 +7,33 @@
############################################################ ############################################################
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from shapely.geometry import Point, Polygon, LineString
from shapely.ops import cascaded_union, unary_union
from FlatCAMObj import * from FlatCAMObj import *
import math import math
from copy import copy, deepcopy
import numpy as np import numpy as np
import scipy.interpolate
import zlib import zlib
import re import re
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings') fcTranslate.apply_language('strings')
import builtins
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
class ToolPDF(FlatCAMTool): class ToolPDF(FlatCAMTool):
''' """
Parse a PDF file. Parse a PDF file.
Reference here: https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf Reference here: https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf
Return a list of geometries Return a list of geometries
''' """
toolName = _("PDF Import Tool") toolName = _("PDF Import Tool")
def __init__(self, app): def __init__(self, app):
@@ -39,50 +43,72 @@ class ToolPDF(FlatCAMTool):
self.stream_re = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S) self.stream_re = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S)
# detect 're' command
self.rect_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s*re$')
# detect 'm' command
self.start_subpath_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sm$')
# detect 'l' command
self.draw_line_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sl')
# detect 'c' command
self.draw_arc_3pt_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)'
r'\s(-?\d+\.?\d*)\s*c$')
# detect 'v' command
self.draw_arc_2pt_c1start_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s*v$')
# detect 'y' command
self.draw_arc_2pt_c2stop_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s*y$')
# detect 'h' command
self.end_subpath_re = re.compile(r'^h$')
# detect 'w' command # detect 'w' command
self.strokewidth_re = re.compile(r'^(\d+\.?\d*)\s*w$') self.strokewidth_re = re.compile(r'^(\d+\.?\d*)\s*w$')
# detect 're' command # detect 'S' command
self.rect_re = re.compile(r'^(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sre$') self.stroke_path__re = re.compile(r'^S$')
# detect 'm' command # detect 's' command
self.start_path_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sm$') self.close_stroke_path__re = re.compile(r'^s$')
# detect 'l' command # detect 'f' or 'f*' command
self.draw_line_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sl') self.fill_path_re = re.compile(r'^[f|F][*]?$')
# detect 'c' command # detect 'B' or 'B*' command
self.draw_arc_3pt_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sc$') self.fill_stroke_path_re = re.compile(r'^B[*]?$')
# detect 'v' command # detect 'b' or 'b*' command
self.draw_arc_2pt_23_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sv$') self.close_fill_stroke_path_re = re.compile(r'^b[*]?$')
# detect 'y' command # detect 'n'
self.draw_arc_2pt_13_re = re.compile(r'(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\sy$') self.no_op_re = re.compile(r'^n$')
# detect 'h' command
self.end_path_re = re.compile(r'^h$')
# detect offset transformation. Pattern: (1) (0) (0) (1) (x) (y)
self.offset_re = re.compile(r'^1\.?0*\s0?\.?0*\s0?\.?0*\s1\.?0*\s(-?\d+\.?\d*)\s(-?\d+\.?\d*)\s*cm$')
# detect scale transformation. Pattern: (factor_x) (0) (0) (factor_y) (0) (0)
self.scale_re = re.compile(r'^q? (-?\d+\.?\d*) 0\.?0* 0\.?0* (-?\d+\.?\d*) 0\.?0* 0\.?0*\s+cm$')
# detect combined transformation. Should always be the last
self.combined_transform_re = re.compile(r'^q?\s*(-?\d+\.?\d*) (-?\d+\.?\d*) (-?\d+\.?\d*) (-?\d+\.?\d*) '
r'(-?\d+\.?\d*) (-?\d+\.?\d*)\s+cm$')
# detect clipping path
self.clip_path_re = re.compile(r'^W[*]? n?$')
self.geo_buffer = []
self.pdf_parsed = '' self.pdf_parsed = ''
# conversion factor to INCH
self.point_to_unit_factor = 0.01388888888
def run(self, toggle=True): def run(self, toggle=True):
self.app.report_usage("ToolPDF()") self.app.report_usage("ToolPDF()")
# if toggle: # init variables for reuse
# # if the splitter is hidden, display it, else hide it but only if the current widget is the same self.geo_buffer = []
# if self.app.ui.splitter.sizes()[0] == 0: self.pdf_parsed = ''
# self.app.ui.splitter.setSizes([1, 1])
# else: # the UNITS in PDF files are points and here we set the factor to convert them to real units (either MM or INCH)
# try: if self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() == 'MM':
# if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName: # 1 inch = 72 points => 1 point = 1 / 72 = 0.01388888888 inch = 0.01388888888 inch * 25.4 = 0.35277777778 mm
# self.app.ui.splitter.setSizes([0, 1]) self.point_to_unit_factor = 0.35277777778
# except AttributeError: else:
# pass # 1 inch = 72 points => 1 point = 1 / 72 = 0.01388888888 inch
# else: self.point_to_unit_factor = 0.01388888888
# if self.app.ui.splitter.sizes()[0] == 0:
# self.app.ui.splitter.setSizes([1, 1])
#
# FlatCAMTool.run(self)
self.set_tool_ui() self.set_tool_ui()
self.on_open_pdf_click() self.on_open_pdf_click()
# self.app.ui.notebook.setTabText(2, "PDF Tool")
def install(self, icon=None, separator=None, **kwargs): def install(self, icon=None, separator=None, **kwargs):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+Q', **kwargs) FlatCAMTool.install(self, icon, separator, shortcut='ALT+Q', **kwargs)
@@ -104,75 +130,425 @@ class ToolPDF(FlatCAMTool):
try: try:
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"), filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"),
directory=self.app.get_last_folder(), filter=_filter_) directory=self.app.get_last_folder(),
filter=_filter_)
except TypeError: except TypeError:
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"), filter=_filter_) filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"), filter=_filter_)
filenames = [str(filename) for filename in filenames]
if len(filenames) == 0: if len(filenames) == 0:
self.app.inform.emit(_("[WARNING_NOTCL] Open PDF cancelled.")) self.app.inform.emit(_("[WARNING_NOTCL] Open PDF cancelled."))
else: else:
for filename in filenames: for filename in filenames:
if filename != '': if filename != '':
self.app.worker_task.emit({'fcn': self.open_pdf, self.app.worker_task.emit({'fcn': self.open_pdf, 'params': [filename]})
'params': [filename]})
def open_pdf(self, filename): def open_pdf(self, filename):
new_name = filename.split('/')[-1].split('\\')[-1]
def obj_init(grb_obj, app_obj): def obj_init(grb_obj, app_obj):
with open(filename, "rb") as f: with open(filename, "rb") as f:
pdf = f.read() pdf = f.read()
stream_nr = 0
for s in re.findall(self.stream_re, pdf): for s in re.findall(self.stream_re, pdf):
stream_nr += 1
print("STREAM:", stream_nr, '\n', '\n')
s = s.strip(b'\r\n') s = s.strip(b'\r\n')
try: try:
self.pdf_parsed += zlib.decompress(s).decode('UTF-8') self.pdf_parsed += (zlib.decompress(s).decode('UTF-8') + '\r\n')
except: except Exception as e:
pass app_obj.log.debug("ToolPDF.open_pdf().obj_init() --> %s" % str(e))
grb_obj.solid_geometry = [self.bezier_to_linestring(0, 0, 0, 0)]
ap_dict = self.parse_pdf(pdf_content=self.pdf_parsed)
grb_obj.apertures = deepcopy(ap_dict)
poly_buff = []
for ap in ap_dict:
for k in ap_dict[ap]:
if k == 'solid_geometry':
poly_buff += ap_dict[ap][k]
poly_buff = unary_union(poly_buff)
poly_buff = poly_buff.buffer(0.0000001)
poly_buff = poly_buff.buffer(-0.0000001)
grb_obj.solid_geometry = deepcopy(poly_buff)
with self.app.proc_container.new(_("Opening PDF.")): with self.app.proc_container.new(_("Opening PDF.")):
# obj_init()
self.parse_pdf()
ret = self.app.new_object("geometry", "bla", obj_init, autoselected=False)
# Register recent file
self.app.file_opened.emit("geometry", "bla")
# # Object name
# name = outname or filename.split('/')[-1].split('\\')[-1]
#
# ret = self.new_object("excellon", name, obj_init, autoselected=False)
# if ret == 'fail':
# self.inform.emit(_('[ERROR_NOTCL] Open Excellon file failed. Probable not an Excellon file.'))
# return
#
# # Register recent file
# self.file_opened.emit("excellon", filename)
#
# # GUI feedback
# self.inform.emit(_("[success] Opened: %s") % filename)
# # self.progress.emit(100)
def parse_pdf(self): ret = self.app.new_object("gerber", new_name, obj_init, autoselected=False)
for pline in self.pdf_parsed: if ret == 'fail':
pass self.app.inform.emit(_('[ERROR_NOTCL] Open PDF file failed.'))
return
def bezier_to_linestring(self, start, stop, c1, c2): # Register recent file
self.app.file_opened.emit("gerber", new_name)
# GUI feedback
self.app.inform.emit(_("[success] Opened: %s") % filename)
def parse_pdf(self, pdf_content):
path = dict()
path['lines'] = [] # it's a list of points
path['bezier'] = [] # it's a list of sublists each like this [start, c1, c2, stop]
path['rectangle'] = [] # it's a list of sublists of points
start_point = None
current_point = None
size = None
# signal that we have encountered a close path command
flag_close_path = False
# initial values for the transformations, in case they are not encountered in the PDF file
offset_geo = [0, 0]
scale_geo = [1, 1]
# initial aperture
aperture = 10
# store the apertures here
apertures_dict = {}
line_nr = 0
lines = pdf_content.splitlines()
for pline in lines:
line_nr += 1
log.debug("line %d: %s" % (line_nr, pline))
# TRANSFORMATIONS DETECTION #
# Detect Scale transform
match = self.scale_re.search(pline)
if match:
log.debug(
"ToolPDF.parse_pdf() --> SCALE transformation found on line: %s --> %s" % (line_nr, pline))
scale_geo = [float(match.group(1)), float(match.group(2))]
continue
# Detect Offset transform
match = self.offset_re.search(pline)
if match:
log.debug(
"ToolPDF.parse_pdf() --> OFFSET transformation found on line: %s --> %s" % (line_nr, pline))
offset_geo = [float(match.group(1)), float(match.group(2))]
continue
# Detect combined transformation. Must be always the last from transformations to be checked.
# TODO: Perhaps it can replace the others transformation detections
match = self.combined_transform_re.search(pline)
if match:
# transformation = TRANSLATION (OFFSET)
if float(match.group(1)) == 1 and float(match.group(2)) == 0 and \
float(match.group(3)) == 0 and float(match.group(4)) == 1:
pass
# transformation = SCALING
elif float(match.group(2)) == 0 and float(match.group(3)) == 0 and \
float(match.group(5)) == 0 and float(match.group(6)) == 0:
pass
# transformation = ROTATION
elif float(match.group(1)) == float(match.group(4)) and \
float(match.group(2)) == - float(match.group(3)) and \
float(match.group(5)) == 0 and float(match.group(6)) == 0:
# rot_angle = math.acos(float(match.group(1)))
pass
# transformation = SKEW
elif float(match.group(1)) == 1 and float(match.group(4)) == 1 and \
float(match.group(5)) == 0 and float(match.group(6)) == 0:
# skew_x = math.atan(float(match.group(2)))
# skew_y = math.atan(float(match.group(3)))
pass
# transformation combined
else:
log.debug("ToolPDF.parse_pdf() --> COMBINED transformation found on line: %s --> %s" %
(line_nr, pline))
scale_geo = [float(match.group(1)), float(match.group(4))]
offset_geo = [float(match.group(5)), float(match.group(6))]
continue
# PATH CONSTRUCTION #
# Start SUBPATH
match = self.start_subpath_re.search(pline)
if match:
x = float(match.group(1)) + offset_geo[0]
y = float(match.group(2)) + offset_geo[1]
pt = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
start_point = pt
current_point = pt
continue
# Draw Line
match = self.draw_line_re.search(pline)
if match:
x = float(match.group(1)) + offset_geo[0]
y = float(match.group(2)) + offset_geo[1]
pt = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
path['lines'].append(pt)
current_point = pt
continue
# Draw Bezier 'c'
match = self.draw_arc_3pt_re.search(pline)
if match:
start = current_point
x = float(match.group(1)) + offset_geo[0]
y = float(match.group(2)) + offset_geo[1]
c1 = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
x = float(match.group(3)) + offset_geo[0]
y = float(match.group(4)) + offset_geo[1]
c2 = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
x = float(match.group(5)) + offset_geo[0]
y = float(match.group(6)) + offset_geo[1]
stop = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
path['bezier'].append([start, c1, c2, stop])
current_point = stop
continue
# Draw Bezier 'v'
match = self.draw_arc_2pt_c1start_re.search(pline)
if match:
start = current_point
x = float(match.group(1)) + offset_geo[0]
y = float(match.group(2)) + offset_geo[1]
c2 = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
x = float(match.group(3)) + offset_geo[0]
y = float(match.group(4)) + offset_geo[1]
stop = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
path['bezier'].append([start, start, c2, stop])
current_point = stop
continue
# Draw Bezier 'y'
match = self.draw_arc_2pt_c2stop_re.search(pline)
if match:
start = current_point
x = float(match.group(1)) + offset_geo[0]
y = float(match.group(2)) + offset_geo[1]
c1 = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
x = float(match.group(3)) + offset_geo[0]
y = float(match.group(4)) + offset_geo[1]
stop = (x * self.point_to_unit_factor * scale_geo[0], y * self.point_to_unit_factor * scale_geo[1])
path['bezier'].append([start, c1, stop, stop])
current_point = stop
continue
# Close SUBPATH
match = self.end_subpath_re.search(pline)
if match:
flag_close_path = True
continue
# Draw RECTANGLE
match = self.rect_re.search(pline)
if match:
x = (float(match.group(1)) + offset_geo[0]) * self.point_to_unit_factor * scale_geo[0]
y = (float(match.group(2)) + offset_geo[1]) * self.point_to_unit_factor * scale_geo[1]
width = (float(match.group(3)) + offset_geo[0]) * self.point_to_unit_factor * scale_geo[0]
height = (float(match.group(4)) + offset_geo[1]) * self.point_to_unit_factor * scale_geo[1]
pt1 = (x, y)
pt2 = (x+width, y)
pt3 = (x+width, y+height)
pt4 = (x, y+height)
path['rectangle'] += [pt1, pt2, pt3, pt4, pt1]
current_point = pt1
continue
# Detect clipping path set
# ignore this and delete the current subpath
match = self.clip_path_re.search(pline)
if match:
path['lines'] = []
path['bezier'] = []
path['rectangle'] = []
continue
# PATH PAINTING #
# Detect Stroke width / aperture
match = self.strokewidth_re.search(pline)
if match:
size = float(match.group(1)) * self.point_to_unit_factor * scale_geo[0]
flag = 0
if not apertures_dict:
apertures_dict[str(aperture)] = dict()
apertures_dict[str(aperture)]['size'] = size
apertures_dict[str(aperture)]['type'] = 'C'
apertures_dict[str(aperture)]['solid_geometry'] = []
else:
for k in apertures_dict:
if size == apertures_dict[k]['size']:
flag = 1
break
if flag == 0:
aperture += 1
apertures_dict[str(aperture)] = dict()
apertures_dict[str(aperture)]['size'] = size
apertures_dict[str(aperture)]['type'] = 'C'
apertures_dict[str(aperture)]['solid_geometry'] = []
continue
# Detect No_Op command, ignore the current subpath
match = self.no_op_re.search(pline)
if match:
path['lines'] = []
path['bezier'] = []
path['rectangle'] = []
continue
# Stroke the path
match = self.stroke_path__re.search(pline)
if match:
# path['lines'] = []
# path['bezier'] = []
# path['rectangle'] = []
# continue
geo = None
if path['lines']:
path['lines'].insert(0, start_point)
geo = copy(path['lines'])
if flag_close_path:
flag_close_path = False
geo.append(start_point)
path['lines'] = []
if path['bezier']:
geo = list()
geo.append(start_point)
for b in path['bezier']:
geo += self.bezier_to_points(start=b[0], c1=b[1], c2=b[2], stop=b[3])
if flag_close_path:
flag_close_path = False
geo.append(start_point)
path['bezier'] = []
if path['rectangle']:
geo = copy(path['rectangle'])
# if flag_close_path:
# flag_close_path = False
# geo.append(start_point)
path['rectangle'] = []
ext_geo = LineString(geo)
ext_geo = ext_geo.buffer((float(size) / 2), resolution=self.step_per_circles)
# ext_geo = affinity.scale(ext_geo, scale_geo[0], scale_geo[1])
# off_x = offset_geo[0]
# off_y = offset_geo[1]
#
# ext_geo = affinity.translate(ext_geo, off_x, off_y)
try:
apertures_dict[str(aperture)]['solid_geometry'].append(deepcopy(ext_geo))
except KeyError:
# in case there is no stroke width yet therefore no aperture
apertures_dict['0'] = {}
apertures_dict['0']['solid_geometry'] = []
apertures_dict['0']['size'] = size
apertures_dict['0']['type'] = 'C'
apertures_dict['0']['solid_geometry'].append(deepcopy(ext_geo))
continue
# Fill the path
match = self.fill_path_re.search(pline)
match2 = self.fill_stroke_path_re.search(pline)
if match or match2:
geo = None
if path['lines']:
path['lines'].insert(0, start_point)
geo = copy(path['lines'])
geo.append(start_point)
path['lines'] = []
elif path['bezier']:
geo = []
for b in path['bezier']:
geo += self.bezier_to_points(start=b[0], c1=b[1], c2=b[2], stop=b[3])
geo.append(start_point)
path['bezier'] = []
elif path['rectangle']:
# path['rectangle'].append(start_point)
geo = copy(path['rectangle'])
path['rectangle'] = []
ext_geo = Polygon(geo)
ext_geo = ext_geo.buffer(0.000001, resolution=self.step_per_circles)
# ext_geo = affinity.scale(ext_geo, scale_geo[0], scale_geo[1])
# off_x = offset_geo[0]
# off_y = offset_geo[1]
#
# ext_geo = affinity.translate(ext_geo, off_x, off_y)
try:
apertures_dict[str(aperture)]['solid_geometry'].append(deepcopy(ext_geo))
except KeyError:
# in case there is no stroke width yet therefore no aperture
apertures_dict['0'] = {}
apertures_dict['0']['solid_geometry'] = []
apertures_dict['0']['size'] = size
apertures_dict['0']['type'] = 'C'
apertures_dict['0']['solid_geometry'].append(deepcopy(ext_geo))
continue
return apertures_dict
def bezier_to_points(self, start, c1, c2, stop):
""" """
From here: https://gis.stackexchange.com/questions/106937/python-library-or-algorithm-to-generate-arc-geometry-from-three-coordinate-pairs # Equation Bezier, page 184 PDF 1.4 reference
# https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf
# Given the coordinates of the four points, the curve is generated by varying the parameter t from 0.0 to 1.0
# in the following equation:
# R(t) = P0*(1 - t) ** 3 + P1*3*t*(1 - t) ** 2 + P2 * 3*(1 - t) * t ** 2 + P3*t ** 3
# When t = 0.0, the value from the function coincides with the current point P0; when t = 1.0, R(t) coincides
# with the final point P3. Intermediate values of t generate intermediate points along the curve.
# The curve does not, in general, pass through the two control points P1 and P2
:return: LineString geometry :return: LineString geometry
""" """
coords = np.array([[0, 0], [25, 10], [33, 39], [53, 53]])
# equation Bezier, page 184 PDF 1.4 reference # here we store the geometric points
# https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf points = []
# R(t) = P0*(1 - t) ** 3 + P1*3*t*(1 - 5) ** 2 + P2 * 3*(1 - t) * t ** 2 + P3*t ** 3
domain = [] nr_points = np.arange(0.0, 1.0, (1 / self.step_per_circles))
i = 0 for t in nr_points:
while i <=1: term_p0 = (1 - t) ** 3
domain.append(i) term_p1 = 3 * t * (1 - t) ** 2
for i in domain: term_p2 = 3 * (1 - t) * t ** 2
term_p3 = t ** 3
return even_line x = start[0] * term_p0 + c1[0] * term_p1 + c2[0] * term_p2 + stop[0] * term_p3
y = start[1] * term_p0 + c1[1] * term_p1 + c2[1] * term_p2 + stop[1] * term_p3
points.append([x, y])
return points
# def bezier_to_circle(self, path):
# lst = []
# for el in range(len(path)):
# if type(path) is list:
# for coord in path[el]:
# lst.append(coord)
# else:
# lst.append(el)
#
# if lst:
# minx = min(lst, key=lambda t: t[0])[0]
# miny = min(lst, key=lambda t: t[1])[1]
# maxx = max(lst, key=lambda t: t[0])[0]
# maxy = max(lst, key=lambda t: t[1])[1]
# center = (maxx-minx, maxy-miny)
# radius = (maxx-minx) / 2
# return [center, radius]
#
# def circle_to_points(self, center, radius):
# geo = Point(center).buffer(radius, resolution=self.step_per_circles)
# return LineString(list(geo.exterior.coords))
#