diff --git a/.gitignore b/.gitignore index 180e21f..7e802bb 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ lib64/ parts/ sdist/ var/ +.idea/ *.egg-info/ *.eggs/ .installed.cfg @@ -82,4 +83,9 @@ __vm/ *.sln.docstates *.sln *.vcxproj -*.vcxproj.filters \ No newline at end of file +*.vcxproj.filters +old-workspace.jpg + +workspace.png + +workspace.jpg diff --git a/fluxclient/device/discover.py b/fluxclient/device/discover.py index 77e84b0..b4c3b29 100644 --- a/fluxclient/device/discover.py +++ b/fluxclient/device/discover.py @@ -200,10 +200,10 @@ def add_master_key(self, uuid, serial, master_key, disc_ver): if uuid in self.devices: device = self.devices[uuid] if device.master_key != master_key: - raise Exception("Device %s got vart master keys" % device, + raise Exception("Device %s got conflict master keys" % device, device.master_key, master_key) if device.serial != serial: - raise Exception("Device %s got vart master keys" % device, + raise Exception("Device %s got conflict master keys" % device, device.serial, serial) return device else: diff --git a/fluxclient/device/manager_backends/ssl1.py b/fluxclient/device/manager_backends/ssl1.py index f426d5b..5a2f97d 100644 --- a/fluxclient/device/manager_backends/ssl1.py +++ b/fluxclient/device/manager_backends/ssl1.py @@ -14,7 +14,7 @@ __all__ = ["SSL1Backend"] SHORT_PACKER = Struct(" HW_PROFILE['model-1']['radius']: - return 'out_of_bound' - elif float(md.get('MAX_Y', 0)) > HW_PROFILE['model-1']['radius']: - return 'out_of_bound' - elif float(md.get('MAX_R', 0)) > HW_PROFILE['model-1']['radius']: - return 'out_of_bound' - elif float(md.get('MAX_Z', 0)) > HW_PROFILE['model-1']['height'] or float(md.get('MAX_Z', 0)) < 0: - return 'out_of_bound' + if model == 'beambox': + if float(md.get('MAX_X', 0)) > HW_PROFILE[model]['width']: + return 'out_of_bound' + elif float(md.get('MAX_Y', 0)) > HW_PROFILE[model]['length']: + return 'out_of_bound' + elif float(md.get('MAX_Z', 0)) > HW_PROFILE[model]['height'] or float(md.get('MAX_Z', 0)) < 0: + return 'out_of_bound' + else: + return 'ok' else: - return 'ok' + if float(md.get('MAX_X', 0)) > HW_PROFILE[model]['radius']: + return 'out_of_bound' + elif float(md.get('MAX_Y', 0)) > HW_PROFILE[model]['radius']: + return 'out_of_bound' + elif float(md.get('MAX_R', 0)) > HW_PROFILE[model]['radius']: + return 'out_of_bound' + elif float(md.get('MAX_Z', 0)) > HW_PROFILE[model]['height'] or float(md.get('MAX_Z', 0)) < 0: + return 'out_of_bound' + else: + return 'ok' else: self.data = tmp_data return 'broken' diff --git a/fluxclient/hw_profile/__init__.py b/fluxclient/hw_profile/__init__.py index 08b0a82..e8dca68 100644 --- a/fluxclient/hw_profile/__init__.py +++ b/fluxclient/hw_profile/__init__.py @@ -1,5 +1,6 @@ HW_PROFILE = { 'model-1': { + 'plate_shape': 'elliptic', 'radius': 86., 'scan_full_len': 360., 'height': 240., @@ -11,5 +12,28 @@ # min_len_that_step_motor_can_move = 2.5 # step_len = alpha * scan_full_len / N }, + 'beambox': { + 'plate_shape': 'rectangular', + 'width': 400, + 'length': 400, + 'height': 10, + 'radius': 400 + # 'nozzle_height': 4.45, + # 'step_setting': {400: (3, 2.7), 800: (7, 3.15)} + # 'step_setting': {100: (1, 3.6), 200: (1, 1.8), 400: (1, 0.9), 800: (1, 0.45), 1200: (1, 0.3)} + } } # HW_PROFILE['model-1']['radius'] + +class HardwareData(object): + def __init__(self, model): + self.model = model + self._genattr() + + def _genattr(self): + profile = HW_PROFILE.get(self.model) + if not profile: + return None + + for key, val in profile.items(): + setattr(self, key, val) diff --git a/fluxclient/laser/laser_base.py b/fluxclient/laser/laser_base.py index 6af4892..670db82 100755 --- a/fluxclient/laser/laser_base.py +++ b/fluxclient/laser/laser_base.py @@ -33,7 +33,7 @@ def __init__(self): # self.obj_height = 0.0 # plate self.pixel_per_mm = 10 # sample rate for each point - self.radius = 85 # laser max radius = 85mm + self.radius = 150 # laser max radius = 85mm # list holding current image self.reset_image() @@ -250,7 +250,8 @@ def rotate(x, y, rotation, cx=0., cy=0.): # 2 3 ox2, oy2 = ox1, oy3 ox4, oy4 = ox3, oy1 - pix = pix.resize(tuple(map(lambda x: int(x * self.pixel_per_mm), ((ox3 - ox1), (oy1 - oy3))))) + + pix = pix.resize(tuple(map(lambda x: int(x * self.pixel_per_mm), ((ox3 - ox1), (oy3 - oy1))))) # rotate four corner ox1, oy1 = rotate(ox1, oy1, rotation, cx, cy) diff --git a/fluxclient/robot/robot.py b/fluxclient/robot/robot.py index e60e5b7..10711b9 100644 --- a/fluxclient/robot/robot.py +++ b/fluxclient/robot/robot.py @@ -485,6 +485,10 @@ def diagnosis(self, option): def move(self, *ignore, **commands): return self._backend.maintain_move(**commands) + @invalied_validator + def calibrate_beambox_camera(self): + return self._backend.calibrate_beambox_camera() + @invalied_validator def load_filament(self, index=0, temperature=210.0, process_callback=None): diff --git a/fluxclient/robot/robot_backend_2.py b/fluxclient/robot/robot_backend_2.py index df2c3a5..a6e08cc 100644 --- a/fluxclient/robot/robot_backend_2.py +++ b/fluxclient/robot/robot_backend_2.py @@ -162,6 +162,13 @@ def maintain_move(self, *ignore, **commands): if ret != "ok": raise_error(ret) + def calibrate_beambox_camera(self, *ignore, **commands): + ret = self.make_cmd('calibrate_beambox_camera'.encode()) + logger.info("calibrate_beambox_camera!!") + if ret != "ok": + logger.info("Return", ret) + raise_error(ret) + def __load_filament(self, instance, cmd, process_callback): ret = self.make_cmd(cmd) diff --git a/fluxclient/toolpath/__init__.py b/fluxclient/toolpath/__init__.py index e04539d..5c3778a 100644 --- a/fluxclient/toolpath/__init__.py +++ b/fluxclient/toolpath/__init__.py @@ -1,11 +1,12 @@ -from ._toolpath import (ToolpathProcessor, +from fluxclient.toolpath._toolpath import (ToolpathProcessor, PyToolpathProcessor, GCodeMemoryWriter, GCodeFileWriter, FCodeV1FileWriter, FCodeV1MemoryWriter, - GCodeParser) + GCodeParser, + DitheringProcessor) from ._fcode_parser import FCodeParser __all__ = ["ToolpathProcessor", @@ -15,4 +16,5 @@ "FCodeV1FileWriter", "FCodeV1MemoryWriter", "FCodeParser", - "GCodeParser"] + "GCodeParser", + "DitheringProcessor"] diff --git a/fluxclient/toolpath/bitmap_factory.py b/fluxclient/toolpath/bitmap_factory.py index 4d2c3d1..84194e1 100644 --- a/fluxclient/toolpath/bitmap_factory.py +++ b/fluxclient/toolpath/bitmap_factory.py @@ -1,6 +1,48 @@ -from math import sin, cos +from math import sin, cos, tan, pi +import logging +from io import BytesIO + +from PIL import Image, ImageEnhance, ImageOps +from fluxclient.hw_profile import HardwareData from fluxclient.laser.laser_base import LaserBase +logger = logging.getLogger(__name__) + +WORKSPACE_SIZE = 300 # (mm) + + +def recalculate_bound(x1, y1, x2, y2, rotate, image): + rotate = rotate % pi + + if rotate < 0.0087: + return ((x1, y1), (x2, y2), image.convert("RGBA")) + elif rotate - (pi / 2.0) < 0.0087: + cx, cy = ((x1 + x2) / 2.0), ((y1 + y2) / 2.0) + x3 = cx + (y2 - y1) / 2.0 + y3 = cy + (x1 - x2) / 2.0 + x4 = cx - (y2 - y1) / 2.0 + y4 = cy - (x1 - x2) / 2.0 + return ((x3, y3), (x4, y4), image.convert("RGBA").rotate(90, expand=True)) + elif rotate - pi < 0.0087: + return ((x1, y1), (x2, y2), image.convert("RGBA").rotate(180)) + elif rotate - (pi / 2.0 * 3.0): + cx, cy = ((x1 + x2) / 2.0), ((y1 + y2) / 2.0) + x3 = cx + (y2 - y1) / 2.0 + y3 = cy + (x1 - x2) / 2.0 + x4 = cx - (y2 - y1) / 2.0 + y4 = cy - (x1 - x2) / 2.0 + return ((x1, y1), (x2, y2), image.convert("RGBA").rotate(270, expand=True)) + else: + t1 = tan(rotate) + t2 = tan(pi - rotate) + + x3 = ((t1 * x1) - y1 - (t2 * x2) + y2) / (t1 - t2) + y3 = t1 * x3 - t1 * x1 + y1 + x4 = ((t1 * x2) - y2 - (t2 * x1) + y1) / (t1 - t2) + y4 = t2 * x4 - t2 * x1 + y1 + return ((min(x1, x2, x3, x4), max(y1, y2, y3, y4)), + (max(x1, x2, x3, x4), min(y1, y2, y3, y4)), + image.convert("RGBA").rotate(rotate / 180.0 * pi, expand=True)) class BitmapImage(object): @@ -11,6 +53,12 @@ def __init__(self, buf, size, point1, point2, rotation, threshold): self.x2, self.y2 = point2 self.rotation = rotation self.threshold = threshold + self._workspace = None + + @property + def pil_image(self): + return Image.frombytes('L', (self.width, self.height), self.buf) + # return Image.open(BytesIO(self.buf)) def get_bound(self): cx, cy = (self.x1 + self.x2) / 2.0, (self.y1 + self.y2) / 2.0 @@ -30,11 +78,12 @@ def get_bound(self): class BitmapFactory(object): - def __init__(self, radius=85, pixel_per_mm=10): + def __init__(self, radius=150, pixel_per_mm=10): self._magic = LaserBase() self._magic.pixel_per_mm = pixel_per_mm self._magic.radius = radius self._magic.shading = True + self._images = [] @property def pixel_per_mm(self): @@ -44,35 +93,199 @@ def pixel_per_mm(self): def radius(self): return self._magic.radius + def _clear_workspace(self): + self._workspace = None + + def _gen_preview_image(self): + #TODO + pass + def add_image(self, bitmap_image): - self._magic.add_image(bitmap_image.buf, - bitmap_image.width, bitmap_image.height, - bitmap_image.x1, bitmap_image.y1, - bitmap_image.x2, bitmap_image.y2, - bitmap_image.rotation, - bitmap_image.threshold) + self._clear_workspace() + self._gen_preview_image() + # self._magic.add_image(bitmap_image.buf, + # bitmap_image.width, bitmap_image.height, + # bitmap_image.x1, bitmap_image.y1, + # bitmap_image.x2, bitmap_image.y2, + # bitmap_image.rotation, + # bitmap_image.threshold) - def generate_preview(self): - return self._magic.dump(mode="preview") + self._images.append(bitmap_image) - def walk_horizon(self): - ratio = 1 / self.pixel_per_mm + def _crop_image(self, left, upper, right, lower): + pass + + def _delta_image(self): + """ + for temp using, need to be fix. + """ + size = int(WORKSPACE_SIZE * self.pixel_per_mm) + center = int(size / 2) + # Create a (size, size) space + workspace = Image.new("RGBA", (size, size), "white") + + for img in self._images: + c1, c2, rotated_img = recalculate_bound(img.x1, img.y1, img.x2, img.y2, img.rotation, img.pil_image) + + w = abs(int((c2[0] - c1[0]) * self.pixel_per_mm)) + h = abs(int((c1[1] - c2[1]) * self.pixel_per_mm)) + alt_img = rotated_img.resize((w, h)) + + box = [ + int(c1[0] * self.pixel_per_mm + center), + int(center - c1[1] * self.pixel_per_mm), + int(c1[0] * self.pixel_per_mm + center) + w, + int(center - c1[1] * self.pixel_per_mm) + h, + ] + + crop_x0, crop_y0, crop_x1, crop_y1 = 0, 0, alt_img.width, alt_img.height + if box[0] > size or box[1] > size or box[2] < 0 or box[3] < 0: + continue + + if box[0] < 0: + crop_x0 = box[0] * -1 + box[0] = 0 + if box[1] < 0: + crop_y0 = box[1] * -1 + box[1] = 0 + if box[2] > size: + box[2] = size + crop_x1 -= (box[2] - size) + if box[3] > size: + box[3] = size + crop_y1 -= (box[2] - size) + + alt_img = alt_img.crop((crop_x0, crop_y0, crop_x1, crop_y1)) + workspace.paste(alt_img, box=box) + return workspace + + def _get_witdh_length(self, hardware): + if hardware.plate_shape is 'rectangular': + width = round(hardware.width * self.pixel_per_mm) + length = round(hardware.length * self.pixel_per_mm) + elif hardware.plate_shape is 'elliptic': + width = length = round(hardware.radius * self.pixel_per_mm) + return width, length + + def _gen_empty_workspace(self): + hardware = HardwareData('beambox') + width, length = self._get_witdh_length(hardware) + workspace = Image.new("RGBA", (width, length), "white") + return workspace + + def _rotate_img(self, img, degree): + temp_img = img.convert("RGBA").rotate(degree, expand=True) + empty_img = Image.new('RGBA', temp_img.size, "white") + out_img = Image.composite(temp_img, empty_img, temp_img) + return out_img + + def _resize_img(self, img): + temp_x1 = img.x1 * cos(img.rotation) - sin(img.rotation) * img.y1 + temp_y1 = img.x1 * sin(img.rotation) + cos(img.rotation) * img.y1 + temp_x2 = img.x2 * cos(img.rotation) - sin(img.rotation) * img.y2 + temp_y2 = img.x2 * sin(img.rotation) + cos(img.rotation) * img.y2 + + h = round(abs(temp_y2 - temp_y1) * self.pixel_per_mm) + w = round(abs(temp_x2 - temp_x1) * self.pixel_per_mm) - xlen = len(self._magic.image_map[0]) - xoffset = xlen // 2 + resized_img = img.pil_image.resize((w, h)) + return resized_img - # xaxis is bitmap to real world mapping - xaxis = tuple((v * ratio - for v in range(-xoffset, xlen - xoffset))) - xlast = (xlen - xoffset + 1) * ratio + def _cal_corner(self, img, rotated_img): + img_center = ( + ((img.x1 + img.x2) / 2) * self.pixel_per_mm, + ((img.y1 + img.y2) / 2) * self.pixel_per_mm + ) + center = tuple(map(lambda x: x/2, rotated_img.getbbox()[2:])) + corner = (round(img_center[0] - center[0]), round(img_center[1] - center[1])) + return corner + + + def _get_workspace(self): + if self._workspace: + return self._workspace + + workspace = self._gen_empty_workspace() + + for img in self._images: + + #====Enhance test + brightness = ImageEnhance.Brightness(img.pil_image) + bright_img = brightness.enhance(2.0) + bright_img.save("bright2.jpg") + sharpness = ImageEnhance.Sharpness(img.pil_image) + sharp_img = sharpness.enhance(10.0) + sharp_img.save("sharp.jpg") + #====== + + resized_img = self._resize_img(img) + #resized_img.save("resized.jpg", "JPEG") + + rotate = img.rotation * 180 / pi + rotated_img = self._rotate_img(resized_img, rotate) + #rotated_img.save("rotated.jpg", "JPEG") + + corner = self._cal_corner(img, rotated_img) + workspace.paste(rotated_img, box=corner) + mirror_image = ImageOps.mirror(rotated_img) + #workspace.paste(mirror_image, box=corner) + + + + #========mirror test + #mirror = ImageOps.mirror(workspace) + #mirror.save("mirror.jpg", "JPEG") + #============ + workspace.save("workspace.jpg", "JPEG") + #mirror.save("workspace.jpg", "JPEG") + self._workspace = workspace + return workspace + + def generate_preview(self, new_ver=False): + if new_ver: + b = BytesIO() + self._get_workspace().save(b, "png") + return b.getbuffer().tobytes() + else: + return self._magic.dump(mode="preview") + + def walk_spath(self): def x_enum(row): - for ptr_x, x in enumerate(xaxis): - yield x, 255 - row[ptr_x] - yield xlast, 0 - - row_length = len(self._magic.image_map) - ytop = row_length * ratio / 2 - for ptr_y, row in enumerate(self._magic.image_map): - y = ytop - ptr_y * ratio - yield (ptr_y / row_length), y, x_enum(row) + if row % 2 == 0 : + for pixelX in range(workspace.width - 1 , -1, -1 ): + x = round(pixelX * ratio, 2) + val = 255 - workspace.getpixel((pixelX, row)) + #yield x, val + yield x - 300, val + + else: + for pixelX in range(workspace.width): + x = round(pixelX * ratio, 2) + val = 255 - workspace.getpixel((pixelX, row)) + #yield x, val + yield x - 300, val + + ratio = 1 / self.pixel_per_mm + workspace = self._get_workspace().convert("L") + #workspace.save("workspaceL.jpg", "JPEG") + + for ptr_y in range(workspace.height): + progress = ptr_y / workspace.height + y = (ptr_y + 1) * ratio + yield progress, y, x_enum(ptr_y) + + def walk_horizon(self): + def x_enum(row): + for pixelX in range(workspace.width): + x = round(pixelX * ratio, 2) + val = 255 - workspace.getpixel((pixelX, row)) + yield x, val + + ratio = 1 / self.pixel_per_mm + workspace = self._get_workspace().convert("L") + + for ptr_y in range(workspace.height): + progress = ptr_y / workspace.height + y = (ptr_y + 1) * ratio + yield progress, y, x_enum(ptr_y) diff --git a/fluxclient/toolpath/laser.py b/fluxclient/toolpath/laser.py index 8ceed1a..4988381 100644 --- a/fluxclient/toolpath/laser.py +++ b/fluxclient/toolpath/laser.py @@ -16,7 +16,8 @@ def svg2laser(proc, svg_factory, z_height, travel_speed=2400, if current_xy != src_xy: proc.set_toolhead_pwm(0) src_x, src_y = src_xy - proc.moveto(feedrate=travel_speed, x=src_x, y=src_y) + #proc.moveto(feedrate=travel_speed, x=src_x, y=src_y) + proc.moveto(feedrate=engraving_speed, x=src_x, y=src_y) proc.set_toolhead_pwm(engraving_strength) dist_x, dist_y = dist_xy @@ -26,66 +27,157 @@ def svg2laser(proc, svg_factory, z_height, travel_speed=2400, proc.set_toolhead_pwm(0) proc.moveto(feedrate=travel_speed, x=0, y=0) +def svgeditor2laser(proc, svg_factory, z_height, travel_speed=12000, + engraving_strength=1.0, focal_length=6.4, + progress_callback=lambda p: None): + + proc.append_comment("FLUX Laser Svgeditor Tool") + proc.home() + proc.set_toolhead_pwm(0) + #proc.moveto(feedrate=12000, x=0, y=0, z=z_height + focal_length) + current_pwm = 0 + current_y = -999 + current_speed = 0 + current_power_limit = 0 + ending_x = -1 + ACCELERATION_BUFFER_LENGTH = 5 # millimeter + from_left = False + power_limit = 1000 + is_bitmap = False + shading = False + + for strength, args, dist_xy in svg_factory.walk(progress_callback): + if strength < 0: + from_left = args.get("from_left", from_left) + power_limit = args.get("power_limit", power_limit) + is_bitmap = args.get("is_bitmap", is_bitmap) + shading = args.get("shading", shading) + if "shading" in args: + if shading: + print("Enable shading") + proc.set_toolhead_fan_speed(-1) + else: + print("Disable shading") + proc.set_toolhead_fan_speed(1) + continue + else: + speed = args + + speed = speed * 60 + speed = travel_speed if (current_pwm == 0 and not is_bitmap) else speed + pwm = strength / 100.0 + need_to_change = False + current_line_start_engraving_pts = 0 + + if current_pwm != pwm: + current_pwm = pwm + need_to_change = True + + # Pass for non-engraving route + if current_pwm == 0 and not need_to_change: + continue + + if dist_xy == 'done' or dist_xy == 'line': + proc.set_toolhead_pwm(0) + else: + dist_x, dist_y = dist_xy + movement_args = dict(x=dist_x) + + if current_y != dist_y: + # Do x-acceleration buffer + if current_pwm > 0 and is_bitmap and ending_x > -1: + proc.set_toolhead_pwm(0) + if from_left: + buffer_current = dict(x = min(400, ending_x - ACCELERATION_BUFFER_LENGTH), y = current_y, feedrate = travel_speed) + buffer_next = dict(x = max(0, dist_x - ACCELERATION_BUFFER_LENGTH), y = dist_y) + else: + buffer_current = dict(x = min(400, ending_x + ACCELERATION_BUFFER_LENGTH), y = current_y, feedrate = travel_speed) + buffer_next = dict(x = max(0, dist_x + ACCELERATION_BUFFER_LENGTH), y = dist_y) + if buffer_next['x'] < 0: + buffer_next['x'] = 0 + if buffer_next['x'] > 400: + buffer_next['x'] = 400 + proc.moveto(**buffer_current) + proc.moveto(**buffer_next) + current_speed = travel_speed + + current_y = dist_y + movement_args['y'] = dist_y + + + if current_speed != speed: + current_speed = speed + movement_args['feedrate'] = speed + + proc.moveto(**movement_args) + ending_x = dist_x + + if need_to_change: + proc.set_toolhead_pwm(pwm) + if current_power_limit != power_limit: + current_power_limit = power_limit + proc.set_toolhead_pwm(-power_limit) +#================for testing============================================ +# pwm = 0 +# for dist_x, dist_y in svg_factory.walk_cal(): +# if dist_x == 'line': +# pwm = 0 +# elif dist_x % 1 == 0: +# pwm += 1 +# cpwm = cal_pwm(pwm) +# proc.set_toolhead_pwm(cpwm) +# print('result :', cpwm, dist_x, dist_y) +# proc.moveto(feedrate=12000, x=dist_x, y=dist_y) +#======================================================================= def bitmap2laser(proc, bitmap_factory, z_height, one_way=True, - vertical=False, travel_speed=2400, engraving_speed=400, + vertical=False, travel_speed=6000, engraving_speed=400, shading=True, max_engraving_strength=1.0, focal_length=6.4, progress_callback=lambda p: None): - current_pwm = 0 - proc.append_comment("FLUX Laser Bitmap Tool") - proc.set_toolhead_pwm(0) - proc.moveto(feedrate=5000, x=0, y=0, z=z_height + focal_length) - - ptr_width = 0.5 / bitmap_factory.pixel_per_mm - - if shading: - val2pwm = tuple(max_engraving_strength * pow(((i / 255.0)), 0.7) - for i in range(256)) - else: - val2pwm = tuple(0 if i == 0 else max_engraving_strength - for i in range(256)) - - for progress, y, enum in bitmap_factory.walk_horizon(): - progress_callback(progress) - x_bound = (R2 - y * y) ** 0.5 - - # Find first engrave point in row + def gen_val2pwm(): + if shading: + val2pwm = tuple(max_engraving_strength * pow(((i / 255.0)), 0.7) + for i in range(256)) + else: + val2pwm = tuple(0 if i == 0 else max_engraving_strength + for i in range(256)) + return val2pwm + + def moveto_first_enter_point(y, enum): + nonlocal current_pwm for x, val in enum: - if x > -x_bound and val: - proc.moveto(y=y) - - if x - ptr_width > -x_bound: - proc.moveto(feedrate=travel_speed, x=max(x - 3 - ptr_width, - -x_bound)) - proc.moveto(feedrate=travel_speed, x=max(x - ptr_width, - -x_bound)) + if val: + proc.set_toolhead_pwm(0) + #proc.moveto(feedrate=travel_speed, x=x, y=y) + proc.moveto(feedrate=engraving_speed, x=x, y=y) proc.set_toolhead_pwm(val2pwm[val]) current_pwm = val break - # Draw until x over limit + def draw_until_endpoint(y, enum): + nonlocal current_pwm for x, val in enum: - if x + ptr_width > x_bound: - if val != current_pwm: - proc.moveto(feedrate=engraving_speed, x=(x - ptr_width)) - proc.set_toolhead_pwm(val) + if val != current_pwm: + proc.set_toolhead_pwm(val2pwm[current_pwm]) + feedrate = engraving_speed if current_pwm else travel_speed + #proc.moveto(feedrate=feedrate, x=x) + proc.moveto(x=x) + current_pwm = val - if val: - proc.moveto(feedrate=engraving_speed, x=x_bound) - proc.set_toolhead_pwm(0) - current_pwm = 0 - break + current_pwm = 0 + proc.append_comment("FLUX Laser Bitmap Tool") + proc.set_toolhead_pwm(0) + proc.moveto(feedrate=5000, x=0, y=0, z=z_height + focal_length) - else: - if val != current_pwm: - feedrate = engraving_speed if current_pwm else travel_speed - proc.moveto(feedrate=feedrate, x=x - ptr_width) - current_pwm = val - proc.set_toolhead_pwm(val2pwm[current_pwm]) + val2pwm = gen_val2pwm() + #walk_method = bitmap_factory.walk_horizon + walk_method = bitmap_factory.walk_spath - if current_pwm: - proc.set_toolhead_pwm(0) - current_pwm = 0 + for progress, y, enum in walk_method(): + progress_callback(progress) + + moveto_first_enter_point(y, enum) + draw_until_endpoint(y, enum) def laserCalibration(proc, bitmap_factory, z_height, one_way=True, diff --git a/fluxclient/toolpath/svg_factory.py b/fluxclient/toolpath/svg_factory.py index 6ed444d..1528c2f 100644 --- a/fluxclient/toolpath/svg_factory.py +++ b/fluxclient/toolpath/svg_factory.py @@ -1,9 +1,11 @@ +from PIL import Image, ImageDraw +from io import BytesIO from lxml import etree as ET # noqa from fluxclient.laser.laser_base import LaserBase from fluxclient.utils.svg_parser import SVGParser - +from fluxclient.parser._parser import get_all_points class SvgImage(object): _preview_buf = None @@ -36,7 +38,7 @@ def set_image_coordinate(self, point1, point2, rotation): class SvgFactory(object): - def __init__(self, radius=85): + def __init__(self, radius=150): self._magic = LaserBase() self._magic.pixel_per_mm = 10 self._magic.radius = radius @@ -52,13 +54,22 @@ def add_image(self, svg_image): self._svg_images.append(svg_image) def generate_preview(self): - for img in self._svg_images: - if img._preview_buf: - self._magic.add_image(img._preview_buf, - img._preview_width, img._preview_height, - img.x1, img.y1, img.x2, img.y2, - img.rotation, 100) - return self._magic.dump(mode="preview") + img = Image.new('RGBA', (100,100)) + + draw = ImageDraw.Draw(img) + draw.ellipse((25, 25, 75, 75), fill=(255, 0, 0)) + b = BytesIO() + img.save(b, 'png') + image_bytes = b.getvalue() + return image_bytes + + #for img in self._svg_images: + # if img._preview_buf: + # self._magic.add_image(img._preview_buf, + # img._preview_width, img._preview_height, + # img.x1, img.y1, img.x2, img.y2, + # img.rotation, 100) + #return self._magic.dump(mode="preview") def walk(self, progress_callback=lambda p: None): images_length = len(self._svg_images) @@ -72,10 +83,33 @@ def walk(self, progress_callback=lambda p: None): map(float, root.attrib['viewBox'].replace(',', ' ').split()) ) - path_data = SVGParser.elements_to_list(root) + # keys = root.attrib.keys() + # print('keys', keys) +# + # for key in keys: + # root.attrib.pop(key) + # print('after root', root.attrib) + # modify_svg_data = ET.tostring(root) +# + # print('modify_svg_data', modify_svg_data) + + + + + svg_byte_data = str.encode(svg_data) + + path_lst = get_all_points(svg_byte_data) + + + + + + # path_data = SVGParser.elements_to_list(root) + # print('path_data', len(path_data), path_data) + progress_callback(index / images_length) - for each_path in SVGParser.process(path_data, (None, None, + for each_path in SVGParser.process(path_lst, (None, None, image.x1, image.y1, image.x2, image.y2, image.rotation), @@ -88,9 +122,21 @@ def walk(self, progress_callback=lambda p: None): move_to = True else: if move_to: - src_xy = (x, y) + #src_xy = (x, y) + src_xy = (x - 300, y) move_to = False else: - next_xy = (x, y) + #next_xy = (x, y) + next_xy = (x - 300, y) + # print("points") yield src_xy, next_xy src_xy = next_xy + + + '''for each_path in path_lst: + + for index in range(len(each_path)-1): + src_xy = each_path[index] + next_xy = each_path[index+1] + print ((src_xy,next_xy)) + yield src_xy, next_xy''' diff --git a/fluxclient/toolpath/svgeditor_factory.py b/fluxclient/toolpath/svgeditor_factory.py new file mode 100644 index 0000000..35771f5 --- /dev/null +++ b/fluxclient/toolpath/svgeditor_factory.py @@ -0,0 +1,558 @@ +#import cairosvg +import base64 +import re + +import numpy as np + +from PIL import Image, ImageDraw, ImageEnhance +from lxml import etree as ET +from io import BytesIO +from math import floor + +from fluxclient.parser._parser import get_all_points +from fluxclient.hw_profile import HardwareData +from fluxclient.toolpath import DitheringProcessor + +class SvgeditorImage(object): + def __init__(self, thumbnail, svg_data, pixel_per_mm=25, hardware='beambox'): + self.hardware = HardwareData(hardware) + self.pixel_per_mm = pixel_per_mm + + self.buf = svg_data + self.errors = list() + self._groups = list() + self._params = list() + self._tags = dict() + self._definitions = dict() + + self.name_space = 'http://www.w3.org/2000/svg' + self.xlink = 'http://www.w3.org/1999/xlink' + self.svg_init = ''.format( + width=self.hardware.width * 10, + height=self.hardware.length * 10, + ns=self.name_space, + xlink_ns=self.xlink + ) + + self._gen_tags() + self._gen_thumbnail(thumbnail) + #self._gen_thumbnail(svg_data) + self.run() + + @property + def thumbnail(self): + if not self._thumbnail: + self.thumbnail = None + return self._thumbnail + + @property + def groups(self): + return self._groups + + @property + def params(self): + return self._params + + def _gen_tags(self): + tag_list = [ + 'g', + 'title', + 'image', + 'defs', + 'path', + 'symbol', + 'use' + ] + + for tag in tag_list: + self._tags[tag] = "{%s}%s" % (self.name_space, tag) + + def _element_check(self, element, tags): + if isinstance(tags, list): + for tag in tags: + if element.tag == tag: + return True + return False + else: + return element.tag == tags + + def _tag_check(self, element): + for key, value in self._tags.items(): + if element.tag == value: + return str(key) + return False + + def _analysis_group(self, group): + def process_transform_group(element): + nonlocal elements, processedList + el = ET.XML(self.svg_init) + el.append(element) + for elem in el.iter(): + ta = self._tag_check(elem) + processedList.insert(0, ta) + processedList.pop() + return el + + def ignore_processed_element(): + nonlocal processedList + processedList.pop() + + elements = list() + processedList = list() + for element in group.iter(): + if processedList: + ignore_processed_element() + continue + + tag = self._tag_check(element) + if tag is 'g' or tag is 'title': + if element.attrib.get('transform'): + el = process_transform_group(element) + else: + continue + + elif tag is 'image': + el = self._gen_image_data(element) + + elif tag is 'use': + use_data = self._gen_use_data(element) + el = ET.XML(self.svg_init) + el.append(use_data) + + else: + el = ET.XML(self.svg_init) + el.append(element) + + elements.append(el) + return elements + + def _put_into_definitions_space(self, symbol): + _id = symbol.attrib.get('id', None) + if not _id: + return + self._definitions[_id] = symbol + + def _gen_thumbnail(self, thumbnail): + mimetype, data = thumbnail.split(b',') + self._thumbnail = Image.open(BytesIO(base64.b64decode(data))) + self._thumbnail.save('test.png') + + # empty = Image.new("RGBA", (4000, 4000), "white") +# + # output = cairosvg.svg2png(bytestring=thumbnail) + # #self._thumbnail = Image.open(BytesIO(output)) + # img = Image.open(BytesIO(output)) +# + # draw = ImageDraw.Draw(empty) + # line = [0, 100, 4000, 0] + # draw.line(line , fill=(128,128,128), width=3) +# + # empty.paste(img, box=(0,0)) + # self._thumbnail = empty +# + # import ipdb; ipdb.set_trace() + # self._thumbnail.show() + + def _gen_definitions_from_defs(self, tree): + defs_group = tree.findall(".//{%s}defs" % self.name_space) + for defs in defs_group: + for element in defs: + tag = self._tag_check(element) + if tag is 'symbol': + self._put_into_definitions_space(element) + try: + tree.remove(defs) + except: + pass + return tree + + def run(self): + svg_tree = ET.XML(self.buf) + svg_tree = self._gen_definitions_from_defs(svg_tree) + + for elements in svg_tree: + tag = self._tag_check(elements) + if tag is 'g': + params = self._get_params(elements) + self._put_into_params_space(params) + group = self._analysis_group(elements) + self._put_into_group_space(group) + + def _get_buf_and_mimetype(self, dic): + buf_with_mimetype = dic.pop("{%s}href" % self.xlink, "") + dic['mimetype'], dic['buf'] = buf_with_mimetype.split(',') + return dic + + def _put_into_group_space(self, group): + self._groups.append(group) + + def _put_into_params_space(self, params): + self._params.append(params) + + def _analysis_matrix_attrib(self, matrix): + a,b,c,d,e,f = re.findall("\(.*?\)", matrix[0])[0].strip("()").split(",") + a,b,c,d,e,f = map(float, (a,b,c,d,e,f)) + return a,b,c,d,e,f + + def _analysis_transform(self, x, y, transform): + another = list() + matrix = list() + params = re.findall("^.*?\)| .*\)", transform) + for param in params: + param = param.strip() + lis = matrix if re.match("^matrix", param) else another + lis.append(param) + a,b,c,d,e,f = self._analysis_matrix_attrib(matrix) + translate = "matrix(1, 0, 0, 1, {tx}, {ty})".format(tx=x * a, ty=y * d) + transform = "{} {} {}".format(' '.join(another), translate, ' '.join(matrix)) + return transform + + def _cal_transform(self, element): + transform = element.attrib.pop('transform', None) + x = float(element.attrib.pop('x', 0)) + y = float(element.attrib.pop('y', 0)) + transform = self._analysis_transform(x, y, transform) + element.attrib['transform'] = transform + return element + + def _parser_symbol_to_g(self, use, symbol): + use.tag = "{%s}g" % self.name_space + for element in symbol: + use.append(element) + return use + + def _gen_use_data(self, use): + _id = use.attrib.pop("{%s}href" % self.xlink, None) + if _id is None: return + _id = _id.strip('#') + symbol = self._definitions.get(_id, None) + if symbol is None: return + use = self._cal_transform(use) + use = self._parser_symbol_to_g(use, symbol) + return use + + def _gen_image_data(self, image): + dic = dict(zip(image.keys(), image.values())) + dic = self._get_buf_and_mimetype(dic) + bitmap = BitmapImage(dic, self.pixel_per_mm) + return bitmap + + def _get_params(self, group): + strength = group.attrib.get('data-strength', 0.0) + speed = group.attrib.get('data-speed', 200.0) + strength, speed = map(float, (strength, speed)) + return strength, speed + + +class SvgeditorFactory(object): + def __init__ (self, pixel_per_mm=10): + self.pixel_per_mm =pixel_per_mm + + def add_image(self, images, params): + self.groups = list(zip(params, images)) + + def add_thumbnail(self, thumbnail): + self._thumbnail = thumbnail + + def generate_thumbnail(self): + b = BytesIO() + self._thumbnail.save(b, 'png') + image_bytes = b.getvalue() + return image_bytes + + def _is_bitmapImage(self, image): + boolen = True if isinstance(image, BitmapImage) else False + return boolen + + def _gen_svg_walk_path(self, image): + pwm = 100 + svg_data = ET.tostring(image) + paths = get_all_points(svg_data) + for path in paths: + for dist_xy in path: + dist_x, dist_y = dist_xy + dist_x = dist_x / 10 + #==================== + #dist_x = (dist_x - 3000) / 10 + #==================== + dist_y = dist_y / 10 + yield pwm, (dist_x, dist_y) + yield 0.0, (dist_x, dist_y) + + def _filter_threshold(self, val, threshold): + threshold = 255 / 100 * threshold + val = 255 if val >= threshold else 0 + return val + + def _gen_bitmap_walk_path(self, image, progress_callback): + factory = BitmapFactory(pixel_per_mm=self.pixel_per_mm) + factory.add_image(image) + + current_val = 0 + current_from_left = False + for from_left, y, enum in factory.walk_spath(progress_callback): + for x, val in enum: + if not val: + if current_val != 0: + current_val = 0 + if current_from_left != from_left: + current_from_left = from_left + yield -1, dict(from_left=from_left) + yield val, (x, y) + else: + continue + #=============== + # x = x - 300 + #=============== + if not image.shading: + val = self._filter_threshold(val, image.threshold) + + val = (val / 255.0) * 100 + + if val != current_val: + current_val = val + if current_from_left != from_left: + current_from_left = from_left + yield -1, dict(from_left=from_left) + yield val, (x, y) + + if current_from_left != from_left: + current_from_left = from_left + yield -1, dict(from_left=from_left) + yield val, (x,y) + + def _gen_walk_paths(self, group, speed, progress_callback): + for item in group: + if self._is_bitmapImage(item): + yield -1, dict(is_bitmap = True, shading = item.shading), 0 + for strength, args in self._gen_bitmap_walk_path(item, progress_callback): + if strength < 0: + yield -1, args, 0 + else: + yield strength, speed, args + else: + yield -1, dict(is_bitmap = False, shading = False), 0 + for strength, dist_xy in self._gen_svg_walk_path(item): + yield strength, speed, dist_xy + + yield 0.0, speed, 'done' + + def walk(self, progress_callback=lambda p: None): + self.groups.reverse() + + for params, group in self.groups: + layer_power, speed = params + layer_power = layer_power / 100.0 + group.reverse() + yield -1, dict(power_limit=layer_power), 0 + for pwm, args, dist_xy in self._gen_walk_paths( + group, speed, progress_callback): + yield pwm, args, dist_xy + + def walk_cal(self): + ratio = 1 / 20 + for ptr_y in range(200, 220): + y = round(ptr_y * ratio, 2) + for ptr_x in range(100, 5200): + x = round(ptr_x * ratio, 2) + yield x, y + yield 'line', 'line' + +class BitmapImage(object): + def __init__(self, image, pixel_per_mm=10): + self.pixel_per_mm = pixel_per_mm + self.ratio = self.pixel_per_mm / 10 + self.shading = False + self._setAttrs(image) + self._convertToInt() + self.pil_image = Image.open(BytesIO(base64.b64decode(image['buf']))) + self._convertAttrs() + + def _setAttrs(self, image): + for key, value in image.items(): + if key == "data-threshold": + self.threshold = int(value) + elif key == "data-shading": + self.shading = False if value == 'false' else True + + self.__setattr__(key, value) + + def _convertToInt(self): + self.width = round(int(round(float(self.width))) * self.ratio) + self.height = round(int(round(float(self.height))) * self.ratio) + self.x = round(int(round(float(self.x))) * self.ratio) + self.y = round(int(round(float(self.y))) * self.ratio) + + def _convertTransform(self): + if not hasattr(self, 'transform'): + return + params = re.findall("^.*?\)| .*\)", self.transform) + for param in params: + param = param.strip() + key = re.findall("^.*?\(", param) + key = key[0].strip('()') + value = re.findall("\(.*?\)", param) + value = value[0] + self.__setattr__(key, value) + + def _convertRotate(self): + if hasattr(self, 'rotate'): + rotate = self.rotate.strip('()') + ro, ro_x, ro_y = re.split(" |,", rotate) + self.rotate, self.rotate_cx, self.rotate_cy = map(float, (ro, ro_x, ro_y)) + self.rotate_cx, self.rotate_cy = map( + lambda x: x * self.ratio, (self.rotate_cx, self.rotate_cy)) + else: + self.rotate = self.rotate_cx = self.rotate_cy = 0 + + def _convertAttrs(self): + self._convertTransform() + self._convertRotate() + + +class BitmapFactory(object): + def __init__(self, pixel_per_mm=10): + self._image = None + self.pixel_per_mm = pixel_per_mm + self.dithering_processor = DitheringProcessor() + + def _clear_workspace(self): + self._workspace = None + + def add_image(self, bitmap_image): + self._clear_workspace() + self._image = bitmap_image + + def _get_width_length(self, hardware): + if hardware.plate_shape is 'rectangular': + width = round(hardware.width * self.pixel_per_mm) + length = round(hardware.length * self.pixel_per_mm) + elif hardware.plate_shape is 'elliptic': + width = length = round(hardware.radius * self.pixel_per_mm) + return width, length + + def _gen_empty_workspace(self): + hardware = HardwareData('beambox') + width, length = self._get_width_length(hardware) + workspace = Image.new("RGBA", (width, length), "white") + return workspace + + def _rotate_img(self, img, degree): + temp_img = img.convert("RGBA").rotate(degree, expand=True) + empty_img = Image.new('RGBA', temp_img.size, "white") + out_img = Image.composite(temp_img, empty_img, temp_img) + return out_img + + def _cal_corner(self, img, rotated_img): + img_center = (img.x + img.width / 2, img.y + img.height / 2) + center = tuple(map(lambda x: x/2, rotated_img.getbbox()[2:])) + bbox = (round(img_center[0] - center[0]), round(img_center[1] - center[1])) + bbox += (round(img_center[0] + center[0]), round(img_center[1] + center[1])) + return bbox + + def _floyd_steinberg_dither(self, image, progress_callback = lambda p: None): + """ + https://en.wikipedia.org/wiki/Floyd–Steinberg_dithering + Pseudocode: + for each y from top to bottom + for each x from left to right + oldpixel := pixel[x][y] + newpixel := find_closest_palette_color(oldpixel) + pixel[x][y] := newpixel + quant_error := oldpixel - newpixel + pixel[x+1][y ] := pixel[x+1][y ] + quant_error * 7/16 + pixel[x-1][y+1] := pixel[x-1][y+1] + quant_error * 3/16 + pixel[x ][y+1] := pixel[x ][y+1] + quant_error * 5/16 + pixel[x+1][y+1] := pixel[x+1][y+1] + quant_error * 1/16 + find_closest_palette_color(oldpixel) = floor(oldpixel / 256) + """ + + data = np.array(image) + + progress_callback("Dithering", 0.5) + + self.dithering_processor.dither(data) + + return Image.fromarray(data, 'RGBA') + + def _get_workspace(self, progress_callback = lambda p: None): + if self._workspace: + return self._workspace + + workspace = self._gen_empty_workspace() + img = self._image + + resized_img = img.pil_image.resize((img.width, img.height)) + print("Resizing image - ", img.width, img.height) + rotated_img = self._rotate_img(resized_img, -img.rotate) + if img.shading: + print("Dithering image - ", img.width, img.height) + rotated_img = self._floyd_steinberg_dither(rotated_img, progress_callback) + print("Calculating Image - ", img.width, img.height) + workspace.imgbbox = self._cal_corner(img, rotated_img) + workspace.paste(rotated_img, box=workspace.imgbbox[:2]) + # workspace.save('workspace.png', 'JPEG') + + self._workspace = workspace + return workspace + + def walk_spath(self, progress_callback): + fromLeft = True + def find_the_bbox(box, workspace): + left, upper, right, lower = box + left = 0 if left < 0 else left + upper = 0 if upper < 0 else upper + right = workspace.width - 1 if right > workspace.width else right + lower = workspace.height - 1 if lower > workspace.height else lower + return (left, upper, right, lower) + + def x_enum(row): + nonlocal fromLeft + if not fromLeft: + fromLeft = True + for pixelX in range(right , left, -1 ): + x = round(pixelX * ratio, 2) + val = 255 - workspace.getpixel((pixelX, row)) + yield x, val + + else: + fromLeft = False + for pixelX in range(left, right): + x = round(pixelX * ratio, 2) + val = 255 - workspace.getpixel((pixelX, row)) + yield x, val + + ratio = 1 / self.pixel_per_mm + workspace = self._get_workspace(progress_callback).convert("L") + #workspace = self._get_workspace().convert("1") + left, upper, right, lower = self._get_workspace().imgbbox + left, upper, right, lower = find_the_bbox( + (left, upper, right, lower), workspace) + workspace.save("workspace.jpg", "JPEG") + + for ptr_y in range(upper, lower): + progress_callback("Calculating Toolpath - " + str(round( (upper - ptr_y) * 100 / (upper - lower) )) + "%", (upper - ptr_y) / (upper - lower)) + #progress = ptr_y / workspace.height + y = round(ptr_y * ratio, 2) + #yield progress, y, x_enum(ptr_y) + yield fromLeft, y, x_enum(ptr_y) + + def walk_horizon(self): + def x_enum(row): + for pixelX in range(workspace.width): + x = round(pixelX * ratio, 2) + val = 255 - workspace.getpixel((pixelX, row)) + yield x, val + + ratio = 1 / self.pixel_per_mm + workspace = self._get_workspace().convert("L") + + for ptr_y in range(workspace.height): + #progress = ptr_y / workspace.height + y = round(ptr_y * ratio, 2) + #yield progress, y, x_enum(ptr_y) + yield y, x_enum(ptr_y) + +if __name__ == "__main__": + import ipdb; ipdb.set_trace() + pass diff --git a/fluxclient/utils/svg_parser.py b/fluxclient/utils/svg_parser.py index acedbac..5af8065 100644 --- a/fluxclient/utils/svg_parser.py +++ b/fluxclient/utils/svg_parser.py @@ -665,6 +665,7 @@ def process(path_data, params, viewBox, radius): new_path.append([x2, y2]) continue out = 0 # flag show how the point's are out of viewBox, using binary encoding + if x1 < viewBox[0] or x1 > viewBox[0] + viewBox[2] or y1 < viewBox[1] or y1 > viewBox[1] + viewBox[3]: out += 1 if x2 < viewBox[0] or x2 > viewBox[0] + viewBox[2] or y2 < viewBox[1] or y2 > viewBox[1] + viewBox[3]: @@ -790,80 +791,84 @@ def process(path_data, params, viewBox, radius): else: pass + path_data[path] = new_path + # make every points inside the boundary circle -> (cx, cy, r) = (0, 0, radius) - in_path = [] - for i in range(1, len(new_path)): - if new_path[i - 1][0] == '\n': - fake_x, fake_y = new_path[i] - else: - fake_x, fake_y = new_path[i - 1] # record where head should be as if there's no boundary - if new_path[i][0] != '\n': - flag = 0 - if new_path[i][0] ** 2 + new_path[i][1] ** 2 > radius ** 2: - flag += 1 - if fake_x ** 2 + fake_y ** 2 > radius ** 2: - flag += 2 - - if flag == 0: # both inside the circle - in_path.append(new_path[i - 1]) - in_path.append(new_path[i]) - else: - # find the intersection point between vector a->b and circle - # a = (x1, y1), b = (x2, y2), circle = (0, 0, r) - # (x1 + t*(x2-x1))^2 + (y1 + t(y2-y1))^2 = r^2 - # solve t, and find the proper sign for it - x1, y1 = fake_x, fake_y - x2, y2 = new_path[i] - if x1 == x2 and y1 == y2: - continue - # (-b +- sqrt(b^2-4ac)) / 2a - a = (x2 - x1) ** 2 + (y2 - y1) ** 2 - b = 2 * ((x1 * x2) - (x1 ** 2) + (y1 * y2) - (y1 ** 2)) - c = (x1 ** 2) + (y1 ** 2) - (radius ** 2) - - if (b ** 2) - (4 * a * c) >= 0: # solvable - t_p = (-b + sqrt((b ** 2) - (4 * a * c))) / (2 * a) - t_n = (-b - sqrt((b ** 2) - (4 * a * c))) / (2 * a) - v = [x2 - x1, y2 - y1] - if flag == 1: # in to out - in_path.append([fake_x, fake_y]) - t = t_p if abs(t_p) < 1 else t_n # must be inner division point - in_path.append([fake_x + t * v[0], fake_y + t * v[1]]) - in_path.append(['\n', '\n']) - elif flag == 2: # out to in - t = t_p if abs(t_p) < 1 else t_n # must be inner division point - in_path.append(['\n', '\n']) - in_path.append([fake_x + t * v[0], fake_y + t * v[1]]) - in_path.append([new_path[i][0], new_path[i][1]]) - elif flag == 3: # both out - if abs(t_p) < 1 and abs(t_n) < 1: # must be inner division point - in_path.append(['\n', '\n']) - in_path.append([fake_x + t_n * v[0], fake_y + t_n * v[1]]) - in_path.append([fake_x + t_p * v[0], fake_y + t_p * v[1]]) - in_path.append(['\n', '\n']) - else: # insoluble - pass - else: - in_path.append(new_path[i]) + # in_path = [] + # for i in range(1, len(new_path)): + # if new_path[i - 1][0] == '\n': + # fake_x, fake_y = new_path[i] + # else: + # fake_x, fake_y = new_path[i - 1] # record where head should be as if there's no boundary + # if new_path[i][0] != '\n': + # flag = 0 + # if new_path[i][0] ** 2 + new_path[i][1] ** 2 > radius ** 2: + # flag += 1 + # if fake_x ** 2 + fake_y ** 2 > radius ** 2: + # flag += 2 +# + # if flag == 0: # both inside the circle + # in_path.append(new_path[i - 1]) + # in_path.append(new_path[i]) + # else: + # # find the intersection point between vector a->b and circle + # # a = (x1, y1), b = (x2, y2), circle = (0, 0, r) + # # (x1 + t*(x2-x1))^2 + (y1 + t(y2-y1))^2 = r^2 + # # solve t, and find the proper sign for it + # x1, y1 = fake_x, fake_y + # x2, y2 = new_path[i] + # if x1 == x2 and y1 == y2: + # continue + # # (-b +- sqrt(b^2-4ac)) / 2a + # a = (x2 - x1) ** 2 + (y2 - y1) ** 2 + # b = 2 * ((x1 * x2) - (x1 ** 2) + (y1 * y2) - (y1 ** 2)) + # c = (x1 ** 2) + (y1 ** 2) - (radius ** 2) +# + # if (b ** 2) - (4 * a * c) >= 0: # solvable + # t_p = (-b + sqrt((b ** 2) - (4 * a * c))) / (2 * a) + # t_n = (-b - sqrt((b ** 2) - (4 * a * c))) / (2 * a) + # v = [x2 - x1, y2 - y1] + # if flag == 1: # in to out + # in_path.append([fake_x, fake_y]) + # t = t_p if abs(t_p) < 1 else t_n # must be inner division point + # in_path.append([fake_x + t * v[0], fake_y + t * v[1]]) + # in_path.append(['\n', '\n']) + # elif flag == 2: # out to in + # t = t_p if abs(t_p) < 1 else t_n # must be inner division point + # in_path.append(['\n', '\n']) + # in_path.append([fake_x + t * v[0], fake_y + t * v[1]]) + # in_path.append([new_path[i][0], new_path[i][1]]) + # elif flag == 3: # both out + # if abs(t_p) < 1 and abs(t_n) < 1: # must be inner division point + # in_path.append(['\n', '\n']) + # in_path.append([fake_x + t_n * v[0], fake_y + t_n * v[1]]) + # in_path.append([fake_x + t_p * v[0], fake_y + t_p * v[1]]) + # in_path.append(['\n', '\n']) + # else: # insoluble + # pass + # else: + # in_path.append(new_path[i]) +# + # # delete redundant points + # if len(in_path) > 0: + # tmp = [in_path[0]] + # for i in in_path: + # if tmp[-1] != i: + # tmp.append(i) + # in_path = tmp +# + # path_data[path] = in_path - # delete redundant points - if len(in_path) > 0: - tmp = [in_path[0]] - for i in in_path: - if tmp[-1] != i: - tmp.append(i) - in_path = tmp - - path_data[path] = in_path return path_data + if __name__ == '__main__': import sys with open(sys.argv[1], 'rt', encoding="utf-8") as f: buf = f.read() parser = ET.XMLParser(encoding="utf-8") root = ET.fromstring(buf, parser=parser) - print(ET.tostring(root, pretty_print=True).decode('utf8')) + #print(ET.tostring(root, pretty_print=True).decode('utf8')) # # with open(sys.argv[1], 'rb') as f: # with open(sys.argv[1], 'rb') as f: diff --git a/setup_utils.py b/setup_utils.py index 87ab9b8..1f2428b 100644 --- a/setup_utils.py +++ b/setup_utils.py @@ -5,6 +5,7 @@ import platform import sys import os +import numpy try: from Cython.Distutils import build_ext # noqa @@ -129,7 +130,8 @@ def create_utils_extentions(): "src/toolpath/_toolpath.pyx" ], language="c++", - extra_compile_args=get_default_extra_compile_args()), + extra_compile_args=get_default_extra_compile_args(), + include_dirs=[numpy.get_include()]), Extension( 'fluxclient.utils._utils', sources=[ @@ -284,4 +286,13 @@ def find_in_program_files(label, names): include_dirs=["src/printer/"] )) + extensions.append(Extension( + 'fluxclient.parser._parser', + sources = [ + "src/svg_parser/nanosvg.c", + "src/svg_parser/svg_parser.pyx" + ] + + )) + return extensions diff --git a/src/svg_parser/nanosvg.c b/src/svg_parser/nanosvg.c new file mode 100644 index 0000000..5fee8d2 --- /dev/null +++ b/src/svg_parser/nanosvg.c @@ -0,0 +1,2722 @@ + + +#include +#include +#include +#include "nanosvg.h" +#include + +static int nsvg__isspace(char c) +{ + return strchr(" \t\n\v\f\r", c) != 0; +} + +static int nsvg__isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int nsvg__isnum(char c) +{ + return strchr("0123456789+-.eE", c) != 0; +} + +static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } +static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } + + +// Simple XML parser + +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 +#define NSVG_XML_MAX_ATTRIBS 256 + +static void nsvg__parseContent(char* s, + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + // Trim start white spaces + while (*s && nsvg__isspace(*s)) s++; + if (!*s) return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char* s, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void* ud) +{ + const char* attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char* name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (*s && nsvg__isspace(*s)) s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) s++; + if (*s) { *s++ = '\0'; } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { + char* name = NULL; + char* value = NULL; + + // Skip white space before the attrib name + while (*s && nsvg__isspace(*s)) s++; + if (!*s) break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') s++; + if (*s) { *s++ = '\0'; } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') s++; + if (!*s) break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) s++; + if (*s) { *s++ = '\0'; } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +int nsvg__parseXML(char* input, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + char* s = input; + char* mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } + + return 1; +} + + +/* Simple SVG parser. */ + +#define NSVG_MAX_ATTR 128 + +enum NSVGgradientUnits { + NSVG_USER_SPACE = 0, + NSVG_OBJECT_SPACE = 1 +}; + +#define NSVG_MAX_DASHES 8 + +enum NSVGunits { + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX +}; + +typedef struct NSVGcoordinate { + float value; + int units; +} NSVGcoordinate; + +typedef struct NSVGlinearData { + NSVGcoordinate x1, y1, x2, y2; +} NSVGlinearData; + +typedef struct NSVGradialData { + NSVGcoordinate cx, cy, r, fx, fy; +} NSVGradialData; + +typedef struct NSVGgradientData +{ + char id[64]; + char ref[64]; + char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop* stops; + struct NSVGgradientData* next; +} NSVGgradientData; + +typedef struct NSVGattrib +{ + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; +} NSVGattrib; + +typedef struct NSVGparser +{ + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float* pts; + int npts; + int cpts; + NSVGpath* plist; + NSVGimage* image; + NSVGgradientData* gradients; + NSVGshape* shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; +} NSVGparser; + +static void nsvg__xformIdentity(float* t) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float* t, float tx, float ty) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = tx; t[5] = ty; +} + +static void nsvg__xformSetScale(float* t, float sx, float sy) +{ + t[0] = sx; t[1] = 0.0f; + t[2] = 0.0f; t[3] = sy; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float* t, float a) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = tanf(a); t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float* t, float a) +{ + t[0] = 1.0f; t[1] = tanf(a); + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float* t, float a) +{ + float cs = cosf(a), sn = sinf(a); + t[0] = cs; t[1] = sn; + t[2] = -sn; t[3] = cs; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float* t, float* s) +{ + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float* inv, float* t) +{ + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float* t, float* s) +{ + float s2[6]; + memcpy(s2, s, sizeof(float)*6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float)*6); +} + +static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2] + t[4]; + *dy = x*t[1] + y*t[3] + t[5]; +} + +static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2]; + *dy = x*t[1] + y*t[3]; +} + +#define NSVG_EPSILON (1e-12) + +static int nsvg__ptInBounds(float* pt, float* bounds) +{ + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) +{ + double it = 1.0-t; + return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; +} + +static void nsvg__curveBounds(float* bounds, float* curve) +{ + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float* v0 = &curve[0]; + float* v1 = &curve[2]; + float* v2 = &curve[4]; + float* v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b*b - 4.0*c*a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); + bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); + } + } +} + +static NSVGparser* nsvg__createParser() +{ + NSVGparser* p; + p = (NSVGparser*)malloc(sizeof(NSVGparser)); + if (p == NULL) goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); + if (p->image == NULL) goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0,0,0); + p->attr[0].strokeColor = NSVG_RGB(0,0,0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; + +error: + if (p) { + if (p->image) free(p->image); + free(p); + } + return NULL; +} + +static void nsvg__deletePaths(NSVGpath* path) +{ + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } +} + +static void nsvg__deletePaint(NSVGpaint* paint) +{ + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); +} + +static void nsvg__deleteGradientData(NSVGgradientData* grad) +{ + NSVGgradientData* next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser* p) +{ + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser* p) +{ + p->npts = 0; +} + +static void nsvg__addPoint(NSVGparser* p, float x, float y) +{ + if (p->npts+1 > p->cpts) { + p->cpts = p->cpts ? p->cpts*2 : 8; + p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); + if (!p->pts) return; + } + p->pts[p->npts*2+0] = x; + p->pts[p->npts*2+1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser* p, float x, float y) +{ + if (p->npts > 0) { + p->pts[(p->npts-1)*2+0] = x; + p->pts[(p->npts-1)*2+1] = y; + } else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser* p, float x, float y) +{ + float px,py, dx,dy; + if (p->npts > 0) { + px = p->pts[(p->npts-1)*2+0]; + py = p->pts[(p->npts-1)*2+1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); + nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) +{ + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); +} + +static NSVGattrib* nsvg__getAttr(NSVGparser* p) +{ + return &p->attr[p->attrHead]; +} + +static void nsvg__pushAttr(NSVGparser* p) +{ + if (p->attrHead < NSVG_MAX_ATTR-1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser* p) +{ + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser* p) +{ + return p->viewMinx; +} + +static float nsvg__actualOrigY(NSVGparser* p) +{ + return p->viewMiny; +} + +static float nsvg__actualWidth(NSVGparser* p) +{ + return p->viewWidth; +} + +static float nsvg__actualHeight(NSVGparser* p) +{ + return p->viewHeight; +} + +static float nsvg__actualLength(NSVGparser* p) +{ + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w*w + h*h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) +{ + NSVGattrib* attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: return c.value; + case NSVG_UNITS_PX: return c.value; + case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: return c.value * p->dpi; + case NSVG_UNITS_EM: return c.value * attr->fontSize; + case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; + default: return c.value; + } + return c.value; +} + +static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) +{ + NSVGgradientData* grad = p->gradients; + while (grad) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGgradientData* data = NULL; + NSVGgradientData* ref = NULL; + NSVGgradientStop* stops = NULL; + NSVGgradient* grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + + data = nsvg__findGradientData(p, id); + if (data == NULL) return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + while (ref != NULL) { + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + ref = nsvg__findGradientData(p, ref->ref); + } + if (stops == NULL) return NULL; + + grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); + if (grad == NULL) return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; grad->xform[1] = -dx; + grad->xform[2] = dx; grad->xform[3] = dy; + grad->xform[4] = x1; grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; grad->xform[1] = 0; + grad->xform[2] = 0; grad->xform[3] = r; + grad->xform[4] = cx; grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, attr->xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float* t) +{ + float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); + float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) +{ + NSVGpath* path; + float curve[4*2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts-1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser* p) +{ + NSVGattrib* attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape* shape; + NSVGpath* path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape*)malloc(sizeof(NSVGshape)); + if (shape == NULL) goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; + } else if (attr->hasFill == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); + if (shape->fill.gradient == NULL) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; + } else if (attr->hasStroke == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); + if (shape->stroke.gradient == NULL) + shape->stroke.type = NSVG_PAINT_NONE; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; + +error: + if (shape) free(shape); +} + +static void nsvg__addPath(NSVGparser* p, char closed) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGpath* path = NULL; + float bounds[4]; + float* curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + path = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (path == NULL) goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (path->pts == NULL) goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts-1; i += 3) { + curve = &path->pts[i*2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; + +error: + if (path != NULL) { + if (path->pts != NULL) free(path->pts); + free(path); + } +} + +// We roll our own string to float because the std library one uses locale and messes things up. +static double nsvg__atof(const char* s) +{ + char* cur = (char*)s; + char* end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = (double)strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + int expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + + +static const char* nsvg__parseNumber(const char* s, char* it, const int size) +{ + const int last = size-1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + // integer part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) it[i++] = *s; + s++; + // fraction part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + // exponent + if (*s == 'e' || *s == 'E') { + if (i < last) it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char* nsvg__getNextPathItem(const char* s, char* it) +{ + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char* str) +{ + unsigned int c = 0, r = 0, g = 0, b = 0; + int n = 0; + str++; // skip # + // Calculate number of characters. + while(str[n] && !nsvg__isspace(str[n])) + n++; + if (n == 6) { + sscanf(str, "%x", &c); + } else if (n == 3) { + sscanf(str, "%x", &c); + c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); + c |= c<<4; + } + r = (c >> 16) & 0xff; + g = (c >> 8) & 0xff; + b = c & 0xff; + return NSVG_RGB(r,g,b); +} + +static unsigned int nsvg__parseColorRGB(const char* str) +{ + int r = -1, g = -1, b = -1; + char s1[32]="", s2[32]=""; + sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); + if (strchr(s1, '%')) { + return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); + } else { + return NSVG_RGB(r,g,b); + } +} + +typedef struct NSVGNamedColor { + const char* name; + unsigned int color; +} NSVGNamedColor; + +NSVGNamedColor nsvg__colors[] = { + + { "red", NSVG_RGB(255, 0, 0) }, + { "green", NSVG_RGB( 0, 128, 0) }, + { "blue", NSVG_RGB( 0, 0, 255) }, + { "yellow", NSVG_RGB(255, 255, 0) }, + { "cyan", NSVG_RGB( 0, 255, 255) }, + { "magenta", NSVG_RGB(255, 0, 255) }, + { "black", NSVG_RGB( 0, 0, 0) }, + { "grey", NSVG_RGB(128, 128, 128) }, + { "gray", NSVG_RGB(128, 128, 128) }, + { "white", NSVG_RGB(255, 255, 255) }, + +#ifdef NANOSVG_ALL_COLOR_KEYWORDS + { "aliceblue", NSVG_RGB(240, 248, 255) }, + { "antiquewhite", NSVG_RGB(250, 235, 215) }, + { "aqua", NSVG_RGB( 0, 255, 255) }, + { "aquamarine", NSVG_RGB(127, 255, 212) }, + { "azure", NSVG_RGB(240, 255, 255) }, + { "beige", NSVG_RGB(245, 245, 220) }, + { "bisque", NSVG_RGB(255, 228, 196) }, + { "blanchedalmond", NSVG_RGB(255, 235, 205) }, + { "blueviolet", NSVG_RGB(138, 43, 226) }, + { "brown", NSVG_RGB(165, 42, 42) }, + { "burlywood", NSVG_RGB(222, 184, 135) }, + { "cadetblue", NSVG_RGB( 95, 158, 160) }, + { "chartreuse", NSVG_RGB(127, 255, 0) }, + { "chocolate", NSVG_RGB(210, 105, 30) }, + { "coral", NSVG_RGB(255, 127, 80) }, + { "cornflowerblue", NSVG_RGB(100, 149, 237) }, + { "cornsilk", NSVG_RGB(255, 248, 220) }, + { "crimson", NSVG_RGB(220, 20, 60) }, + { "darkblue", NSVG_RGB( 0, 0, 139) }, + { "darkcyan", NSVG_RGB( 0, 139, 139) }, + { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, + { "darkgray", NSVG_RGB(169, 169, 169) }, + { "darkgreen", NSVG_RGB( 0, 100, 0) }, + { "darkgrey", NSVG_RGB(169, 169, 169) }, + { "darkkhaki", NSVG_RGB(189, 183, 107) }, + { "darkmagenta", NSVG_RGB(139, 0, 139) }, + { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, + { "darkorange", NSVG_RGB(255, 140, 0) }, + { "darkorchid", NSVG_RGB(153, 50, 204) }, + { "darkred", NSVG_RGB(139, 0, 0) }, + { "darksalmon", NSVG_RGB(233, 150, 122) }, + { "darkseagreen", NSVG_RGB(143, 188, 143) }, + { "darkslateblue", NSVG_RGB( 72, 61, 139) }, + { "darkslategray", NSVG_RGB( 47, 79, 79) }, + { "darkslategrey", NSVG_RGB( 47, 79, 79) }, + { "darkturquoise", NSVG_RGB( 0, 206, 209) }, + { "darkviolet", NSVG_RGB(148, 0, 211) }, + { "deeppink", NSVG_RGB(255, 20, 147) }, + { "deepskyblue", NSVG_RGB( 0, 191, 255) }, + { "dimgray", NSVG_RGB(105, 105, 105) }, + { "dimgrey", NSVG_RGB(105, 105, 105) }, + { "dodgerblue", NSVG_RGB( 30, 144, 255) }, + { "firebrick", NSVG_RGB(178, 34, 34) }, + { "floralwhite", NSVG_RGB(255, 250, 240) }, + { "forestgreen", NSVG_RGB( 34, 139, 34) }, + { "fuchsia", NSVG_RGB(255, 0, 255) }, + { "gainsboro", NSVG_RGB(220, 220, 220) }, + { "ghostwhite", NSVG_RGB(248, 248, 255) }, + { "gold", NSVG_RGB(255, 215, 0) }, + { "goldenrod", NSVG_RGB(218, 165, 32) }, + { "greenyellow", NSVG_RGB(173, 255, 47) }, + { "honeydew", NSVG_RGB(240, 255, 240) }, + { "hotpink", NSVG_RGB(255, 105, 180) }, + { "indianred", NSVG_RGB(205, 92, 92) }, + { "indigo", NSVG_RGB( 75, 0, 130) }, + { "ivory", NSVG_RGB(255, 255, 240) }, + { "khaki", NSVG_RGB(240, 230, 140) }, + { "lavender", NSVG_RGB(230, 230, 250) }, + { "lavenderblush", NSVG_RGB(255, 240, 245) }, + { "lawngreen", NSVG_RGB(124, 252, 0) }, + { "lemonchiffon", NSVG_RGB(255, 250, 205) }, + { "lightblue", NSVG_RGB(173, 216, 230) }, + { "lightcoral", NSVG_RGB(240, 128, 128) }, + { "lightcyan", NSVG_RGB(224, 255, 255) }, + { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, + { "lightgray", NSVG_RGB(211, 211, 211) }, + { "lightgreen", NSVG_RGB(144, 238, 144) }, + { "lightgrey", NSVG_RGB(211, 211, 211) }, + { "lightpink", NSVG_RGB(255, 182, 193) }, + { "lightsalmon", NSVG_RGB(255, 160, 122) }, + { "lightseagreen", NSVG_RGB( 32, 178, 170) }, + { "lightskyblue", NSVG_RGB(135, 206, 250) }, + { "lightslategray", NSVG_RGB(119, 136, 153) }, + { "lightslategrey", NSVG_RGB(119, 136, 153) }, + { "lightsteelblue", NSVG_RGB(176, 196, 222) }, + { "lightyellow", NSVG_RGB(255, 255, 224) }, + { "lime", NSVG_RGB( 0, 255, 0) }, + { "limegreen", NSVG_RGB( 50, 205, 50) }, + { "linen", NSVG_RGB(250, 240, 230) }, + { "maroon", NSVG_RGB(128, 0, 0) }, + { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, + { "mediumblue", NSVG_RGB( 0, 0, 205) }, + { "mediumorchid", NSVG_RGB(186, 85, 211) }, + { "mediumpurple", NSVG_RGB(147, 112, 219) }, + { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, + { "mediumslateblue", NSVG_RGB(123, 104, 238) }, + { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, + { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, + { "mediumvioletred", NSVG_RGB(199, 21, 133) }, + { "midnightblue", NSVG_RGB( 25, 25, 112) }, + { "mintcream", NSVG_RGB(245, 255, 250) }, + { "mistyrose", NSVG_RGB(255, 228, 225) }, + { "moccasin", NSVG_RGB(255, 228, 181) }, + { "navajowhite", NSVG_RGB(255, 222, 173) }, + { "navy", NSVG_RGB( 0, 0, 128) }, + { "oldlace", NSVG_RGB(253, 245, 230) }, + { "olive", NSVG_RGB(128, 128, 0) }, + { "olivedrab", NSVG_RGB(107, 142, 35) }, + { "orange", NSVG_RGB(255, 165, 0) }, + { "orangered", NSVG_RGB(255, 69, 0) }, + { "orchid", NSVG_RGB(218, 112, 214) }, + { "palegoldenrod", NSVG_RGB(238, 232, 170) }, + { "palegreen", NSVG_RGB(152, 251, 152) }, + { "paleturquoise", NSVG_RGB(175, 238, 238) }, + { "palevioletred", NSVG_RGB(219, 112, 147) }, + { "papayawhip", NSVG_RGB(255, 239, 213) }, + { "peachpuff", NSVG_RGB(255, 218, 185) }, + { "peru", NSVG_RGB(205, 133, 63) }, + { "pink", NSVG_RGB(255, 192, 203) }, + { "plum", NSVG_RGB(221, 160, 221) }, + { "powderblue", NSVG_RGB(176, 224, 230) }, + { "purple", NSVG_RGB(128, 0, 128) }, + { "rosybrown", NSVG_RGB(188, 143, 143) }, + { "royalblue", NSVG_RGB( 65, 105, 225) }, + { "saddlebrown", NSVG_RGB(139, 69, 19) }, + { "salmon", NSVG_RGB(250, 128, 114) }, + { "sandybrown", NSVG_RGB(244, 164, 96) }, + { "seagreen", NSVG_RGB( 46, 139, 87) }, + { "seashell", NSVG_RGB(255, 245, 238) }, + { "sienna", NSVG_RGB(160, 82, 45) }, + { "silver", NSVG_RGB(192, 192, 192) }, + { "skyblue", NSVG_RGB(135, 206, 235) }, + { "slateblue", NSVG_RGB(106, 90, 205) }, + { "slategray", NSVG_RGB(112, 128, 144) }, + { "slategrey", NSVG_RGB(112, 128, 144) }, + { "snow", NSVG_RGB(255, 250, 250) }, + { "springgreen", NSVG_RGB( 0, 255, 127) }, + { "steelblue", NSVG_RGB( 70, 130, 180) }, + { "tan", NSVG_RGB(210, 180, 140) }, + { "teal", NSVG_RGB( 0, 128, 128) }, + { "thistle", NSVG_RGB(216, 191, 216) }, + { "tomato", NSVG_RGB(255, 99, 71) }, + { "turquoise", NSVG_RGB( 64, 224, 208) }, + { "violet", NSVG_RGB(238, 130, 238) }, + { "wheat", NSVG_RGB(245, 222, 179) }, + { "whitesmoke", NSVG_RGB(245, 245, 245) }, + { "yellowgreen", NSVG_RGB(154, 205, 50) }, +#endif +}; + +static unsigned int nsvg__parseColorName(const char* str) +{ + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char* str) +{ + size_t len = 0; + while(*str == ' ') ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char* str) +{ + float val = 0; + sscanf(str, "%f", &val); + if (val < 0.0f) val = 0.0f; + if (val > 1.0f) val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char* str) +{ + float val = 0; + sscanf(str, "%f", &val); + if (val < 0.0f) val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char* units) +{ + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) +{ + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char units[32]=""; + sscanf(str, "%f%31s", &coord.value, units); + coord.units = nsvg__parseUnits(units); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) +{ + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) +{ + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) +{ + const char* end; + const char* ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); +} + + +static int nsvg__parseMatrix(float* xform, const char* str) +{ + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) return len; + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseTranslate(float* xform, const char* str) +{ + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseScale(float* xform, const char* str) +{ + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewX(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewY(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseRotate(float* xform, const char* str) +{ + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float)*6); + + return len; +} + +static void nsvg__parseTransform(float* xform, const char* str) +{ + float t[6]; + nsvg__xformIdentity(xform); + while (*str) + { + if (strncmp(str, "matrix", 6) == 0) + str += nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + str += nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + str += nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + str += nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + str += nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + str += nsvg__parseSkewY(t, str); + else{ + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char* id, const char* str) +{ + int i = 0; + str += 4; // "url("; + if (*str == '#') + str++; + while (i < 63 && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char* str) +{ + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char* str) +{ + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseFillRule(const char* str) +{ + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char* nsvg__getNextDashItem(const char* s, char* it) +{ + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) +{ + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str); + +static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) +{ + float xform[6]; + NSVGattrib* attr = nsvg__getAttr(p); + if (!attr) return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) +{ + const char* str; + const char* val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; + ++str; + + n = (int)(str - start); + if (n > 511) n = 511; + if (n) memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; + + n = (int)(end - val); + if (n > 511) n = 511; + if (n) memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str) +{ + const char* start; + const char* end; + + while (*str) { + // Left Trim + while(*str && nsvg__isspace(*str)) ++str; + start = str; + while(*str && *str != ';') ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) + { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) +{ + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + } + return 0; +} + +static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2*x1 - *cpx2; + cy1 = 2*y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2*x1 - *cpx2; + cy = 2*y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) { return x*x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) +{ + return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) +{ + float r = nsvg__vecrat(ux,uy, vx,vy); + if (r < -1.0f) r = -1.0f; + if (r > 1.0f) r = 1.0f; + return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx*dx + dy*dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); + sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); + if (sa < 0.0f) sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; + cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle + da = nsvg__vecang(ux,uy, vx,vy); // Delta angle + +// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; +// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; t[1] = sinrx; + t[2] = -sinrx; t[3] = cosrx; + t[4] = cx; t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i/(float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser* p, const char** attr) +{ + const char* s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + float cpx, cpy, cpx2, cpy2; + const char* tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; cpy = 0; + cpx2 = 0; cpy2 = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + s = nsvg__getNextPathItem(s, item); + if (!*item) break; + if (nsvg__isnum(item[0])) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; cpy2 = cpy; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs-2]; + cpy = args[nargs-1]; + cpx2 = cpx; cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + cmd = item[0]; + rargs = nsvg__getArgsPerElement(cmd); + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser* p, const char** attr) +{ + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) rx = ry; + if (ry < 0.0f && rx > 0.0f) ry = rx; + if (rx < 0.0f) rx = 0.0f; + if (ry < 0.0f) ry = 0.0f; + if (rx > w/2.0f) rx = w/2.0f; + if (ry > h/2.0f) ry = h/2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x+w, y); + nsvg__lineTo(p, x+w, y+h); + nsvg__lineTo(p, x, y+h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x+rx, y); + nsvg__lineTo(p, x+w-rx, y); + nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); + nsvg__lineTo(p, x+w, y+h-ry); + nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); + nsvg__lineTo(p, x+rx, y+h); + nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); + nsvg__lineTo(p, x, y+ry); + nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+r, cy); + nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); + nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); + nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); + nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+rx, cy); + nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); + nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); + nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); + nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser* p, const char** attr) +{ + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) +{ + int i; + const char* s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) +{ + int i; + NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i+1], 63); + grad->id[63] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i+1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i+1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i+1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i+1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i+1]; + strncpy(grad->ref, href+1, 62); + grad->ref[62] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) +{ + NSVGattrib* curAttr = nsvg__getAttr(p); + NSVGgradientData* grad; + NSVGgradientStop* stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) return; + + grad->nstops++; + grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); + if (grad->stops == NULL) return; + + // Insert + idx = grad->nstops-1; + for (i = 0; i < grad->nstops-1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops-1) { + for (i = grad->nstops-1; i > idx; i--) + grad->stops[i] = grad->stops[i-1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void* ud, const char* el, const char** attr) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void* ud, const char* el) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void* ud, const char* s) +{ + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser* p, float* bounds) +{ + NSVGshape* shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) +{ + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) +{ + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply (grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply (grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) +{ + NSVGshape* shape; + NSVGpath* path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float* pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx+sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i =0; i < path->npts; i++) { + pt = &path->pts[i*2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +NSVGimage* nsvgParse(char* input, const char* units, float dpi) +{ + NSVGparser* p; + NSVGimage* ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Scale to viewBox + //nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) +{ + FILE* fp = NULL; + size_t size; + char* data = NULL; + NSVGimage* image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char*)malloc(size+1); + if (data == NULL) goto error; + if (fread(data, 1, size, fp) != size) goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; + +error: + if (fp) fclose(fp); + if (data) free(data); + if (image) nsvgDelete(image); + return NULL; +} + +void nsvgDelete(NSVGimage* image) +{ + NSVGshape *snext, *shape; + if (image == NULL) return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); +} + diff --git a/src/svg_parser/nanosvg.h b/src/svg_parser/nanosvg.h new file mode 100644 index 0000000..b25cc13 --- /dev/null +++ b/src/svg_parser/nanosvg.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example + * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) + * + * Arc calculation code based on canvg (https://code.google.com/p/canvg/) + * + * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + * + */ + +#ifndef NANOSVG_H +#define NANOSVG_H + +#ifdef __cplusplus +extern "C" { +#endif + +// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. +// +// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. +// +// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! +// +// The shapes in the SVG images are transformed by the viewBox and converted to specified units. +// That is, you should get the same looking data as your designed in your favorite app. +// +// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose +// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. +// +// The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. +// DPI (dots-per-inch) controls how the unit conversion is done. +// +// If you don't know or care about the units stuff, "px" and 96 should get you going. + + +/* Example Usage: + // Load + NSVGImage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); +*/ + +enum NSVGpaintType { + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 +}; + +enum NSVGspreadType { + NSVG_SPREAD_PAD = 0, + NSVG_SPREAD_REFLECT = 1, + NSVG_SPREAD_REPEAT = 2 +}; + +enum NSVGlineJoin { + NSVG_JOIN_MITER = 0, + NSVG_JOIN_ROUND = 1, + NSVG_JOIN_BEVEL = 2 +}; + +enum NSVGlineCap { + NSVG_CAP_BUTT = 0, + NSVG_CAP_ROUND = 1, + NSVG_CAP_SQUARE = 2 +}; + +enum NSVGfillRule { + NSVG_FILLRULE_NONZERO = 0, + NSVG_FILLRULE_EVENODD = 1 +}; + +enum NSVGflags { + NSVG_FLAGS_VISIBLE = 0x01 +}; + +typedef struct NSVGgradientStop { + unsigned int color; + float offset; +} NSVGgradientStop; + +typedef struct NSVGgradient { + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; +} NSVGgradient; + +typedef struct NSVGpaint { + char type; + union { + unsigned int color; + NSVGgradient* gradient; + }; +} NSVGpaint; + +typedef struct NSVGpath +{ + float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath* next; // Pointer to next path, or NULL if last element. +} NSVGpath; + +typedef struct NSVGshape +{ + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + NSVGpath* paths; // Linked list of paths in the image. + struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +} NSVGshape; + +typedef struct NSVGimage +{ + float width; // Width of the image. + float height; // Height of the image. + NSVGshape* shapes; // Linked list of shapes in the image. +} NSVGimage; + +// Parses SVG file from a file, returns SVG image as paths. +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); + +// Parses SVG file from a null terminated string, returns SVG image as paths. +// Important note: changes the string. +NSVGimage* nsvgParse(char* input, const char* units, float dpi); + +// Deletes list of paths. +void nsvgDelete(NSVGimage* image); + +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. + +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_SLICE 2 + +#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) + +#ifdef _MSC_VER + #pragma warning (disable: 4996) // Switch off security warnings + #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings + #ifdef __cplusplus + #define NSVG_INLINE inline + #else + #define NSVG_INLINE + #endif +#else + #define NSVG_INLINE inline +#endif + +#ifdef __cplusplus +} +#endif + +#endif // NANOSVG_H + diff --git a/src/svg_parser/svg_parser.c b/src/svg_parser/svg_parser.c new file mode 100644 index 0000000..55c37dc --- /dev/null +++ b/src/svg_parser/svg_parser.c @@ -0,0 +1,4042 @@ +/* Generated by Cython 0.25.2 */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#ifndef Py_PYTHON_H + #error Python headers needed to compile C extensions, please install development version of Python. +#elif PY_VERSION_HEX < 0x02060000 || (0x03000000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x03020000) + #error Cython requires Python 2.6+ or Python 3.2+. +#else +#define CYTHON_ABI "0_25_2" +#include +#ifndef offsetof + #define offsetof(type, member) ( (size_t) & ((type*)0) -> member ) +#endif +#if !defined(WIN32) && !defined(MS_WINDOWS) + #ifndef __stdcall + #define __stdcall + #endif + #ifndef __cdecl + #define __cdecl + #endif + #ifndef __fastcall + #define __fastcall + #endif +#endif +#ifndef DL_IMPORT + #define DL_IMPORT(t) t +#endif +#ifndef DL_EXPORT + #define DL_EXPORT(t) t +#endif +#ifndef HAVE_LONG_LONG + #if PY_VERSION_HEX >= 0x03030000 || (PY_MAJOR_VERSION == 2 && PY_VERSION_HEX >= 0x02070000) + #define HAVE_LONG_LONG + #endif +#endif +#ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG +#endif +#ifndef Py_HUGE_VAL + #define Py_HUGE_VAL HUGE_VAL +#endif +#ifdef PYPY_VERSION + #define CYTHON_COMPILING_IN_PYPY 1 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #undef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 0 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #undef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #undef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 1 + #undef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 0 + #undef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 0 + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 +#elif defined(PYSTON_VERSION) + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 1 + #define CYTHON_COMPILING_IN_CPYTHON 0 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #undef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 0 + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #undef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 0 + #undef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 0 +#else + #define CYTHON_COMPILING_IN_PYPY 0 + #define CYTHON_COMPILING_IN_PYSTON 0 + #define CYTHON_COMPILING_IN_CPYTHON 1 + #ifndef CYTHON_USE_TYPE_SLOTS + #define CYTHON_USE_TYPE_SLOTS 1 + #endif + #if PY_MAJOR_VERSION < 3 + #undef CYTHON_USE_ASYNC_SLOTS + #define CYTHON_USE_ASYNC_SLOTS 0 + #elif !defined(CYTHON_USE_ASYNC_SLOTS) + #define CYTHON_USE_ASYNC_SLOTS 1 + #endif + #if PY_VERSION_HEX < 0x02070000 + #undef CYTHON_USE_PYLONG_INTERNALS + #define CYTHON_USE_PYLONG_INTERNALS 0 + #elif !defined(CYTHON_USE_PYLONG_INTERNALS) + #define CYTHON_USE_PYLONG_INTERNALS 1 + #endif + #ifndef CYTHON_USE_PYLIST_INTERNALS + #define CYTHON_USE_PYLIST_INTERNALS 1 + #endif + #ifndef CYTHON_USE_UNICODE_INTERNALS + #define CYTHON_USE_UNICODE_INTERNALS 1 + #endif + #if PY_VERSION_HEX < 0x030300F0 + #undef CYTHON_USE_UNICODE_WRITER + #define CYTHON_USE_UNICODE_WRITER 0 + #elif !defined(CYTHON_USE_UNICODE_WRITER) + #define CYTHON_USE_UNICODE_WRITER 1 + #endif + #ifndef CYTHON_AVOID_BORROWED_REFS + #define CYTHON_AVOID_BORROWED_REFS 0 + #endif + #ifndef CYTHON_ASSUME_SAFE_MACROS + #define CYTHON_ASSUME_SAFE_MACROS 1 + #endif + #ifndef CYTHON_UNPACK_METHODS + #define CYTHON_UNPACK_METHODS 1 + #endif + #ifndef CYTHON_FAST_THREAD_STATE + #define CYTHON_FAST_THREAD_STATE 1 + #endif + #ifndef CYTHON_FAST_PYCALL + #define CYTHON_FAST_PYCALL 1 + #endif +#endif +#if !defined(CYTHON_FAST_PYCCALL) +#define CYTHON_FAST_PYCCALL (CYTHON_FAST_PYCALL && PY_VERSION_HEX >= 0x030600B1) +#endif +#if CYTHON_USE_PYLONG_INTERNALS + #include "longintrepr.h" + #undef SHIFT + #undef BASE + #undef MASK +#endif +#if CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x02070600 && !defined(Py_OptimizeFlag) + #define Py_OptimizeFlag 0 +#endif +#define __PYX_BUILD_PY_SSIZE_T "n" +#define CYTHON_FORMAT_SSIZE_T "z" +#if PY_MAJOR_VERSION < 3 + #define __Pyx_BUILTIN_MODULE_NAME "__builtin__" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a+k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyClass_Type +#else + #define __Pyx_BUILTIN_MODULE_NAME "builtins" + #define __Pyx_PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)\ + PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos) + #define __Pyx_DefaultClassType PyType_Type +#endif +#ifndef Py_TPFLAGS_CHECKTYPES + #define Py_TPFLAGS_CHECKTYPES 0 +#endif +#ifndef Py_TPFLAGS_HAVE_INDEX + #define Py_TPFLAGS_HAVE_INDEX 0 +#endif +#ifndef Py_TPFLAGS_HAVE_NEWBUFFER + #define Py_TPFLAGS_HAVE_NEWBUFFER 0 +#endif +#ifndef Py_TPFLAGS_HAVE_FINALIZE + #define Py_TPFLAGS_HAVE_FINALIZE 0 +#endif +#ifndef METH_FASTCALL + #define METH_FASTCALL 0x80 + typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args, + Py_ssize_t nargs, PyObject *kwnames); +#else + #define __Pyx_PyCFunctionFast _PyCFunctionFast +#endif +#if CYTHON_FAST_PYCCALL +#define __Pyx_PyFastCFunction_Check(func)\ + ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST))))) +#else +#define __Pyx_PyFastCFunction_Check(func) 0 +#endif +#if PY_VERSION_HEX > 0x03030000 && defined(PyUnicode_KIND) + #define CYTHON_PEP393_ENABLED 1 + #define __Pyx_PyUnicode_READY(op) (likely(PyUnicode_IS_READY(op)) ?\ + 0 : _PyUnicode_Ready((PyObject *)(op))) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_LENGTH(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) PyUnicode_READ_CHAR(u, i) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) PyUnicode_MAX_CHAR_VALUE(u) + #define __Pyx_PyUnicode_KIND(u) PyUnicode_KIND(u) + #define __Pyx_PyUnicode_DATA(u) PyUnicode_DATA(u) + #define __Pyx_PyUnicode_READ(k, d, i) PyUnicode_READ(k, d, i) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) PyUnicode_WRITE(k, d, i, ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != (likely(PyUnicode_IS_READY(u)) ? PyUnicode_GET_LENGTH(u) : PyUnicode_GET_SIZE(u))) +#else + #define CYTHON_PEP393_ENABLED 0 + #define PyUnicode_1BYTE_KIND 1 + #define PyUnicode_2BYTE_KIND 2 + #define PyUnicode_4BYTE_KIND 4 + #define __Pyx_PyUnicode_READY(op) (0) + #define __Pyx_PyUnicode_GET_LENGTH(u) PyUnicode_GET_SIZE(u) + #define __Pyx_PyUnicode_READ_CHAR(u, i) ((Py_UCS4)(PyUnicode_AS_UNICODE(u)[i])) + #define __Pyx_PyUnicode_MAX_CHAR_VALUE(u) ((sizeof(Py_UNICODE) == 2) ? 65535 : 1114111) + #define __Pyx_PyUnicode_KIND(u) (sizeof(Py_UNICODE)) + #define __Pyx_PyUnicode_DATA(u) ((void*)PyUnicode_AS_UNICODE(u)) + #define __Pyx_PyUnicode_READ(k, d, i) ((void)(k), (Py_UCS4)(((Py_UNICODE*)d)[i])) + #define __Pyx_PyUnicode_WRITE(k, d, i, ch) (((void)(k)), ((Py_UNICODE*)d)[i] = ch) + #define __Pyx_PyUnicode_IS_TRUE(u) (0 != PyUnicode_GET_SIZE(u)) +#endif +#if CYTHON_COMPILING_IN_PYPY + #define __Pyx_PyUnicode_Concat(a, b) PyNumber_Add(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) PyNumber_Add(a, b) +#else + #define __Pyx_PyUnicode_Concat(a, b) PyUnicode_Concat(a, b) + #define __Pyx_PyUnicode_ConcatSafe(a, b) ((unlikely((a) == Py_None) || unlikely((b) == Py_None)) ?\ + PyNumber_Add(a, b) : __Pyx_PyUnicode_Concat(a, b)) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyUnicode_Contains) + #define PyUnicode_Contains(u, s) PySequence_Contains(u, s) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyByteArray_Check) + #define PyByteArray_Check(obj) PyObject_TypeCheck(obj, &PyByteArray_Type) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Format) + #define PyObject_Format(obj, fmt) PyObject_CallMethod(obj, "__format__", "O", fmt) +#endif +#if CYTHON_COMPILING_IN_PYPY && !defined(PyObject_Malloc) + #define PyObject_Malloc(s) PyMem_Malloc(s) + #define PyObject_Free(p) PyMem_Free(p) + #define PyObject_Realloc(p) PyMem_Realloc(p) +#endif +#if CYTHON_COMPILING_IN_PYSTON + #define __Pyx_PyCode_HasFreeVars(co) PyCode_HasFreeVars(co) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) PyFrame_SetLineNumber(frame, lineno) +#else + #define __Pyx_PyCode_HasFreeVars(co) (PyCode_GetNumFree(co) > 0) + #define __Pyx_PyFrame_SetLineNumber(frame, lineno) (frame)->f_lineno = (lineno) +#endif +#define __Pyx_PyString_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : __Pyx_PyString_Format(a, b)) +#define __Pyx_PyUnicode_FormatSafe(a, b) ((unlikely((a) == Py_None)) ? PyNumber_Remainder(a, b) : PyUnicode_Format(a, b)) +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyString_Format(a, b) PyUnicode_Format(a, b) +#else + #define __Pyx_PyString_Format(a, b) PyString_Format(a, b) +#endif +#if PY_MAJOR_VERSION < 3 && !defined(PyObject_ASCII) + #define PyObject_ASCII(o) PyObject_Repr(o) +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBaseString_Type PyUnicode_Type + #define PyStringObject PyUnicodeObject + #define PyString_Type PyUnicode_Type + #define PyString_Check PyUnicode_Check + #define PyString_CheckExact PyUnicode_CheckExact +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyBaseString_Check(obj) PyUnicode_Check(obj) + #define __Pyx_PyBaseString_CheckExact(obj) PyUnicode_CheckExact(obj) +#else + #define __Pyx_PyBaseString_Check(obj) (PyString_Check(obj) || PyUnicode_Check(obj)) + #define __Pyx_PyBaseString_CheckExact(obj) (PyString_CheckExact(obj) || PyUnicode_CheckExact(obj)) +#endif +#ifndef PySet_CheckExact + #define PySet_CheckExact(obj) (Py_TYPE(obj) == &PySet_Type) +#endif +#define __Pyx_TypeCheck(obj, type) PyObject_TypeCheck(obj, (PyTypeObject *)type) +#define __Pyx_PyException_Check(obj) __Pyx_TypeCheck(obj, PyExc_Exception) +#if PY_MAJOR_VERSION >= 3 + #define PyIntObject PyLongObject + #define PyInt_Type PyLong_Type + #define PyInt_Check(op) PyLong_Check(op) + #define PyInt_CheckExact(op) PyLong_CheckExact(op) + #define PyInt_FromString PyLong_FromString + #define PyInt_FromUnicode PyLong_FromUnicode + #define PyInt_FromLong PyLong_FromLong + #define PyInt_FromSize_t PyLong_FromSize_t + #define PyInt_FromSsize_t PyLong_FromSsize_t + #define PyInt_AsLong PyLong_AsLong + #define PyInt_AS_LONG PyLong_AS_LONG + #define PyInt_AsSsize_t PyLong_AsSsize_t + #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask + #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask + #define PyNumber_Int PyNumber_Long +#endif +#if PY_MAJOR_VERSION >= 3 + #define PyBoolObject PyLongObject +#endif +#if PY_MAJOR_VERSION >= 3 && CYTHON_COMPILING_IN_PYPY + #ifndef PyUnicode_InternFromString + #define PyUnicode_InternFromString(s) PyUnicode_FromString(s) + #endif +#endif +#if PY_VERSION_HEX < 0x030200A4 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t PyInt_AsLong +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t +#endif +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyMethod_New(func, self, klass) ((self) ? PyMethod_New(func, self) : PyInstanceMethod_New(func)) +#else + #define __Pyx_PyMethod_New(func, self, klass) PyMethod_New(func, self, klass) +#endif +#if CYTHON_USE_ASYNC_SLOTS + #if PY_VERSION_HEX >= 0x030500B1 + #define __Pyx_PyAsyncMethodsStruct PyAsyncMethods + #define __Pyx_PyType_AsAsync(obj) (Py_TYPE(obj)->tp_as_async) + #else + typedef struct { + unaryfunc am_await; + unaryfunc am_aiter; + unaryfunc am_anext; + } __Pyx_PyAsyncMethodsStruct; + #define __Pyx_PyType_AsAsync(obj) ((__Pyx_PyAsyncMethodsStruct*) (Py_TYPE(obj)->tp_reserved)) + #endif +#else + #define __Pyx_PyType_AsAsync(obj) NULL +#endif +#ifndef CYTHON_RESTRICT + #if defined(__GNUC__) + #define CYTHON_RESTRICT __restrict__ + #elif defined(_MSC_VER) && _MSC_VER >= 1400 + #define CYTHON_RESTRICT __restrict + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_RESTRICT restrict + #else + #define CYTHON_RESTRICT + #endif +#endif +#ifndef CYTHON_UNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +# elif defined(__ICC) || (defined(__INTEL_COMPILER) && !defined(_MSC_VER)) +# define CYTHON_UNUSED __attribute__ ((__unused__)) +# else +# define CYTHON_UNUSED +# endif +#endif +#ifndef CYTHON_MAYBE_UNUSED_VAR +# if defined(__cplusplus) + template void CYTHON_MAYBE_UNUSED_VAR( const T& ) { } +# else +# define CYTHON_MAYBE_UNUSED_VAR(x) (void)(x) +# endif +#endif +#ifndef CYTHON_NCP_UNUSED +# if CYTHON_COMPILING_IN_CPYTHON +# define CYTHON_NCP_UNUSED +# else +# define CYTHON_NCP_UNUSED CYTHON_UNUSED +# endif +#endif +#define __Pyx_void_to_None(void_result) ((void)(void_result), Py_INCREF(Py_None), Py_None) + +#ifndef CYTHON_INLINE + #if defined(__clang__) + #define CYTHON_INLINE __inline__ __attribute__ ((__unused__)) + #elif defined(__GNUC__) + #define CYTHON_INLINE __inline__ + #elif defined(_MSC_VER) + #define CYTHON_INLINE __inline + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define CYTHON_INLINE inline + #else + #define CYTHON_INLINE + #endif +#endif + +#if defined(WIN32) || defined(MS_WINDOWS) + #define _USE_MATH_DEFINES +#endif +#include +#ifdef NAN +#define __PYX_NAN() ((float) NAN) +#else +static CYTHON_INLINE float __PYX_NAN() { + float value; + memset(&value, 0xFF, sizeof(value)); + return value; +} +#endif +#if defined(__CYGWIN__) && defined(_LDBL_EQ_DBL) +#define __Pyx_truncl trunc +#else +#define __Pyx_truncl truncl +#endif + + +#define __PYX_ERR(f_index, lineno, Ln_error) \ +{ \ + __pyx_filename = __pyx_f[f_index]; __pyx_lineno = lineno; __pyx_clineno = __LINE__; goto Ln_error; \ +} + +#if PY_MAJOR_VERSION >= 3 + #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceTrueDivide(x,y) +#else + #define __Pyx_PyNumber_Divide(x,y) PyNumber_Divide(x,y) + #define __Pyx_PyNumber_InPlaceDivide(x,y) PyNumber_InPlaceDivide(x,y) +#endif + +#ifndef __PYX_EXTERN_C + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif +#endif + +#define __PYX_HAVE__fluxclient__parser___parser +#define __PYX_HAVE_API__fluxclient__parser___parser +#include "nanosvg.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ + +#ifdef PYREX_WITHOUT_ASSERTIONS +#define CYTHON_WITHOUT_ASSERTIONS +#endif + +typedef struct {PyObject **p; const char *s; const Py_ssize_t n; const char* encoding; + const char is_unicode; const char is_str; const char intern; } __Pyx_StringTabEntry; + +#define __PYX_DEFAULT_STRING_ENCODING_IS_ASCII 0 +#define __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT 0 +#define __PYX_DEFAULT_STRING_ENCODING "" +#define __Pyx_PyObject_FromString __Pyx_PyBytes_FromString +#define __Pyx_PyObject_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#define __Pyx_uchar_cast(c) ((unsigned char)c) +#define __Pyx_long_cast(x) ((long)x) +#define __Pyx_fits_Py_ssize_t(v, type, is_signed) (\ + (sizeof(type) < sizeof(Py_ssize_t)) ||\ + (sizeof(type) > sizeof(Py_ssize_t) &&\ + likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX) &&\ + (!is_signed || likely(v > (type)PY_SSIZE_T_MIN ||\ + v == (type)PY_SSIZE_T_MIN))) ||\ + (sizeof(type) == sizeof(Py_ssize_t) &&\ + (is_signed || likely(v < (type)PY_SSIZE_T_MAX ||\ + v == (type)PY_SSIZE_T_MAX))) ) +#if defined (__cplusplus) && __cplusplus >= 201103L + #include + #define __Pyx_sst_abs(value) std::abs(value) +#elif SIZEOF_INT >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) abs(value) +#elif SIZEOF_LONG >= SIZEOF_SIZE_T + #define __Pyx_sst_abs(value) labs(value) +#elif defined (_MSC_VER) && defined (_M_X64) + #define __Pyx_sst_abs(value) _abs64(value) +#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + #define __Pyx_sst_abs(value) llabs(value) +#elif defined (__GNUC__) + #define __Pyx_sst_abs(value) __builtin_llabs(value) +#else + #define __Pyx_sst_abs(value) ((value<0) ? -value : value) +#endif +static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject*); +static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length); +#define __Pyx_PyByteArray_FromString(s) PyByteArray_FromStringAndSize((const char*)s, strlen((const char*)s)) +#define __Pyx_PyByteArray_FromStringAndSize(s, l) PyByteArray_FromStringAndSize((const char*)s, l) +#define __Pyx_PyBytes_FromString PyBytes_FromString +#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char*); +#if PY_MAJOR_VERSION < 3 + #define __Pyx_PyStr_FromString __Pyx_PyBytes_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyBytes_FromStringAndSize +#else + #define __Pyx_PyStr_FromString __Pyx_PyUnicode_FromString + #define __Pyx_PyStr_FromStringAndSize __Pyx_PyUnicode_FromStringAndSize +#endif +#define __Pyx_PyObject_AsSString(s) ((signed char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_AsUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s)) +#define __Pyx_PyObject_FromCString(s) __Pyx_PyObject_FromString((const char*)s) +#define __Pyx_PyBytes_FromCString(s) __Pyx_PyBytes_FromString((const char*)s) +#define __Pyx_PyByteArray_FromCString(s) __Pyx_PyByteArray_FromString((const char*)s) +#define __Pyx_PyStr_FromCString(s) __Pyx_PyStr_FromString((const char*)s) +#define __Pyx_PyUnicode_FromCString(s) __Pyx_PyUnicode_FromString((const char*)s) +#if PY_MAJOR_VERSION < 3 +static CYTHON_INLINE size_t __Pyx_Py_UNICODE_strlen(const Py_UNICODE *u) +{ + const Py_UNICODE *u_end = u; + while (*u_end++) ; + return (size_t)(u_end - u - 1); +} +#else +#define __Pyx_Py_UNICODE_strlen Py_UNICODE_strlen +#endif +#define __Pyx_PyUnicode_FromUnicode(u) PyUnicode_FromUnicode(u, __Pyx_Py_UNICODE_strlen(u)) +#define __Pyx_PyUnicode_FromUnicodeAndLength PyUnicode_FromUnicode +#define __Pyx_PyUnicode_AsUnicode PyUnicode_AsUnicode +#define __Pyx_NewRef(obj) (Py_INCREF(obj), obj) +#define __Pyx_Owned_Py_None(b) __Pyx_NewRef(Py_None) +#define __Pyx_PyBool_FromLong(b) ((b) ? __Pyx_NewRef(Py_True) : __Pyx_NewRef(Py_False)) +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x); +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject*); +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t); +#if CYTHON_ASSUME_SAFE_MACROS +#define __pyx_PyFloat_AsDouble(x) (PyFloat_CheckExact(x) ? PyFloat_AS_DOUBLE(x) : PyFloat_AsDouble(x)) +#else +#define __pyx_PyFloat_AsDouble(x) PyFloat_AsDouble(x) +#endif +#define __pyx_PyFloat_AsFloat(x) ((float) __pyx_PyFloat_AsDouble(x)) +#if PY_MAJOR_VERSION >= 3 +#define __Pyx_PyNumber_Int(x) (PyLong_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Long(x)) +#else +#define __Pyx_PyNumber_Int(x) (PyInt_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Int(x)) +#endif +#define __Pyx_PyNumber_Float(x) (PyFloat_CheckExact(x) ? __Pyx_NewRef(x) : PyNumber_Float(x)) +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII +static int __Pyx_sys_getdefaultencoding_not_ascii; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + PyObject* ascii_chars_u = NULL; + PyObject* ascii_chars_b = NULL; + const char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + if (strcmp(default_encoding_c, "ascii") == 0) { + __Pyx_sys_getdefaultencoding_not_ascii = 0; + } else { + char ascii_chars[128]; + int c; + for (c = 0; c < 128; c++) { + ascii_chars[c] = c; + } + __Pyx_sys_getdefaultencoding_not_ascii = 1; + ascii_chars_u = PyUnicode_DecodeASCII(ascii_chars, 128, NULL); + if (!ascii_chars_u) goto bad; + ascii_chars_b = PyUnicode_AsEncodedString(ascii_chars_u, default_encoding_c, NULL); + if (!ascii_chars_b || !PyBytes_Check(ascii_chars_b) || memcmp(ascii_chars, PyBytes_AS_STRING(ascii_chars_b), 128) != 0) { + PyErr_Format( + PyExc_ValueError, + "This module compiled with c_string_encoding=ascii, but default encoding '%.200s' is not a superset of ascii.", + default_encoding_c); + goto bad; + } + Py_DECREF(ascii_chars_u); + Py_DECREF(ascii_chars_b); + } + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + Py_XDECREF(ascii_chars_u); + Py_XDECREF(ascii_chars_b); + return -1; +} +#endif +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT && PY_MAJOR_VERSION >= 3 +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_DecodeUTF8(c_str, size, NULL) +#else +#define __Pyx_PyUnicode_FromStringAndSize(c_str, size) PyUnicode_Decode(c_str, size, __PYX_DEFAULT_STRING_ENCODING, NULL) +#if __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT +static char* __PYX_DEFAULT_STRING_ENCODING; +static int __Pyx_init_sys_getdefaultencoding_params(void) { + PyObject* sys; + PyObject* default_encoding = NULL; + char* default_encoding_c; + sys = PyImport_ImportModule("sys"); + if (!sys) goto bad; + default_encoding = PyObject_CallMethod(sys, (char*) (const char*) "getdefaultencoding", NULL); + Py_DECREF(sys); + if (!default_encoding) goto bad; + default_encoding_c = PyBytes_AsString(default_encoding); + if (!default_encoding_c) goto bad; + __PYX_DEFAULT_STRING_ENCODING = (char*) malloc(strlen(default_encoding_c)); + if (!__PYX_DEFAULT_STRING_ENCODING) goto bad; + strcpy(__PYX_DEFAULT_STRING_ENCODING, default_encoding_c); + Py_DECREF(default_encoding); + return 0; +bad: + Py_XDECREF(default_encoding); + return -1; +} +#endif +#endif + + +/* Test for GCC > 2.95 */ +#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95))) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else /* !__GNUC__ or GCC < 2.95 */ + #define likely(x) (x) + #define unlikely(x) (x) +#endif /* __GNUC__ */ + +static PyObject *__pyx_m; +static PyObject *__pyx_d; +static PyObject *__pyx_b; +static PyObject *__pyx_empty_tuple; +static PyObject *__pyx_empty_bytes; +static PyObject *__pyx_empty_unicode; +static int __pyx_lineno; +static int __pyx_clineno = 0; +static const char * __pyx_cfilenm= __FILE__; +static const char *__pyx_filename; + + +static const char *__pyx_f[] = { + "src/svg_parser/svg_parser.pyx", +}; + +/*--- Type declarations ---*/ + +/* --- Runtime support code (head) --- */ +/* Refnanny.proto */ +#ifndef CYTHON_REFNANNY + #define CYTHON_REFNANNY 0 +#endif +#if CYTHON_REFNANNY + typedef struct { + void (*INCREF)(void*, PyObject*, int); + void (*DECREF)(void*, PyObject*, int); + void (*GOTREF)(void*, PyObject*, int); + void (*GIVEREF)(void*, PyObject*, int); + void* (*SetupContext)(const char*, int, const char*); + void (*FinishContext)(void**); + } __Pyx_RefNannyAPIStruct; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; +#ifdef WITH_THREAD + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + if (acquire_gil) {\ + PyGILState_STATE __pyx_gilstate_save = PyGILState_Ensure();\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + PyGILState_Release(__pyx_gilstate_save);\ + } else {\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__);\ + } +#else + #define __Pyx_RefNannySetupContext(name, acquire_gil)\ + __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) +#endif + #define __Pyx_RefNannyFinishContext()\ + __Pyx_RefNanny->FinishContext(&__pyx_refnanny) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) +#else + #define __Pyx_RefNannyDeclarations + #define __Pyx_RefNannySetupContext(name, acquire_gil) + #define __Pyx_RefNannyFinishContext() + #define __Pyx_INCREF(r) Py_INCREF(r) + #define __Pyx_DECREF(r) Py_DECREF(r) + #define __Pyx_GOTREF(r) + #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) + #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) +#endif +#define __Pyx_XDECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_XDECREF(tmp);\ + } while (0) +#define __Pyx_DECREF_SET(r, v) do {\ + PyObject *tmp = (PyObject *) r;\ + r = v; __Pyx_DECREF(tmp);\ + } while (0) +#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) +#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) + +/* PyObjectGetAttrStr.proto */ +#if CYTHON_USE_TYPE_SLOTS +static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) { + PyTypeObject* tp = Py_TYPE(obj); + if (likely(tp->tp_getattro)) + return tp->tp_getattro(obj, attr_name); +#if PY_MAJOR_VERSION < 3 + if (likely(tp->tp_getattr)) + return tp->tp_getattr(obj, PyString_AS_STRING(attr_name)); +#endif + return PyObject_GetAttr(obj, attr_name); +} +#else +#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n) +#endif + +/* GetBuiltinName.proto */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name); + +/* RaiseArgTupleInvalid.proto */ +static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, + Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); + +/* RaiseDoubleKeywords.proto */ +static void __Pyx_RaiseDoubleKeywordsError(const char* func_name, PyObject* kw_name); + +/* ParseKeywords.proto */ +static int __Pyx_ParseOptionalKeywords(PyObject *kwds, PyObject **argnames[],\ + PyObject *kwds2, PyObject *values[], Py_ssize_t num_pos_args,\ + const char* function_name); + +/* GetModuleGlobalName.proto */ +static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name); + +/* PyFunctionFastCall.proto */ +#if CYTHON_FAST_PYCALL +#define __Pyx_PyFunction_FastCall(func, args, nargs)\ + __Pyx_PyFunction_FastCallDict((func), (args), (nargs), NULL) +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs); +#else +#define __Pyx_PyFunction_FastCallDict(func, args, nargs, kwargs) _PyFunction_FastCallDict(func, args, nargs, kwargs) +#endif +#endif + +/* PyCFunctionFastCall.proto */ +#if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject *__Pyx_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs); +#else +#define __Pyx_PyCFunction_FastCall(func, args, nargs) (assert(0), NULL) +#endif + +/* PyObjectCall.proto */ +#if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw); +#else +#define __Pyx_PyObject_Call(func, arg, kw) PyObject_Call(func, arg, kw) +#endif + +/* ListExtend.proto */ +static CYTHON_INLINE int __Pyx_PyList_Extend(PyObject* L, PyObject* v) { +#if CYTHON_COMPILING_IN_CPYTHON + PyObject* none = _PyList_Extend((PyListObject*)L, v); + if (unlikely(!none)) + return -1; + Py_DECREF(none); + return 0; +#else + return PyList_SetSlice(L, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, v); +#endif +} + +/* ListAppend.proto */ +#if CYTHON_USE_PYLIST_INTERNALS && CYTHON_ASSUME_SAFE_MACROS +static CYTHON_INLINE int __Pyx_PyList_Append(PyObject* list, PyObject* x) { + PyListObject* L = (PyListObject*) list; + Py_ssize_t len = Py_SIZE(list); + if (likely(L->allocated > len) & likely(len > (L->allocated >> 1))) { + Py_INCREF(x); + PyList_SET_ITEM(list, len, x); + Py_SIZE(list) = len+1; + return 0; + } + return PyList_Append(list, x); +} +#else +#define __Pyx_PyList_Append(L,x) PyList_Append(L,x) +#endif + +/* CodeObjectCache.proto */ +typedef struct { + PyCodeObject* code_object; + int code_line; +} __Pyx_CodeObjectCacheEntry; +struct __Pyx_CodeObjectCache { + int count; + int max_count; + __Pyx_CodeObjectCacheEntry* entries; +}; +static struct __Pyx_CodeObjectCache __pyx_code_cache = {0,0,NULL}; +static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line); +static PyCodeObject *__pyx_find_code_object(int code_line); +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object); + +/* AddTraceback.proto */ +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename); + +/* CIntToPy.proto */ +static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value); + +/* CIntFromPy.proto */ +static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *); + +/* CIntFromPy.proto */ +static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *); + +/* CheckBinaryVersion.proto */ +static int __Pyx_check_binary_version(void); + +/* InitStrings.proto */ +static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); + + +/* Module declarations from 'cython' */ + +/* Module declarations from 'fluxclient.parser._parser' */ +static PyObject *__pyx_f_10fluxclient_6parser_7_parser_get_all_points(char *, int __pyx_skip_dispatch); /*proto*/ +#define __Pyx_MODULE_NAME "fluxclient.parser._parser" +int __pyx_module_is_main_fluxclient__parser___parser = 0; + +/* Implementation of 'fluxclient.parser._parser' */ +static PyObject *__pyx_builtin_range; +static const char __pyx_k_a[] = "a"; +static const char __pyx_k_b[] = "b"; +static const char __pyx_k_d[] = "d"; +static const char __pyx_k_t[] = "t"; +static const char __pyx_k_x[] = "x"; +static const char __pyx_k_y[] = "y"; +static const char __pyx_k_dx[] = "dx"; +static const char __pyx_k_dy[] = "dy"; +static const char __pyx_k_px[] = "px"; +static const char __pyx_k_py[] = "py"; +static const char __pyx_k_qx[] = "qx"; +static const char __pyx_k_qy[] = "qy"; +static const char __pyx_k_x1[] = "x1"; +static const char __pyx_k_x2[] = "x2"; +static const char __pyx_k_x3[] = "x3"; +static const char __pyx_k_x4[] = "x4"; +static const char __pyx_k_y1[] = "y1"; +static const char __pyx_k_y2[] = "y2"; +static const char __pyx_k_y3[] = "y3"; +static const char __pyx_k_y4[] = "y4"; +static const char __pyx_k_pqx[] = "pqx"; +static const char __pyx_k_pqy[] = "pqy"; +static const char __pyx_k_tol[] = "tol"; +static const char __pyx_k_x12[] = "x12"; +static const char __pyx_k_x23[] = "x23"; +static const char __pyx_k_x34[] = "x34"; +static const char __pyx_k_y12[] = "y12"; +static const char __pyx_k_y23[] = "y23"; +static const char __pyx_k_y34[] = "y34"; +static const char __pyx_k_main[] = "__main__"; +static const char __pyx_k_test[] = "__test__"; +static const char __pyx_k_x123[] = "x123"; +static const char __pyx_k_x234[] = "x234"; +static const char __pyx_k_y123[] = "y123"; +static const char __pyx_k_y234[] = "y234"; +static const char __pyx_k_level[] = "level"; +static const char __pyx_k_range[] = "range"; +static const char __pyx_k_x1234[] = "x1234"; +static const char __pyx_k_y1234[] = "y1234"; +static const char __pyx_k_cubicBez[] = "cubicBez"; +static const char __pyx_k_distPtSeg[] = "distPtSeg"; +static const char __pyx_k_point_lst[] = "point_lst"; +static const char __pyx_k_fluxclient_parser__parser[] = "fluxclient.parser._parser"; +static const char __pyx_k_Users_simon_Dev_fluxclient_dev[] = "/Users/simon/Dev/fluxclient-dev/src/svg_parser/svg_parser.pyx"; +static PyObject *__pyx_kp_s_Users_simon_Dev_fluxclient_dev; +static PyObject *__pyx_n_s_a; +static PyObject *__pyx_n_s_b; +static PyObject *__pyx_n_s_cubicBez; +static PyObject *__pyx_n_s_d; +static PyObject *__pyx_n_s_distPtSeg; +static PyObject *__pyx_n_s_dx; +static PyObject *__pyx_n_s_dy; +static PyObject *__pyx_n_s_fluxclient_parser__parser; +static PyObject *__pyx_n_s_level; +static PyObject *__pyx_n_s_main; +static PyObject *__pyx_n_s_point_lst; +static PyObject *__pyx_n_s_pqx; +static PyObject *__pyx_n_s_pqy; +static PyObject *__pyx_n_s_px; +static PyObject *__pyx_n_s_py; +static PyObject *__pyx_n_s_qx; +static PyObject *__pyx_n_s_qy; +static PyObject *__pyx_n_s_range; +static PyObject *__pyx_n_s_t; +static PyObject *__pyx_n_s_test; +static PyObject *__pyx_n_s_tol; +static PyObject *__pyx_n_s_x; +static PyObject *__pyx_n_s_x1; +static PyObject *__pyx_n_s_x12; +static PyObject *__pyx_n_s_x123; +static PyObject *__pyx_n_s_x1234; +static PyObject *__pyx_n_s_x2; +static PyObject *__pyx_n_s_x23; +static PyObject *__pyx_n_s_x234; +static PyObject *__pyx_n_s_x3; +static PyObject *__pyx_n_s_x34; +static PyObject *__pyx_n_s_x4; +static PyObject *__pyx_n_s_y; +static PyObject *__pyx_n_s_y1; +static PyObject *__pyx_n_s_y12; +static PyObject *__pyx_n_s_y123; +static PyObject *__pyx_n_s_y1234; +static PyObject *__pyx_n_s_y2; +static PyObject *__pyx_n_s_y23; +static PyObject *__pyx_n_s_y234; +static PyObject *__pyx_n_s_y3; +static PyObject *__pyx_n_s_y34; +static PyObject *__pyx_n_s_y4; +static PyObject *__pyx_pf_10fluxclient_6parser_7_parser_distPtSeg(CYTHON_UNUSED PyObject *__pyx_self, float __pyx_v_x, float __pyx_v_y, float __pyx_v_px, float __pyx_v_py, float __pyx_v_qx, float __pyx_v_qy); /* proto */ +static PyObject *__pyx_pf_10fluxclient_6parser_7_parser_2cubicBez(CYTHON_UNUSED PyObject *__pyx_self, float __pyx_v_x1, float __pyx_v_y1, float __pyx_v_x2, float __pyx_v_y2, float __pyx_v_x3, float __pyx_v_y3, float __pyx_v_x4, float __pyx_v_y4, float __pyx_v_tol, int __pyx_v_level); /* proto */ +static PyObject *__pyx_pf_10fluxclient_6parser_7_parser_4get_all_points(CYTHON_UNUSED PyObject *__pyx_self, char *__pyx_v_svg_data); /* proto */ +static PyObject *__pyx_int_0; +static PyObject *__pyx_tuple_; +static PyObject *__pyx_tuple__3; +static PyObject *__pyx_codeobj__2; +static PyObject *__pyx_codeobj__4; + +/* "src/svg_parser/svg_parser.pyx":20 + * NSVGimage* nsvgParse(char* input, const char* units, float dpi); + * + * def distPtSeg(float x, float y, float px, float py, float qx, float qy): # <<<<<<<<<<<<<< + * cdef float pqx, pqy, dx, dy, d, t + * pqx = qx-px + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_10fluxclient_6parser_7_parser_1distPtSeg(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_10fluxclient_6parser_7_parser_1distPtSeg = {"distPtSeg", (PyCFunction)__pyx_pw_10fluxclient_6parser_7_parser_1distPtSeg, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_10fluxclient_6parser_7_parser_1distPtSeg(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + float __pyx_v_x; + float __pyx_v_y; + float __pyx_v_px; + float __pyx_v_py; + float __pyx_v_qx; + float __pyx_v_qy; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("distPtSeg (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x,&__pyx_n_s_y,&__pyx_n_s_px,&__pyx_n_s_py,&__pyx_n_s_qx,&__pyx_n_s_qy,0}; + PyObject* values[6] = {0,0,0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5); + case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_x)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + case 1: + if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_y)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("distPtSeg", 1, 6, 6, 1); __PYX_ERR(0, 20, __pyx_L3_error) + } + case 2: + if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_px)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("distPtSeg", 1, 6, 6, 2); __PYX_ERR(0, 20, __pyx_L3_error) + } + case 3: + if (likely((values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_py)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("distPtSeg", 1, 6, 6, 3); __PYX_ERR(0, 20, __pyx_L3_error) + } + case 4: + if (likely((values[4] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_qx)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("distPtSeg", 1, 6, 6, 4); __PYX_ERR(0, 20, __pyx_L3_error) + } + case 5: + if (likely((values[5] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_qy)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("distPtSeg", 1, 6, 6, 5); __PYX_ERR(0, 20, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "distPtSeg") < 0)) __PYX_ERR(0, 20, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 6) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + values[5] = PyTuple_GET_ITEM(__pyx_args, 5); + } + __pyx_v_x = __pyx_PyFloat_AsFloat(values[0]); if (unlikely((__pyx_v_x == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 20, __pyx_L3_error) + __pyx_v_y = __pyx_PyFloat_AsFloat(values[1]); if (unlikely((__pyx_v_y == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 20, __pyx_L3_error) + __pyx_v_px = __pyx_PyFloat_AsFloat(values[2]); if (unlikely((__pyx_v_px == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 20, __pyx_L3_error) + __pyx_v_py = __pyx_PyFloat_AsFloat(values[3]); if (unlikely((__pyx_v_py == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 20, __pyx_L3_error) + __pyx_v_qx = __pyx_PyFloat_AsFloat(values[4]); if (unlikely((__pyx_v_qx == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 20, __pyx_L3_error) + __pyx_v_qy = __pyx_PyFloat_AsFloat(values[5]); if (unlikely((__pyx_v_qy == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 20, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("distPtSeg", 1, 6, 6, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 20, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("fluxclient.parser._parser.distPtSeg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_10fluxclient_6parser_7_parser_distPtSeg(__pyx_self, __pyx_v_x, __pyx_v_y, __pyx_v_px, __pyx_v_py, __pyx_v_qx, __pyx_v_qy); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_10fluxclient_6parser_7_parser_distPtSeg(CYTHON_UNUSED PyObject *__pyx_self, float __pyx_v_x, float __pyx_v_y, float __pyx_v_px, float __pyx_v_py, float __pyx_v_qx, float __pyx_v_qy) { + float __pyx_v_pqx; + float __pyx_v_pqy; + float __pyx_v_dx; + float __pyx_v_dy; + float __pyx_v_d; + float __pyx_v_t; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + __Pyx_RefNannySetupContext("distPtSeg", 0); + + /* "src/svg_parser/svg_parser.pyx":22 + * def distPtSeg(float x, float y, float px, float py, float qx, float qy): + * cdef float pqx, pqy, dx, dy, d, t + * pqx = qx-px # <<<<<<<<<<<<<< + * pqy = qy-py + * dx = x-px + */ + __pyx_v_pqx = (__pyx_v_qx - __pyx_v_px); + + /* "src/svg_parser/svg_parser.pyx":23 + * cdef float pqx, pqy, dx, dy, d, t + * pqx = qx-px + * pqy = qy-py # <<<<<<<<<<<<<< + * dx = x-px + * dy = y-py + */ + __pyx_v_pqy = (__pyx_v_qy - __pyx_v_py); + + /* "src/svg_parser/svg_parser.pyx":24 + * pqx = qx-px + * pqy = qy-py + * dx = x-px # <<<<<<<<<<<<<< + * dy = y-py + * d = pqx*pqx + pqy*pqy + */ + __pyx_v_dx = (__pyx_v_x - __pyx_v_px); + + /* "src/svg_parser/svg_parser.pyx":25 + * pqy = qy-py + * dx = x-px + * dy = y-py # <<<<<<<<<<<<<< + * d = pqx*pqx + pqy*pqy + * t = pqx*dx + pqy*dy + */ + __pyx_v_dy = (__pyx_v_y - __pyx_v_py); + + /* "src/svg_parser/svg_parser.pyx":26 + * dx = x-px + * dy = y-py + * d = pqx*pqx + pqy*pqy # <<<<<<<<<<<<<< + * t = pqx*dx + pqy*dy + * if d > 0: + */ + __pyx_v_d = ((__pyx_v_pqx * __pyx_v_pqx) + (__pyx_v_pqy * __pyx_v_pqy)); + + /* "src/svg_parser/svg_parser.pyx":27 + * dy = y-py + * d = pqx*pqx + pqy*pqy + * t = pqx*dx + pqy*dy # <<<<<<<<<<<<<< + * if d > 0: + * t = t/d + */ + __pyx_v_t = ((__pyx_v_pqx * __pyx_v_dx) + (__pyx_v_pqy * __pyx_v_dy)); + + /* "src/svg_parser/svg_parser.pyx":28 + * d = pqx*pqx + pqy*pqy + * t = pqx*dx + pqy*dy + * if d > 0: # <<<<<<<<<<<<<< + * t = t/d + * if t < 0: + */ + __pyx_t_1 = ((__pyx_v_d > 0.0) != 0); + if (__pyx_t_1) { + + /* "src/svg_parser/svg_parser.pyx":29 + * t = pqx*dx + pqy*dy + * if d > 0: + * t = t/d # <<<<<<<<<<<<<< + * if t < 0: + * t = 0 + */ + if (unlikely(__pyx_v_d == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 29, __pyx_L1_error) + } + __pyx_v_t = (__pyx_v_t / __pyx_v_d); + + /* "src/svg_parser/svg_parser.pyx":28 + * d = pqx*pqx + pqy*pqy + * t = pqx*dx + pqy*dy + * if d > 0: # <<<<<<<<<<<<<< + * t = t/d + * if t < 0: + */ + } + + /* "src/svg_parser/svg_parser.pyx":30 + * if d > 0: + * t = t/d + * if t < 0: # <<<<<<<<<<<<<< + * t = 0 + * elif t > 1: + */ + __pyx_t_1 = ((__pyx_v_t < 0.0) != 0); + if (__pyx_t_1) { + + /* "src/svg_parser/svg_parser.pyx":31 + * t = t/d + * if t < 0: + * t = 0 # <<<<<<<<<<<<<< + * elif t > 1: + * t = 1 + */ + __pyx_v_t = 0.0; + + /* "src/svg_parser/svg_parser.pyx":30 + * if d > 0: + * t = t/d + * if t < 0: # <<<<<<<<<<<<<< + * t = 0 + * elif t > 1: + */ + goto __pyx_L4; + } + + /* "src/svg_parser/svg_parser.pyx":32 + * if t < 0: + * t = 0 + * elif t > 1: # <<<<<<<<<<<<<< + * t = 1 + * dx = px + t*pqx - x + */ + __pyx_t_1 = ((__pyx_v_t > 1.0) != 0); + if (__pyx_t_1) { + + /* "src/svg_parser/svg_parser.pyx":33 + * t = 0 + * elif t > 1: + * t = 1 # <<<<<<<<<<<<<< + * dx = px + t*pqx - x + * dy = py + t*pqy - y + */ + __pyx_v_t = 1.0; + + /* "src/svg_parser/svg_parser.pyx":32 + * if t < 0: + * t = 0 + * elif t > 1: # <<<<<<<<<<<<<< + * t = 1 + * dx = px + t*pqx - x + */ + } + __pyx_L4:; + + /* "src/svg_parser/svg_parser.pyx":34 + * elif t > 1: + * t = 1 + * dx = px + t*pqx - x # <<<<<<<<<<<<<< + * dy = py + t*pqy - y + * return dx*dx + dy*dy + */ + __pyx_v_dx = ((__pyx_v_px + (__pyx_v_t * __pyx_v_pqx)) - __pyx_v_x); + + /* "src/svg_parser/svg_parser.pyx":35 + * t = 1 + * dx = px + t*pqx - x + * dy = py + t*pqy - y # <<<<<<<<<<<<<< + * return dx*dx + dy*dy + * + */ + __pyx_v_dy = ((__pyx_v_py + (__pyx_v_t * __pyx_v_pqy)) - __pyx_v_y); + + /* "src/svg_parser/svg_parser.pyx":36 + * dx = px + t*pqx - x + * dy = py + t*pqy - y + * return dx*dx + dy*dy # <<<<<<<<<<<<<< + * + * def cubicBez(float x1, float y1, float x2, float y2,float x3, float y3, float x4, float y4,float tol, int level): + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble(((__pyx_v_dx * __pyx_v_dx) + (__pyx_v_dy * __pyx_v_dy))); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 36, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "src/svg_parser/svg_parser.pyx":20 + * NSVGimage* nsvgParse(char* input, const char* units, float dpi); + * + * def distPtSeg(float x, float y, float px, float py, float qx, float qy): # <<<<<<<<<<<<<< + * cdef float pqx, pqy, dx, dy, d, t + * pqx = qx-px + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_AddTraceback("fluxclient.parser._parser.distPtSeg", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "src/svg_parser/svg_parser.pyx":38 + * return dx*dx + dy*dy + * + * def cubicBez(float x1, float y1, float x2, float y2,float x3, float y3, float x4, float y4,float tol, int level): # <<<<<<<<<<<<<< + * cdef float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234 + * cdef float d + */ + +/* Python wrapper */ +static PyObject *__pyx_pw_10fluxclient_6parser_7_parser_3cubicBez(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static PyMethodDef __pyx_mdef_10fluxclient_6parser_7_parser_3cubicBez = {"cubicBez", (PyCFunction)__pyx_pw_10fluxclient_6parser_7_parser_3cubicBez, METH_VARARGS|METH_KEYWORDS, 0}; +static PyObject *__pyx_pw_10fluxclient_6parser_7_parser_3cubicBez(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + float __pyx_v_x1; + float __pyx_v_y1; + float __pyx_v_x2; + float __pyx_v_y2; + float __pyx_v_x3; + float __pyx_v_y3; + float __pyx_v_x4; + float __pyx_v_y4; + float __pyx_v_tol; + int __pyx_v_level; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("cubicBez (wrapper)", 0); + { + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_x1,&__pyx_n_s_y1,&__pyx_n_s_x2,&__pyx_n_s_y2,&__pyx_n_s_x3,&__pyx_n_s_y3,&__pyx_n_s_x4,&__pyx_n_s_y4,&__pyx_n_s_tol,&__pyx_n_s_level,0}; + PyObject* values[10] = {0,0,0,0,0,0,0,0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args); + switch (pos_args) { + case 10: values[9] = PyTuple_GET_ITEM(__pyx_args, 9); + case 9: values[8] = PyTuple_GET_ITEM(__pyx_args, 8); + case 8: values[7] = PyTuple_GET_ITEM(__pyx_args, 7); + case 7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6); + case 6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5); + case 5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + case 4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (pos_args) { + case 0: + if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_x1)) != 0)) kw_args--; + else goto __pyx_L5_argtuple_error; + case 1: + if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_y1)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 1); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 2: + if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_x2)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 2); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 3: + if (likely((values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_y2)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 3); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 4: + if (likely((values[4] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_x3)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 4); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 5: + if (likely((values[5] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_y3)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 5); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 6: + if (likely((values[6] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_x4)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 6); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 7: + if (likely((values[7] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_y4)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 7); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 8: + if (likely((values[8] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_tol)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 8); __PYX_ERR(0, 38, __pyx_L3_error) + } + case 9: + if (likely((values[9] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_level)) != 0)) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, 9); __PYX_ERR(0, 38, __pyx_L3_error) + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "cubicBez") < 0)) __PYX_ERR(0, 38, __pyx_L3_error) + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 10) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + values[3] = PyTuple_GET_ITEM(__pyx_args, 3); + values[4] = PyTuple_GET_ITEM(__pyx_args, 4); + values[5] = PyTuple_GET_ITEM(__pyx_args, 5); + values[6] = PyTuple_GET_ITEM(__pyx_args, 6); + values[7] = PyTuple_GET_ITEM(__pyx_args, 7); + values[8] = PyTuple_GET_ITEM(__pyx_args, 8); + values[9] = PyTuple_GET_ITEM(__pyx_args, 9); + } + __pyx_v_x1 = __pyx_PyFloat_AsFloat(values[0]); if (unlikely((__pyx_v_x1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_y1 = __pyx_PyFloat_AsFloat(values[1]); if (unlikely((__pyx_v_y1 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_x2 = __pyx_PyFloat_AsFloat(values[2]); if (unlikely((__pyx_v_x2 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_y2 = __pyx_PyFloat_AsFloat(values[3]); if (unlikely((__pyx_v_y2 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_x3 = __pyx_PyFloat_AsFloat(values[4]); if (unlikely((__pyx_v_x3 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_y3 = __pyx_PyFloat_AsFloat(values[5]); if (unlikely((__pyx_v_y3 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_x4 = __pyx_PyFloat_AsFloat(values[6]); if (unlikely((__pyx_v_x4 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_y4 = __pyx_PyFloat_AsFloat(values[7]); if (unlikely((__pyx_v_y4 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_tol = __pyx_PyFloat_AsFloat(values[8]); if (unlikely((__pyx_v_tol == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_v_level = __Pyx_PyInt_As_int(values[9]); if (unlikely((__pyx_v_level == (int)-1) && PyErr_Occurred())) __PYX_ERR(0, 38, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("cubicBez", 1, 10, 10, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 38, __pyx_L3_error) + __pyx_L3_error:; + __Pyx_AddTraceback("fluxclient.parser._parser.cubicBez", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_10fluxclient_6parser_7_parser_2cubicBez(__pyx_self, __pyx_v_x1, __pyx_v_y1, __pyx_v_x2, __pyx_v_y2, __pyx_v_x3, __pyx_v_y3, __pyx_v_x4, __pyx_v_y4, __pyx_v_tol, __pyx_v_level); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_10fluxclient_6parser_7_parser_2cubicBez(CYTHON_UNUSED PyObject *__pyx_self, float __pyx_v_x1, float __pyx_v_y1, float __pyx_v_x2, float __pyx_v_y2, float __pyx_v_x3, float __pyx_v_y3, float __pyx_v_x4, float __pyx_v_y4, float __pyx_v_tol, int __pyx_v_level) { + float __pyx_v_x12; + float __pyx_v_y12; + float __pyx_v_x23; + float __pyx_v_y23; + float __pyx_v_x34; + float __pyx_v_y34; + float __pyx_v_x123; + float __pyx_v_y123; + float __pyx_v_x234; + float __pyx_v_y234; + float __pyx_v_x1234; + float __pyx_v_y1234; + float __pyx_v_d; + PyObject *__pyx_v_point_lst = NULL; + PyObject *__pyx_v_a = NULL; + PyObject *__pyx_v_b = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *__pyx_t_6 = NULL; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + PyObject *__pyx_t_9 = NULL; + PyObject *__pyx_t_10 = NULL; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + float __pyx_t_13; + PyObject *__pyx_t_14 = NULL; + PyObject *__pyx_t_15 = NULL; + PyObject *__pyx_t_16 = NULL; + PyObject *__pyx_t_17 = NULL; + int __pyx_t_18; + __Pyx_RefNannySetupContext("cubicBez", 0); + + /* "src/svg_parser/svg_parser.pyx":41 + * cdef float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234 + * cdef float d + * if level > 12: # <<<<<<<<<<<<<< + * return [] + * + */ + __pyx_t_1 = ((__pyx_v_level > 12) != 0); + if (__pyx_t_1) { + + /* "src/svg_parser/svg_parser.pyx":42 + * cdef float d + * if level > 12: + * return [] # <<<<<<<<<<<<<< + * + * x12 = (x1 + x2) * 0.5 + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 42, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_r = __pyx_t_2; + __pyx_t_2 = 0; + goto __pyx_L0; + + /* "src/svg_parser/svg_parser.pyx":41 + * cdef float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234 + * cdef float d + * if level > 12: # <<<<<<<<<<<<<< + * return [] + * + */ + } + + /* "src/svg_parser/svg_parser.pyx":44 + * return [] + * + * x12 = (x1 + x2) * 0.5 # <<<<<<<<<<<<<< + * y12 = (y1 + y2) * 0.5 + * x23 = (x2+x3)*0.5 + */ + __pyx_v_x12 = ((__pyx_v_x1 + __pyx_v_x2) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":45 + * + * x12 = (x1 + x2) * 0.5 + * y12 = (y1 + y2) * 0.5 # <<<<<<<<<<<<<< + * x23 = (x2+x3)*0.5 + * y23 = (y2+y3)*0.5 + */ + __pyx_v_y12 = ((__pyx_v_y1 + __pyx_v_y2) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":46 + * x12 = (x1 + x2) * 0.5 + * y12 = (y1 + y2) * 0.5 + * x23 = (x2+x3)*0.5 # <<<<<<<<<<<<<< + * y23 = (y2+y3)*0.5 + * x34 = (x3+x4)*0.5 + */ + __pyx_v_x23 = ((__pyx_v_x2 + __pyx_v_x3) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":47 + * y12 = (y1 + y2) * 0.5 + * x23 = (x2+x3)*0.5 + * y23 = (y2+y3)*0.5 # <<<<<<<<<<<<<< + * x34 = (x3+x4)*0.5 + * y34 = (y3+y4)*0.5 + */ + __pyx_v_y23 = ((__pyx_v_y2 + __pyx_v_y3) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":48 + * x23 = (x2+x3)*0.5 + * y23 = (y2+y3)*0.5 + * x34 = (x3+x4)*0.5 # <<<<<<<<<<<<<< + * y34 = (y3+y4)*0.5 + * x123 = (x12+x23)*0.5 + */ + __pyx_v_x34 = ((__pyx_v_x3 + __pyx_v_x4) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":49 + * y23 = (y2+y3)*0.5 + * x34 = (x3+x4)*0.5 + * y34 = (y3+y4)*0.5 # <<<<<<<<<<<<<< + * x123 = (x12+x23)*0.5 + * y123 = (y12+y23)*0.5 + */ + __pyx_v_y34 = ((__pyx_v_y3 + __pyx_v_y4) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":50 + * x34 = (x3+x4)*0.5 + * y34 = (y3+y4)*0.5 + * x123 = (x12+x23)*0.5 # <<<<<<<<<<<<<< + * y123 = (y12+y23)*0.5 + * x234 = (x23+x34)*0.5 + */ + __pyx_v_x123 = ((__pyx_v_x12 + __pyx_v_x23) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":51 + * y34 = (y3+y4)*0.5 + * x123 = (x12+x23)*0.5 + * y123 = (y12+y23)*0.5 # <<<<<<<<<<<<<< + * x234 = (x23+x34)*0.5 + * y234 = (y23+y34)*0.5 + */ + __pyx_v_y123 = ((__pyx_v_y12 + __pyx_v_y23) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":52 + * x123 = (x12+x23)*0.5 + * y123 = (y12+y23)*0.5 + * x234 = (x23+x34)*0.5 # <<<<<<<<<<<<<< + * y234 = (y23+y34)*0.5 + * x1234 = (x123+x234)*0.5 + */ + __pyx_v_x234 = ((__pyx_v_x23 + __pyx_v_x34) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":53 + * y123 = (y12+y23)*0.5 + * x234 = (x23+x34)*0.5 + * y234 = (y23+y34)*0.5 # <<<<<<<<<<<<<< + * x1234 = (x123+x234)*0.5 + * y1234 = (y123+y234)*0.5 + */ + __pyx_v_y234 = ((__pyx_v_y23 + __pyx_v_y34) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":54 + * x234 = (x23+x34)*0.5 + * y234 = (y23+y34)*0.5 + * x1234 = (x123+x234)*0.5 # <<<<<<<<<<<<<< + * y1234 = (y123+y234)*0.5 + * d = distPtSeg(x1234, y1234, x1,y1, x4,y4) + */ + __pyx_v_x1234 = ((__pyx_v_x123 + __pyx_v_x234) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":55 + * y234 = (y23+y34)*0.5 + * x1234 = (x123+x234)*0.5 + * y1234 = (y123+y234)*0.5 # <<<<<<<<<<<<<< + * d = distPtSeg(x1234, y1234, x1,y1, x4,y4) + * if d > tol*tol: + */ + __pyx_v_y1234 = ((__pyx_v_y123 + __pyx_v_y234) * 0.5); + + /* "src/svg_parser/svg_parser.pyx":56 + * x1234 = (x123+x234)*0.5 + * y1234 = (y123+y234)*0.5 + * d = distPtSeg(x1234, y1234, x1,y1, x4,y4) # <<<<<<<<<<<<<< + * if d > tol*tol: + * point_lst = [] + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_distPtSeg); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_x1234); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_y1234); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_x1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = PyFloat_FromDouble(__pyx_v_y1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyFloat_FromDouble(__pyx_v_x4); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = PyFloat_FromDouble(__pyx_v_y4); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_10 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_10 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_10)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_10); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[7] = {__pyx_t_10, __pyx_t_4, __pyx_t_5, __pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_11, 6+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[7] = {__pyx_t_10, __pyx_t_4, __pyx_t_5, __pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_11, 6+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_12 = PyTuple_New(6+__pyx_t_11); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + if (__pyx_t_10) { + __Pyx_GIVEREF(__pyx_t_10); PyTuple_SET_ITEM(__pyx_t_12, 0, __pyx_t_10); __pyx_t_10 = NULL; + } + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_12, 0+__pyx_t_11, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_12, 1+__pyx_t_11, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_12, 2+__pyx_t_11, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_12, 3+__pyx_t_11, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_12, 4+__pyx_t_11, __pyx_t_8); + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_12, 5+__pyx_t_11, __pyx_t_9); + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_8 = 0; + __pyx_t_9 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_12, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_t_13 = __pyx_PyFloat_AsFloat(__pyx_t_2); if (unlikely((__pyx_t_13 == (float)-1) && PyErr_Occurred())) __PYX_ERR(0, 56, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_d = __pyx_t_13; + + /* "src/svg_parser/svg_parser.pyx":57 + * y1234 = (y123+y234)*0.5 + * d = distPtSeg(x1234, y1234, x1,y1, x4,y4) + * if d > tol*tol: # <<<<<<<<<<<<<< + * point_lst = [] + * a = cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1) + */ + __pyx_t_1 = ((__pyx_v_d > (__pyx_v_tol * __pyx_v_tol)) != 0); + if (__pyx_t_1) { + + /* "src/svg_parser/svg_parser.pyx":58 + * d = distPtSeg(x1234, y1234, x1,y1, x4,y4) + * if d > tol*tol: + * point_lst = [] # <<<<<<<<<<<<<< + * a = cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1) + * b = cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1) + */ + __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 58, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_v_point_lst = ((PyObject*)__pyx_t_2); + __pyx_t_2 = 0; + + /* "src/svg_parser/svg_parser.pyx":59 + * if d > tol*tol: + * point_lst = [] + * a = cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1) # <<<<<<<<<<<<<< + * b = cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1) + * point_lst.extend(a) + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_cubicBez); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_12 = PyFloat_FromDouble(__pyx_v_x1); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_9 = PyFloat_FromDouble(__pyx_v_y1); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_8 = PyFloat_FromDouble(__pyx_v_x12); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_7 = PyFloat_FromDouble(__pyx_v_y12); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_x123); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_y123); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_x1234); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_10 = PyFloat_FromDouble(__pyx_v_y1234); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_14 = PyFloat_FromDouble(__pyx_v_tol); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_15 = __Pyx_PyInt_From_long((__pyx_v_level + 1)); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_16 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_16 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_16)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_16); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[11] = {__pyx_t_16, __pyx_t_12, __pyx_t_9, __pyx_t_8, __pyx_t_7, __pyx_t_6, __pyx_t_5, __pyx_t_4, __pyx_t_10, __pyx_t_14, __pyx_t_15}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_11, 10+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_16); __pyx_t_16 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[11] = {__pyx_t_16, __pyx_t_12, __pyx_t_9, __pyx_t_8, __pyx_t_7, __pyx_t_6, __pyx_t_5, __pyx_t_4, __pyx_t_10, __pyx_t_14, __pyx_t_15}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_11, 10+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_16); __pyx_t_16 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + } else + #endif + { + __pyx_t_17 = PyTuple_New(10+__pyx_t_11); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_17); + if (__pyx_t_16) { + __Pyx_GIVEREF(__pyx_t_16); PyTuple_SET_ITEM(__pyx_t_17, 0, __pyx_t_16); __pyx_t_16 = NULL; + } + __Pyx_GIVEREF(__pyx_t_12); + PyTuple_SET_ITEM(__pyx_t_17, 0+__pyx_t_11, __pyx_t_12); + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_17, 1+__pyx_t_11, __pyx_t_9); + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_17, 2+__pyx_t_11, __pyx_t_8); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_17, 3+__pyx_t_11, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_17, 4+__pyx_t_11, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_17, 5+__pyx_t_11, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_17, 6+__pyx_t_11, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_17, 7+__pyx_t_11, __pyx_t_10); + __Pyx_GIVEREF(__pyx_t_14); + PyTuple_SET_ITEM(__pyx_t_17, 8+__pyx_t_11, __pyx_t_14); + __Pyx_GIVEREF(__pyx_t_15); + PyTuple_SET_ITEM(__pyx_t_17, 9+__pyx_t_11, __pyx_t_15); + __pyx_t_12 = 0; + __pyx_t_9 = 0; + __pyx_t_8 = 0; + __pyx_t_7 = 0; + __pyx_t_6 = 0; + __pyx_t_5 = 0; + __pyx_t_4 = 0; + __pyx_t_10 = 0; + __pyx_t_14 = 0; + __pyx_t_15 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_17, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 59, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_a = __pyx_t_2; + __pyx_t_2 = 0; + + /* "src/svg_parser/svg_parser.pyx":60 + * point_lst = [] + * a = cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1) + * b = cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1) # <<<<<<<<<<<<<< + * point_lst.extend(a) + * point_lst.extend(b) + */ + __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_cubicBez); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_17 = PyFloat_FromDouble(__pyx_v_x1234); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_17); + __pyx_t_15 = PyFloat_FromDouble(__pyx_v_y1234); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_14 = PyFloat_FromDouble(__pyx_v_x234); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_10 = PyFloat_FromDouble(__pyx_v_y234); if (unlikely(!__pyx_t_10)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_10); + __pyx_t_4 = PyFloat_FromDouble(__pyx_v_x34); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_5 = PyFloat_FromDouble(__pyx_v_y34); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = PyFloat_FromDouble(__pyx_v_x4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_6); + __pyx_t_7 = PyFloat_FromDouble(__pyx_v_y4); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyFloat_FromDouble(__pyx_v_tol); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __pyx_t_9 = __Pyx_PyInt_From_long((__pyx_v_level + 1)); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_9); + __pyx_t_12 = NULL; + __pyx_t_11 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) { + __pyx_t_12 = PyMethod_GET_SELF(__pyx_t_3); + if (likely(__pyx_t_12)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3); + __Pyx_INCREF(__pyx_t_12); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_3, function); + __pyx_t_11 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[11] = {__pyx_t_12, __pyx_t_17, __pyx_t_15, __pyx_t_14, __pyx_t_10, __pyx_t_4, __pyx_t_5, __pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9}; + __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_11, 10+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) { + PyObject *__pyx_temp[11] = {__pyx_t_12, __pyx_t_17, __pyx_t_15, __pyx_t_14, __pyx_t_10, __pyx_t_4, __pyx_t_5, __pyx_t_6, __pyx_t_7, __pyx_t_8, __pyx_t_9}; + __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-__pyx_t_11, 10+__pyx_t_11); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_10); __pyx_t_10 = 0; + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0; + } else + #endif + { + __pyx_t_16 = PyTuple_New(10+__pyx_t_11); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_16); + if (__pyx_t_12) { + __Pyx_GIVEREF(__pyx_t_12); PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_t_12); __pyx_t_12 = NULL; + } + __Pyx_GIVEREF(__pyx_t_17); + PyTuple_SET_ITEM(__pyx_t_16, 0+__pyx_t_11, __pyx_t_17); + __Pyx_GIVEREF(__pyx_t_15); + PyTuple_SET_ITEM(__pyx_t_16, 1+__pyx_t_11, __pyx_t_15); + __Pyx_GIVEREF(__pyx_t_14); + PyTuple_SET_ITEM(__pyx_t_16, 2+__pyx_t_11, __pyx_t_14); + __Pyx_GIVEREF(__pyx_t_10); + PyTuple_SET_ITEM(__pyx_t_16, 3+__pyx_t_11, __pyx_t_10); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_16, 4+__pyx_t_11, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_5); + PyTuple_SET_ITEM(__pyx_t_16, 5+__pyx_t_11, __pyx_t_5); + __Pyx_GIVEREF(__pyx_t_6); + PyTuple_SET_ITEM(__pyx_t_16, 6+__pyx_t_11, __pyx_t_6); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_16, 7+__pyx_t_11, __pyx_t_7); + __Pyx_GIVEREF(__pyx_t_8); + PyTuple_SET_ITEM(__pyx_t_16, 8+__pyx_t_11, __pyx_t_8); + __Pyx_GIVEREF(__pyx_t_9); + PyTuple_SET_ITEM(__pyx_t_16, 9+__pyx_t_11, __pyx_t_9); + __pyx_t_17 = 0; + __pyx_t_15 = 0; + __pyx_t_14 = 0; + __pyx_t_10 = 0; + __pyx_t_4 = 0; + __pyx_t_5 = 0; + __pyx_t_6 = 0; + __pyx_t_7 = 0; + __pyx_t_8 = 0; + __pyx_t_9 = 0; + __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_16, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 60, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; + } + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __pyx_v_b = __pyx_t_2; + __pyx_t_2 = 0; + + /* "src/svg_parser/svg_parser.pyx":61 + * a = cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1) + * b = cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1) + * point_lst.extend(a) # <<<<<<<<<<<<<< + * point_lst.extend(b) + * return point_lst + */ + __pyx_t_18 = __Pyx_PyList_Extend(__pyx_v_point_lst, __pyx_v_a); if (unlikely(__pyx_t_18 == -1)) __PYX_ERR(0, 61, __pyx_L1_error) + + /* "src/svg_parser/svg_parser.pyx":62 + * b = cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1) + * point_lst.extend(a) + * point_lst.extend(b) # <<<<<<<<<<<<<< + * return point_lst + * else: + */ + __pyx_t_18 = __Pyx_PyList_Extend(__pyx_v_point_lst, __pyx_v_b); if (unlikely(__pyx_t_18 == -1)) __PYX_ERR(0, 62, __pyx_L1_error) + + /* "src/svg_parser/svg_parser.pyx":63 + * point_lst.extend(a) + * point_lst.extend(b) + * return point_lst # <<<<<<<<<<<<<< + * else: + * + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_point_lst); + __pyx_r = __pyx_v_point_lst; + goto __pyx_L0; + + /* "src/svg_parser/svg_parser.pyx":57 + * y1234 = (y123+y234)*0.5 + * d = distPtSeg(x1234, y1234, x1,y1, x4,y4) + * if d > tol*tol: # <<<<<<<<<<<<<< + * point_lst = [] + * a = cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1) + */ + } + + /* "src/svg_parser/svg_parser.pyx":66 + * else: + * + * return [(x4,y4)] # <<<<<<<<<<<<<< + * + * cpdef get_all_points(char* svg_data): + */ + /*else*/ { + __Pyx_XDECREF(__pyx_r); + __pyx_t_2 = PyFloat_FromDouble(__pyx_v_x4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyFloat_FromDouble(__pyx_v_y4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_16 = PyTuple_New(2); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_16); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_16, 1, __pyx_t_3); + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_3 = PyList_New(1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 66, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_3); + __Pyx_GIVEREF(__pyx_t_16); + PyList_SET_ITEM(__pyx_t_3, 0, __pyx_t_16); + __pyx_t_16 = 0; + __pyx_r = __pyx_t_3; + __pyx_t_3 = 0; + goto __pyx_L0; + } + + /* "src/svg_parser/svg_parser.pyx":38 + * return dx*dx + dy*dy + * + * def cubicBez(float x1, float y1, float x2, float y2,float x3, float y3, float x4, float y4,float tol, int level): # <<<<<<<<<<<<<< + * cdef float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234 + * cdef float d + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_XDECREF(__pyx_t_6); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_9); + __Pyx_XDECREF(__pyx_t_10); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_XDECREF(__pyx_t_14); + __Pyx_XDECREF(__pyx_t_15); + __Pyx_XDECREF(__pyx_t_16); + __Pyx_XDECREF(__pyx_t_17); + __Pyx_AddTraceback("fluxclient.parser._parser.cubicBez", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_point_lst); + __Pyx_XDECREF(__pyx_v_a); + __Pyx_XDECREF(__pyx_v_b); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "src/svg_parser/svg_parser.pyx":68 + * return [(x4,y4)] + * + * cpdef get_all_points(char* svg_data): # <<<<<<<<<<<<<< + * cdef NSVGimage* g_image + * cdef NSVGpath * path + */ + +static PyObject *__pyx_pw_10fluxclient_6parser_7_parser_5get_all_points(PyObject *__pyx_self, PyObject *__pyx_arg_svg_data); /*proto*/ +static PyObject *__pyx_f_10fluxclient_6parser_7_parser_get_all_points(char *__pyx_v_svg_data, CYTHON_UNUSED int __pyx_skip_dispatch) { + NSVGimage *__pyx_v_g_image; + struct NSVGpath *__pyx_v_path; + float *__pyx_v_p; + int __pyx_v_i; + float __pyx_v_cx; + float __pyx_v_cy; + float __pyx_v_hw; + float __pyx_v_hh; + float __pyx_v_width; + float __pyx_v_height; + float __pyx_v_view_2; + float __pyx_v_view_1; + float __pyx_v_px; + float __pyx_v_aspect; + struct NSVGshape *__pyx_v_shape; + PyObject *__pyx_v_path_lst = NULL; + PyObject *__pyx_v_point_lst = NULL; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + float __pyx_t_2; + struct NSVGshape *__pyx_t_3; + PyObject *__pyx_t_4 = NULL; + struct NSVGpath *__pyx_t_5; + float *__pyx_t_6; + PyObject *__pyx_t_7 = NULL; + PyObject *__pyx_t_8 = NULL; + int __pyx_t_9; + long __pyx_t_10; + int __pyx_t_11; + PyObject *__pyx_t_12 = NULL; + PyObject *__pyx_t_13 = NULL; + PyObject *__pyx_t_14 = NULL; + PyObject *__pyx_t_15 = NULL; + PyObject *__pyx_t_16 = NULL; + PyObject *__pyx_t_17 = NULL; + PyObject *__pyx_t_18 = NULL; + PyObject *__pyx_t_19 = NULL; + PyObject *__pyx_t_20 = NULL; + int __pyx_t_21; + PyObject *__pyx_t_22 = NULL; + __Pyx_RefNannySetupContext("get_all_points", 0); + + /* "src/svg_parser/svg_parser.pyx":76 + * cdef float width,height + * cdef float view_2,view_1,px,aspect + * g_image = nsvgParse(svg_data, "px", 96.0) # <<<<<<<<<<<<<< + * + * cx = g_image.width * 0.5 + */ + __pyx_v_g_image = nsvgParse(__pyx_v_svg_data, ((char const *)"px"), 96.0); + + /* "src/svg_parser/svg_parser.pyx":78 + * g_image = nsvgParse(svg_data, "px", 96.0) + * + * cx = g_image.width * 0.5 # <<<<<<<<<<<<<< + * cy = g_image.height * 0.5 + * hw = g_image.width*0.5 + */ + __pyx_v_cx = (__pyx_v_g_image->width * 0.5); + + /* "src/svg_parser/svg_parser.pyx":79 + * + * cx = g_image.width * 0.5 + * cy = g_image.height * 0.5 # <<<<<<<<<<<<<< + * hw = g_image.width*0.5 + * hh = g_image.height*0.5 + */ + __pyx_v_cy = (__pyx_v_g_image->height * 0.5); + + /* "src/svg_parser/svg_parser.pyx":80 + * cx = g_image.width * 0.5 + * cy = g_image.height * 0.5 + * hw = g_image.width*0.5 # <<<<<<<<<<<<<< + * hh = g_image.height*0.5 + * width = 1880.0 + */ + __pyx_v_hw = (__pyx_v_g_image->width * 0.5); + + /* "src/svg_parser/svg_parser.pyx":81 + * cy = g_image.height * 0.5 + * hw = g_image.width*0.5 + * hh = g_image.height*0.5 # <<<<<<<<<<<<<< + * width = 1880.0 + * height = 955.0 + */ + __pyx_v_hh = (__pyx_v_g_image->height * 0.5); + + /* "src/svg_parser/svg_parser.pyx":82 + * hw = g_image.width*0.5 + * hh = g_image.height*0.5 + * width = 1880.0 # <<<<<<<<<<<<<< + * height = 955.0 + * if width/hw < height/hh: + */ + __pyx_v_width = 1880.0; + + /* "src/svg_parser/svg_parser.pyx":83 + * hh = g_image.height*0.5 + * width = 1880.0 + * height = 955.0 # <<<<<<<<<<<<<< + * if width/hw < height/hh: + * aspect = height / width + */ + __pyx_v_height = 955.0; + + /* "src/svg_parser/svg_parser.pyx":84 + * width = 1880.0 + * height = 955.0 + * if width/hw < height/hh: # <<<<<<<<<<<<<< + * aspect = height / width + * view_2 = cx + hw * 1.2 + */ + if (unlikely(__pyx_v_hw == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 84, __pyx_L1_error) + } + if (unlikely(__pyx_v_hh == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 84, __pyx_L1_error) + } + __pyx_t_1 = (((__pyx_v_width / __pyx_v_hw) < (__pyx_v_height / __pyx_v_hh)) != 0); + if (__pyx_t_1) { + + /* "src/svg_parser/svg_parser.pyx":85 + * height = 955.0 + * if width/hw < height/hh: + * aspect = height / width # <<<<<<<<<<<<<< + * view_2 = cx + hw * 1.2 + * view_1 = cy - hw * 1.2 * aspect + */ + if (unlikely(__pyx_v_width == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 85, __pyx_L1_error) + } + __pyx_v_aspect = (__pyx_v_height / __pyx_v_width); + + /* "src/svg_parser/svg_parser.pyx":86 + * if width/hw < height/hh: + * aspect = height / width + * view_2 = cx + hw * 1.2 # <<<<<<<<<<<<<< + * view_1 = cy - hw * 1.2 * aspect + * + */ + __pyx_v_view_2 = (__pyx_v_cx + (__pyx_v_hw * 1.2)); + + /* "src/svg_parser/svg_parser.pyx":87 + * aspect = height / width + * view_2 = cx + hw * 1.2 + * view_1 = cy - hw * 1.2 * aspect # <<<<<<<<<<<<<< + * + * else: + */ + __pyx_v_view_1 = (__pyx_v_cy - ((__pyx_v_hw * 1.2) * __pyx_v_aspect)); + + /* "src/svg_parser/svg_parser.pyx":84 + * width = 1880.0 + * height = 955.0 + * if width/hw < height/hh: # <<<<<<<<<<<<<< + * aspect = height / width + * view_2 = cx + hw * 1.2 + */ + goto __pyx_L3; + } + + /* "src/svg_parser/svg_parser.pyx":90 + * + * else: + * aspect = width / height # <<<<<<<<<<<<<< + * view_2 = cx + hh * 1.2 * aspect + * view_1 = cy - hh * 1.2 + */ + /*else*/ { + if (unlikely(__pyx_v_height == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 90, __pyx_L1_error) + } + __pyx_v_aspect = (__pyx_v_width / __pyx_v_height); + + /* "src/svg_parser/svg_parser.pyx":91 + * else: + * aspect = width / height + * view_2 = cx + hh * 1.2 * aspect # <<<<<<<<<<<<<< + * view_1 = cy - hh * 1.2 + * + */ + __pyx_v_view_2 = (__pyx_v_cx + ((__pyx_v_hh * 1.2) * __pyx_v_aspect)); + + /* "src/svg_parser/svg_parser.pyx":92 + * aspect = width / height + * view_2 = cx + hh * 1.2 * aspect + * view_1 = cy - hh * 1.2 # <<<<<<<<<<<<<< + * + * px = (view_2 - view_1) / width; + */ + __pyx_v_view_1 = (__pyx_v_cy - (__pyx_v_hh * 1.2)); + } + __pyx_L3:; + + /* "src/svg_parser/svg_parser.pyx":94 + * view_1 = cy - hh * 1.2 + * + * px = (view_2 - view_1) / width; # <<<<<<<<<<<<<< + * + * cdef NSVGshape * shape = g_image.shapes + */ + __pyx_t_2 = (__pyx_v_view_2 - __pyx_v_view_1); + if (unlikely(__pyx_v_width == 0)) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + __PYX_ERR(0, 94, __pyx_L1_error) + } + __pyx_v_px = (__pyx_t_2 / __pyx_v_width); + + /* "src/svg_parser/svg_parser.pyx":96 + * px = (view_2 - view_1) / width; + * + * cdef NSVGshape * shape = g_image.shapes # <<<<<<<<<<<<<< + * path_lst = [] + * while shape != NULL: + */ + __pyx_t_3 = __pyx_v_g_image->shapes; + __pyx_v_shape = __pyx_t_3; + + /* "src/svg_parser/svg_parser.pyx":97 + * + * cdef NSVGshape * shape = g_image.shapes + * path_lst = [] # <<<<<<<<<<<<<< + * while shape != NULL: + * path = shape.paths + */ + __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 97, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_v_path_lst = ((PyObject*)__pyx_t_4); + __pyx_t_4 = 0; + + /* "src/svg_parser/svg_parser.pyx":98 + * cdef NSVGshape * shape = g_image.shapes + * path_lst = [] + * while shape != NULL: # <<<<<<<<<<<<<< + * path = shape.paths + * while path != NULL: + */ + while (1) { + __pyx_t_1 = ((__pyx_v_shape != NULL) != 0); + if (!__pyx_t_1) break; + + /* "src/svg_parser/svg_parser.pyx":99 + * path_lst = [] + * while shape != NULL: + * path = shape.paths # <<<<<<<<<<<<<< + * while path != NULL: + * point_lst = [] + */ + __pyx_t_5 = __pyx_v_shape->paths; + __pyx_v_path = __pyx_t_5; + + /* "src/svg_parser/svg_parser.pyx":100 + * while shape != NULL: + * path = shape.paths + * while path != NULL: # <<<<<<<<<<<<<< + * point_lst = [] + * p = path.pts + */ + while (1) { + __pyx_t_1 = ((__pyx_v_path != NULL) != 0); + if (!__pyx_t_1) break; + + /* "src/svg_parser/svg_parser.pyx":101 + * path = shape.paths + * while path != NULL: + * point_lst = [] # <<<<<<<<<<<<<< + * p = path.pts + * point_lst.append((p[0],p[1])) + */ + __pyx_t_4 = PyList_New(0); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 101, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __Pyx_XDECREF_SET(__pyx_v_point_lst, ((PyObject*)__pyx_t_4)); + __pyx_t_4 = 0; + + /* "src/svg_parser/svg_parser.pyx":102 + * while path != NULL: + * point_lst = [] + * p = path.pts # <<<<<<<<<<<<<< + * point_lst.append((p[0],p[1])) + * for i in range(0,path.npts-1,3): + */ + __pyx_t_6 = __pyx_v_path->pts; + __pyx_v_p = __pyx_t_6; + + /* "src/svg_parser/svg_parser.pyx":103 + * point_lst = [] + * p = path.pts + * point_lst.append((p[0],p[1])) # <<<<<<<<<<<<<< + * for i in range(0,path.npts-1,3): + * p = path.pts + i*2 + */ + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_p[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 103, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_7 = PyFloat_FromDouble((__pyx_v_p[1])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 103, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 103, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_7); + PyTuple_SET_ITEM(__pyx_t_8, 1, __pyx_t_7); + __pyx_t_4 = 0; + __pyx_t_7 = 0; + __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_point_lst, __pyx_t_8); if (unlikely(__pyx_t_9 == -1)) __PYX_ERR(0, 103, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + + /* "src/svg_parser/svg_parser.pyx":104 + * p = path.pts + * point_lst.append((p[0],p[1])) + * for i in range(0,path.npts-1,3): # <<<<<<<<<<<<<< + * p = path.pts + i*2 + * #point_lst.extend(cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], px * 1.5, 0)) + */ + __pyx_t_10 = (__pyx_v_path->npts - 1); + for (__pyx_t_11 = 0; __pyx_t_11 < __pyx_t_10; __pyx_t_11+=3) { + __pyx_v_i = __pyx_t_11; + + /* "src/svg_parser/svg_parser.pyx":105 + * point_lst.append((p[0],p[1])) + * for i in range(0,path.npts-1,3): + * p = path.pts + i*2 # <<<<<<<<<<<<<< + * #point_lst.extend(cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], px * 1.5, 0)) + * point_lst.extend(cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], px * 0.001, 0)) + */ + __pyx_v_p = (__pyx_v_path->pts + (__pyx_v_i * 2)); + + /* "src/svg_parser/svg_parser.pyx":107 + * p = path.pts + i*2 + * #point_lst.extend(cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], px * 1.5, 0)) + * point_lst.extend(cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], px * 0.001, 0)) # <<<<<<<<<<<<<< + * #if path.closed: + * #point_lst.append((path.pts[0],path.pts[1])) + */ + __pyx_t_7 = __Pyx_GetModuleGlobalName(__pyx_n_s_cubicBez); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_7); + __pyx_t_4 = PyFloat_FromDouble((__pyx_v_p[0])); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_12 = PyFloat_FromDouble((__pyx_v_p[1])); if (unlikely(!__pyx_t_12)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_12); + __pyx_t_13 = PyFloat_FromDouble((__pyx_v_p[2])); if (unlikely(!__pyx_t_13)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_13); + __pyx_t_14 = PyFloat_FromDouble((__pyx_v_p[3])); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_14); + __pyx_t_15 = PyFloat_FromDouble((__pyx_v_p[4])); if (unlikely(!__pyx_t_15)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_15); + __pyx_t_16 = PyFloat_FromDouble((__pyx_v_p[5])); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_16); + __pyx_t_17 = PyFloat_FromDouble((__pyx_v_p[6])); if (unlikely(!__pyx_t_17)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_17); + __pyx_t_18 = PyFloat_FromDouble((__pyx_v_p[7])); if (unlikely(!__pyx_t_18)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_18); + __pyx_t_19 = PyFloat_FromDouble((__pyx_v_px * 0.001)); if (unlikely(!__pyx_t_19)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_19); + __pyx_t_20 = NULL; + __pyx_t_21 = 0; + if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_7))) { + __pyx_t_20 = PyMethod_GET_SELF(__pyx_t_7); + if (likely(__pyx_t_20)) { + PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_7); + __Pyx_INCREF(__pyx_t_20); + __Pyx_INCREF(function); + __Pyx_DECREF_SET(__pyx_t_7, function); + __pyx_t_21 = 1; + } + } + #if CYTHON_FAST_PYCALL + if (PyFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[11] = {__pyx_t_20, __pyx_t_4, __pyx_t_12, __pyx_t_13, __pyx_t_14, __pyx_t_15, __pyx_t_16, __pyx_t_17, __pyx_t_18, __pyx_t_19, __pyx_int_0}; + __pyx_t_8 = __Pyx_PyFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_21, 10+__pyx_t_21); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_20); __pyx_t_20 = 0; + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + } else + #endif + #if CYTHON_FAST_PYCCALL + if (__Pyx_PyFastCFunction_Check(__pyx_t_7)) { + PyObject *__pyx_temp[11] = {__pyx_t_20, __pyx_t_4, __pyx_t_12, __pyx_t_13, __pyx_t_14, __pyx_t_15, __pyx_t_16, __pyx_t_17, __pyx_t_18, __pyx_t_19, __pyx_int_0}; + __pyx_t_8 = __Pyx_PyCFunction_FastCall(__pyx_t_7, __pyx_temp+1-__pyx_t_21, 10+__pyx_t_21); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_XDECREF(__pyx_t_20); __pyx_t_20 = 0; + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_DECREF(__pyx_t_12); __pyx_t_12 = 0; + __Pyx_DECREF(__pyx_t_13); __pyx_t_13 = 0; + __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0; + __Pyx_DECREF(__pyx_t_15); __pyx_t_15 = 0; + __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0; + __Pyx_DECREF(__pyx_t_17); __pyx_t_17 = 0; + __Pyx_DECREF(__pyx_t_18); __pyx_t_18 = 0; + __Pyx_DECREF(__pyx_t_19); __pyx_t_19 = 0; + } else + #endif + { + __pyx_t_22 = PyTuple_New(10+__pyx_t_21); if (unlikely(!__pyx_t_22)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_22); + if (__pyx_t_20) { + __Pyx_GIVEREF(__pyx_t_20); PyTuple_SET_ITEM(__pyx_t_22, 0, __pyx_t_20); __pyx_t_20 = NULL; + } + __Pyx_GIVEREF(__pyx_t_4); + PyTuple_SET_ITEM(__pyx_t_22, 0+__pyx_t_21, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_12); + PyTuple_SET_ITEM(__pyx_t_22, 1+__pyx_t_21, __pyx_t_12); + __Pyx_GIVEREF(__pyx_t_13); + PyTuple_SET_ITEM(__pyx_t_22, 2+__pyx_t_21, __pyx_t_13); + __Pyx_GIVEREF(__pyx_t_14); + PyTuple_SET_ITEM(__pyx_t_22, 3+__pyx_t_21, __pyx_t_14); + __Pyx_GIVEREF(__pyx_t_15); + PyTuple_SET_ITEM(__pyx_t_22, 4+__pyx_t_21, __pyx_t_15); + __Pyx_GIVEREF(__pyx_t_16); + PyTuple_SET_ITEM(__pyx_t_22, 5+__pyx_t_21, __pyx_t_16); + __Pyx_GIVEREF(__pyx_t_17); + PyTuple_SET_ITEM(__pyx_t_22, 6+__pyx_t_21, __pyx_t_17); + __Pyx_GIVEREF(__pyx_t_18); + PyTuple_SET_ITEM(__pyx_t_22, 7+__pyx_t_21, __pyx_t_18); + __Pyx_GIVEREF(__pyx_t_19); + PyTuple_SET_ITEM(__pyx_t_22, 8+__pyx_t_21, __pyx_t_19); + __Pyx_INCREF(__pyx_int_0); + __Pyx_GIVEREF(__pyx_int_0); + PyTuple_SET_ITEM(__pyx_t_22, 9+__pyx_t_21, __pyx_int_0); + __pyx_t_4 = 0; + __pyx_t_12 = 0; + __pyx_t_13 = 0; + __pyx_t_14 = 0; + __pyx_t_15 = 0; + __pyx_t_16 = 0; + __pyx_t_17 = 0; + __pyx_t_18 = 0; + __pyx_t_19 = 0; + __pyx_t_8 = __Pyx_PyObject_Call(__pyx_t_7, __pyx_t_22, NULL); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_8); + __Pyx_DECREF(__pyx_t_22); __pyx_t_22 = 0; + } + __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; + __pyx_t_9 = __Pyx_PyList_Extend(__pyx_v_point_lst, __pyx_t_8); if (unlikely(__pyx_t_9 == -1)) __PYX_ERR(0, 107, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0; + } + + /* "src/svg_parser/svg_parser.pyx":110 + * #if path.closed: + * #point_lst.append((path.pts[0],path.pts[1])) + * path_lst.append(point_lst) # <<<<<<<<<<<<<< + * path = path.next + * shape = shape.next + */ + __pyx_t_9 = __Pyx_PyList_Append(__pyx_v_path_lst, __pyx_v_point_lst); if (unlikely(__pyx_t_9 == -1)) __PYX_ERR(0, 110, __pyx_L1_error) + + /* "src/svg_parser/svg_parser.pyx":111 + * #point_lst.append((path.pts[0],path.pts[1])) + * path_lst.append(point_lst) + * path = path.next # <<<<<<<<<<<<<< + * shape = shape.next + * return path_lst + */ + __pyx_t_5 = __pyx_v_path->next; + __pyx_v_path = __pyx_t_5; + } + + /* "src/svg_parser/svg_parser.pyx":112 + * path_lst.append(point_lst) + * path = path.next + * shape = shape.next # <<<<<<<<<<<<<< + * return path_lst + */ + __pyx_t_3 = __pyx_v_shape->next; + __pyx_v_shape = __pyx_t_3; + } + + /* "src/svg_parser/svg_parser.pyx":113 + * path = path.next + * shape = shape.next + * return path_lst # <<<<<<<<<<<<<< + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(__pyx_v_path_lst); + __pyx_r = __pyx_v_path_lst; + goto __pyx_L0; + + /* "src/svg_parser/svg_parser.pyx":68 + * return [(x4,y4)] + * + * cpdef get_all_points(char* svg_data): # <<<<<<<<<<<<<< + * cdef NSVGimage* g_image + * cdef NSVGpath * path + */ + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_7); + __Pyx_XDECREF(__pyx_t_8); + __Pyx_XDECREF(__pyx_t_12); + __Pyx_XDECREF(__pyx_t_13); + __Pyx_XDECREF(__pyx_t_14); + __Pyx_XDECREF(__pyx_t_15); + __Pyx_XDECREF(__pyx_t_16); + __Pyx_XDECREF(__pyx_t_17); + __Pyx_XDECREF(__pyx_t_18); + __Pyx_XDECREF(__pyx_t_19); + __Pyx_XDECREF(__pyx_t_20); + __Pyx_XDECREF(__pyx_t_22); + __Pyx_AddTraceback("fluxclient.parser._parser.get_all_points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_path_lst); + __Pyx_XDECREF(__pyx_v_point_lst); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* Python wrapper */ +static PyObject *__pyx_pw_10fluxclient_6parser_7_parser_5get_all_points(PyObject *__pyx_self, PyObject *__pyx_arg_svg_data); /*proto*/ +static PyObject *__pyx_pw_10fluxclient_6parser_7_parser_5get_all_points(PyObject *__pyx_self, PyObject *__pyx_arg_svg_data) { + char *__pyx_v_svg_data; + PyObject *__pyx_r = 0; + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("get_all_points (wrapper)", 0); + assert(__pyx_arg_svg_data); { + __pyx_v_svg_data = __Pyx_PyObject_AsString(__pyx_arg_svg_data); if (unlikely((!__pyx_v_svg_data) && PyErr_Occurred())) __PYX_ERR(0, 68, __pyx_L3_error) + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L3_error:; + __Pyx_AddTraceback("fluxclient.parser._parser.get_all_points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + __pyx_r = __pyx_pf_10fluxclient_6parser_7_parser_4get_all_points(__pyx_self, ((char *)__pyx_v_svg_data)); + + /* function exit code */ + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyObject *__pyx_pf_10fluxclient_6parser_7_parser_4get_all_points(CYTHON_UNUSED PyObject *__pyx_self, char *__pyx_v_svg_data) { + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannySetupContext("get_all_points", 0); + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_10fluxclient_6parser_7_parser_get_all_points(__pyx_v_svg_data, 0); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 68, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; + + /* function exit code */ + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("fluxclient.parser._parser.get_all_points", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +static PyMethodDef __pyx_methods[] = { + {"get_all_points", (PyCFunction)__pyx_pw_10fluxclient_6parser_7_parser_5get_all_points, METH_O, 0}, + {0, 0, 0, 0} +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef __pyx_moduledef = { + #if PY_VERSION_HEX < 0x03020000 + { PyObject_HEAD_INIT(NULL) NULL, 0, NULL }, + #else + PyModuleDef_HEAD_INIT, + #endif + "_parser", + 0, /* m_doc */ + -1, /* m_size */ + __pyx_methods /* m_methods */, + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL /* m_free */ +}; +#endif + +static __Pyx_StringTabEntry __pyx_string_tab[] = { + {&__pyx_kp_s_Users_simon_Dev_fluxclient_dev, __pyx_k_Users_simon_Dev_fluxclient_dev, sizeof(__pyx_k_Users_simon_Dev_fluxclient_dev), 0, 0, 1, 0}, + {&__pyx_n_s_a, __pyx_k_a, sizeof(__pyx_k_a), 0, 0, 1, 1}, + {&__pyx_n_s_b, __pyx_k_b, sizeof(__pyx_k_b), 0, 0, 1, 1}, + {&__pyx_n_s_cubicBez, __pyx_k_cubicBez, sizeof(__pyx_k_cubicBez), 0, 0, 1, 1}, + {&__pyx_n_s_d, __pyx_k_d, sizeof(__pyx_k_d), 0, 0, 1, 1}, + {&__pyx_n_s_distPtSeg, __pyx_k_distPtSeg, sizeof(__pyx_k_distPtSeg), 0, 0, 1, 1}, + {&__pyx_n_s_dx, __pyx_k_dx, sizeof(__pyx_k_dx), 0, 0, 1, 1}, + {&__pyx_n_s_dy, __pyx_k_dy, sizeof(__pyx_k_dy), 0, 0, 1, 1}, + {&__pyx_n_s_fluxclient_parser__parser, __pyx_k_fluxclient_parser__parser, sizeof(__pyx_k_fluxclient_parser__parser), 0, 0, 1, 1}, + {&__pyx_n_s_level, __pyx_k_level, sizeof(__pyx_k_level), 0, 0, 1, 1}, + {&__pyx_n_s_main, __pyx_k_main, sizeof(__pyx_k_main), 0, 0, 1, 1}, + {&__pyx_n_s_point_lst, __pyx_k_point_lst, sizeof(__pyx_k_point_lst), 0, 0, 1, 1}, + {&__pyx_n_s_pqx, __pyx_k_pqx, sizeof(__pyx_k_pqx), 0, 0, 1, 1}, + {&__pyx_n_s_pqy, __pyx_k_pqy, sizeof(__pyx_k_pqy), 0, 0, 1, 1}, + {&__pyx_n_s_px, __pyx_k_px, sizeof(__pyx_k_px), 0, 0, 1, 1}, + {&__pyx_n_s_py, __pyx_k_py, sizeof(__pyx_k_py), 0, 0, 1, 1}, + {&__pyx_n_s_qx, __pyx_k_qx, sizeof(__pyx_k_qx), 0, 0, 1, 1}, + {&__pyx_n_s_qy, __pyx_k_qy, sizeof(__pyx_k_qy), 0, 0, 1, 1}, + {&__pyx_n_s_range, __pyx_k_range, sizeof(__pyx_k_range), 0, 0, 1, 1}, + {&__pyx_n_s_t, __pyx_k_t, sizeof(__pyx_k_t), 0, 0, 1, 1}, + {&__pyx_n_s_test, __pyx_k_test, sizeof(__pyx_k_test), 0, 0, 1, 1}, + {&__pyx_n_s_tol, __pyx_k_tol, sizeof(__pyx_k_tol), 0, 0, 1, 1}, + {&__pyx_n_s_x, __pyx_k_x, sizeof(__pyx_k_x), 0, 0, 1, 1}, + {&__pyx_n_s_x1, __pyx_k_x1, sizeof(__pyx_k_x1), 0, 0, 1, 1}, + {&__pyx_n_s_x12, __pyx_k_x12, sizeof(__pyx_k_x12), 0, 0, 1, 1}, + {&__pyx_n_s_x123, __pyx_k_x123, sizeof(__pyx_k_x123), 0, 0, 1, 1}, + {&__pyx_n_s_x1234, __pyx_k_x1234, sizeof(__pyx_k_x1234), 0, 0, 1, 1}, + {&__pyx_n_s_x2, __pyx_k_x2, sizeof(__pyx_k_x2), 0, 0, 1, 1}, + {&__pyx_n_s_x23, __pyx_k_x23, sizeof(__pyx_k_x23), 0, 0, 1, 1}, + {&__pyx_n_s_x234, __pyx_k_x234, sizeof(__pyx_k_x234), 0, 0, 1, 1}, + {&__pyx_n_s_x3, __pyx_k_x3, sizeof(__pyx_k_x3), 0, 0, 1, 1}, + {&__pyx_n_s_x34, __pyx_k_x34, sizeof(__pyx_k_x34), 0, 0, 1, 1}, + {&__pyx_n_s_x4, __pyx_k_x4, sizeof(__pyx_k_x4), 0, 0, 1, 1}, + {&__pyx_n_s_y, __pyx_k_y, sizeof(__pyx_k_y), 0, 0, 1, 1}, + {&__pyx_n_s_y1, __pyx_k_y1, sizeof(__pyx_k_y1), 0, 0, 1, 1}, + {&__pyx_n_s_y12, __pyx_k_y12, sizeof(__pyx_k_y12), 0, 0, 1, 1}, + {&__pyx_n_s_y123, __pyx_k_y123, sizeof(__pyx_k_y123), 0, 0, 1, 1}, + {&__pyx_n_s_y1234, __pyx_k_y1234, sizeof(__pyx_k_y1234), 0, 0, 1, 1}, + {&__pyx_n_s_y2, __pyx_k_y2, sizeof(__pyx_k_y2), 0, 0, 1, 1}, + {&__pyx_n_s_y23, __pyx_k_y23, sizeof(__pyx_k_y23), 0, 0, 1, 1}, + {&__pyx_n_s_y234, __pyx_k_y234, sizeof(__pyx_k_y234), 0, 0, 1, 1}, + {&__pyx_n_s_y3, __pyx_k_y3, sizeof(__pyx_k_y3), 0, 0, 1, 1}, + {&__pyx_n_s_y34, __pyx_k_y34, sizeof(__pyx_k_y34), 0, 0, 1, 1}, + {&__pyx_n_s_y4, __pyx_k_y4, sizeof(__pyx_k_y4), 0, 0, 1, 1}, + {0, 0, 0, 0, 0, 0, 0} +}; +static int __Pyx_InitCachedBuiltins(void) { + __pyx_builtin_range = __Pyx_GetBuiltinName(__pyx_n_s_range); if (!__pyx_builtin_range) __PYX_ERR(0, 104, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +static int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations + __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants", 0); + + /* "src/svg_parser/svg_parser.pyx":20 + * NSVGimage* nsvgParse(char* input, const char* units, float dpi); + * + * def distPtSeg(float x, float y, float px, float py, float qx, float qy): # <<<<<<<<<<<<<< + * cdef float pqx, pqy, dx, dy, d, t + * pqx = qx-px + */ + __pyx_tuple_ = PyTuple_Pack(12, __pyx_n_s_x, __pyx_n_s_y, __pyx_n_s_px, __pyx_n_s_py, __pyx_n_s_qx, __pyx_n_s_qy, __pyx_n_s_pqx, __pyx_n_s_pqy, __pyx_n_s_dx, __pyx_n_s_dy, __pyx_n_s_d, __pyx_n_s_t); if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple_); + __Pyx_GIVEREF(__pyx_tuple_); + __pyx_codeobj__2 = (PyObject*)__Pyx_PyCode_New(6, 0, 12, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple_, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_simon_Dev_fluxclient_dev, __pyx_n_s_distPtSeg, 20, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__2)) __PYX_ERR(0, 20, __pyx_L1_error) + + /* "src/svg_parser/svg_parser.pyx":38 + * return dx*dx + dy*dy + * + * def cubicBez(float x1, float y1, float x2, float y2,float x3, float y3, float x4, float y4,float tol, int level): # <<<<<<<<<<<<<< + * cdef float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234 + * cdef float d + */ + __pyx_tuple__3 = PyTuple_Pack(26, __pyx_n_s_x1, __pyx_n_s_y1, __pyx_n_s_x2, __pyx_n_s_y2, __pyx_n_s_x3, __pyx_n_s_y3, __pyx_n_s_x4, __pyx_n_s_y4, __pyx_n_s_tol, __pyx_n_s_level, __pyx_n_s_x12, __pyx_n_s_y12, __pyx_n_s_x23, __pyx_n_s_y23, __pyx_n_s_x34, __pyx_n_s_y34, __pyx_n_s_x123, __pyx_n_s_y123, __pyx_n_s_x234, __pyx_n_s_y234, __pyx_n_s_x1234, __pyx_n_s_y1234, __pyx_n_s_d, __pyx_n_s_point_lst, __pyx_n_s_a, __pyx_n_s_b); if (unlikely(!__pyx_tuple__3)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_GOTREF(__pyx_tuple__3); + __Pyx_GIVEREF(__pyx_tuple__3); + __pyx_codeobj__4 = (PyObject*)__Pyx_PyCode_New(10, 0, 26, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__3, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_simon_Dev_fluxclient_dev, __pyx_n_s_cubicBez, 38, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__4)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_RefNannyFinishContext(); + return 0; + __pyx_L1_error:; + __Pyx_RefNannyFinishContext(); + return -1; +} + +static int __Pyx_InitGlobals(void) { + if (__Pyx_InitStrings(__pyx_string_tab) < 0) __PYX_ERR(0, 1, __pyx_L1_error); + __pyx_int_0 = PyInt_FromLong(0); if (unlikely(!__pyx_int_0)) __PYX_ERR(0, 1, __pyx_L1_error) + return 0; + __pyx_L1_error:; + return -1; +} + +#if PY_MAJOR_VERSION < 3 +PyMODINIT_FUNC init_parser(void); /*proto*/ +PyMODINIT_FUNC init_parser(void) +#else +PyMODINIT_FUNC PyInit__parser(void); /*proto*/ +PyMODINIT_FUNC PyInit__parser(void) +#endif +{ + PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannyDeclarations + #if CYTHON_REFNANNY + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); + if (!__Pyx_RefNanny) { + PyErr_Clear(); + __Pyx_RefNanny = __Pyx_RefNannyImportAPI("Cython.Runtime.refnanny"); + if (!__Pyx_RefNanny) + Py_FatalError("failed to import 'refnanny' module"); + } + #endif + __Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit__parser(void)", 0); + if (__Pyx_check_binary_version() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_empty_unicode = PyUnicode_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_unicode)) __PYX_ERR(0, 1, __pyx_L1_error) + #ifdef __Pyx_CyFunction_USED + if (__pyx_CyFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_FusedFunction_USED + if (__pyx_FusedFunction_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Coroutine_USED + if (__pyx_Coroutine_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_Generator_USED + if (__pyx_Generator_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + #ifdef __Pyx_StopAsyncIteration_USED + if (__pyx_StopAsyncIteration_init() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + /*--- Library function declarations ---*/ + /*--- Threads initialization code ---*/ + #if defined(__PYX_FORCE_INIT_THREADS) && __PYX_FORCE_INIT_THREADS + #ifdef WITH_THREAD /* Python build with threading support? */ + PyEval_InitThreads(); + #endif + #endif + /*--- Module creation code ---*/ + #if PY_MAJOR_VERSION < 3 + __pyx_m = Py_InitModule4("_parser", __pyx_methods, 0, 0, PYTHON_API_VERSION); Py_XINCREF(__pyx_m); + #else + __pyx_m = PyModule_Create(&__pyx_moduledef); + #endif + if (unlikely(!__pyx_m)) __PYX_ERR(0, 1, __pyx_L1_error) + __pyx_d = PyModule_GetDict(__pyx_m); if (unlikely(!__pyx_d)) __PYX_ERR(0, 1, __pyx_L1_error) + Py_INCREF(__pyx_d); + __pyx_b = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME); if (unlikely(!__pyx_b)) __PYX_ERR(0, 1, __pyx_L1_error) + #if CYTHON_COMPILING_IN_PYPY + Py_INCREF(__pyx_b); + #endif + if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) __PYX_ERR(0, 1, __pyx_L1_error); + /*--- Initialize various global constants etc. ---*/ + if (__Pyx_InitGlobals() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #if PY_MAJOR_VERSION < 3 && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if (__Pyx_init_sys_getdefaultencoding_params() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + if (__pyx_module_is_main_fluxclient__parser___parser) { + if (PyObject_SetAttrString(__pyx_m, "__name__", __pyx_n_s_main) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + } + #if PY_MAJOR_VERSION >= 3 + { + PyObject *modules = PyImport_GetModuleDict(); if (unlikely(!modules)) __PYX_ERR(0, 1, __pyx_L1_error) + if (!PyDict_GetItemString(modules, "fluxclient.parser._parser")) { + if (unlikely(PyDict_SetItemString(modules, "fluxclient.parser._parser", __pyx_m) < 0)) __PYX_ERR(0, 1, __pyx_L1_error) + } + } + #endif + /*--- Builtin init code ---*/ + if (__Pyx_InitCachedBuiltins() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Constants init code ---*/ + if (__Pyx_InitCachedConstants() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + /*--- Global init code ---*/ + /*--- Variable export code ---*/ + /*--- Function export code ---*/ + /*--- Type init code ---*/ + /*--- Type import code ---*/ + /*--- Variable import code ---*/ + /*--- Function import code ---*/ + /*--- Execution code ---*/ + #if defined(__Pyx_Generator_USED) || defined(__Pyx_Coroutine_USED) + if (__Pyx_patch_abc() < 0) __PYX_ERR(0, 1, __pyx_L1_error) + #endif + + /* "src/svg_parser/svg_parser.pyx":20 + * NSVGimage* nsvgParse(char* input, const char* units, float dpi); + * + * def distPtSeg(float x, float y, float px, float py, float qx, float qy): # <<<<<<<<<<<<<< + * cdef float pqx, pqy, dx, dy, d, t + * pqx = qx-px + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_10fluxclient_6parser_7_parser_1distPtSeg, NULL, __pyx_n_s_fluxclient_parser__parser); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 20, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_distPtSeg, __pyx_t_1) < 0) __PYX_ERR(0, 20, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "src/svg_parser/svg_parser.pyx":38 + * return dx*dx + dy*dy + * + * def cubicBez(float x1, float y1, float x2, float y2,float x3, float y3, float x4, float y4,float tol, int level): # <<<<<<<<<<<<<< + * cdef float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234 + * cdef float d + */ + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_10fluxclient_6parser_7_parser_3cubicBez, NULL, __pyx_n_s_fluxclient_parser__parser); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_cubicBez, __pyx_t_1) < 0) __PYX_ERR(0, 38, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /* "src/svg_parser/svg_parser.pyx":1 + * import cython # <<<<<<<<<<<<<< + * cdef extern from "nanosvg.h": + * cdef struct NSVGpath: + */ + __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_GOTREF(__pyx_t_1); + if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error) + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + + /*--- Wrapped vars code ---*/ + + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + if (__pyx_m) { + if (__pyx_d) { + __Pyx_AddTraceback("init fluxclient.parser._parser", __pyx_clineno, __pyx_lineno, __pyx_filename); + } + Py_DECREF(__pyx_m); __pyx_m = 0; + } else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_ImportError, "init fluxclient.parser._parser"); + } + __pyx_L0:; + __Pyx_RefNannyFinishContext(); + #if PY_MAJOR_VERSION < 3 + return; + #else + return __pyx_m; + #endif +} + +/* --- Runtime support code --- */ +/* Refnanny */ +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule((char *)modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif + +/* GetBuiltinName */ +static PyObject *__Pyx_GetBuiltinName(PyObject *name) { + PyObject* result = __Pyx_PyObject_GetAttrStr(__pyx_b, name); + if (unlikely(!result)) { + PyErr_Format(PyExc_NameError, +#if PY_MAJOR_VERSION >= 3 + "name '%U' is not defined", name); +#else + "name '%.200s' is not defined", PyString_AS_STRING(name)); +#endif + } + return result; +} + +/* RaiseArgTupleInvalid */ +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%.200s() takes %.8s %" CYTHON_FORMAT_SSIZE_T "d positional argument%.1s (%" CYTHON_FORMAT_SSIZE_T "d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + +/* RaiseDoubleKeywords */ +static void __Pyx_RaiseDoubleKeywordsError( + const char* func_name, + PyObject* kw_name) +{ + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION >= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AsString(kw_name)); + #endif +} + +/* ParseKeywords */ +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + while (PyDict_Next(kwds, &pos, &key, &value)) { + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; + continue; + } + name = first_kw_arg; + #if PY_MAJOR_VERSION < 3 + if (likely(PyString_CheckExact(key)) || likely(PyString_Check(key))) { + while (*name) { + if ((CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**name) == PyString_GET_SIZE(key)) + && _PyString_Eq(**name, key)) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + if ((**argname == key) || ( + (CYTHON_COMPILING_IN_PYPY || PyString_GET_SIZE(**argname) == PyString_GET_SIZE(key)) + && _PyString_Eq(**argname, key))) { + goto arg_passed_twice; + } + argname++; + } + } + } else + #endif + if (likely(PyUnicode_Check(key))) { + while (*name) { + int cmp = (**name == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (PyUnicode_GET_SIZE(**name) != PyUnicode_GET_SIZE(key)) ? 1 : + #endif + PyUnicode_Compare(**name, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) { + values[name-argnames] = value; + break; + } + name++; + } + if (*name) continue; + else { + PyObject*** argname = argnames; + while (argname != first_kw_arg) { + int cmp = (**argname == key) ? 0 : + #if !CYTHON_COMPILING_IN_PYPY && PY_MAJOR_VERSION >= 3 + (PyUnicode_GET_SIZE(**argname) != PyUnicode_GET_SIZE(key)) ? 1 : + #endif + PyUnicode_Compare(**argname, key); + if (cmp < 0 && unlikely(PyErr_Occurred())) goto bad; + if (cmp == 0) goto arg_passed_twice; + argname++; + } + } + } else + goto invalid_keyword_type; + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, key); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%.200s() got an unexpected keyword argument '%.200s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + return -1; +} + +/* GetModuleGlobalName */ +static CYTHON_INLINE PyObject *__Pyx_GetModuleGlobalName(PyObject *name) { + PyObject *result; +#if !CYTHON_AVOID_BORROWED_REFS + result = PyDict_GetItem(__pyx_d, name); + if (likely(result)) { + Py_INCREF(result); + } else { +#else + result = PyObject_GetItem(__pyx_d, name); + if (!result) { + PyErr_Clear(); +#endif + result = __Pyx_GetBuiltinName(name); + } + return result; +} + +/* PyFunctionFastCall */ + #if CYTHON_FAST_PYCALL +#include "frameobject.h" +static PyObject* __Pyx_PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t na, + PyObject *globals) { + PyFrameObject *f; + PyThreadState *tstate = PyThreadState_GET(); + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + fastlocals = f->f_localsplus; + for (i = 0; i < na; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return result; +} +#if 1 || PY_VERSION_HEX < 0x030600B1 +static PyObject *__Pyx_PyFunction_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) { + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *closure; +#if PY_MAJOR_VERSION >= 3 + PyObject *kwdefs; +#endif + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd; + Py_ssize_t nk; + PyObject *result; + assert(kwargs == NULL || PyDict_Check(kwargs)); + nk = kwargs ? PyDict_Size(kwargs) : 0; + if (Py_EnterRecursiveCall((char*)" while calling a Python object")) { + return NULL; + } + if ( +#if PY_MAJOR_VERSION >= 3 + co->co_kwonlyargcount == 0 && +#endif + likely(kwargs == NULL || nk == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + if (argdefs == NULL && co->co_argcount == nargs) { + result = __Pyx_PyFunction_FastCallNoKw(co, args, nargs, globals); + goto done; + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + args = &PyTuple_GET_ITEM(argdefs, 0); + result =__Pyx_PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), globals); + goto done; + } + } + if (kwargs != NULL) { + Py_ssize_t pos, i; + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + result = NULL; + goto done; + } + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + closure = PyFunction_GET_CLOSURE(func); +#if PY_MAJOR_VERSION >= 3 + kwdefs = PyFunction_GET_KW_DEFAULTS(func); +#endif + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } +#if PY_MAJOR_VERSION >= 3 + result = PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, + args, nargs, + k, (int)nk, + d, (int)nd, kwdefs, closure); +#else + result = PyEval_EvalCodeEx(co, globals, (PyObject *)NULL, + args, nargs, + k, (int)nk, + d, (int)nd, closure); +#endif + Py_XDECREF(kwtuple); +done: + Py_LeaveRecursiveCall(); + return result; +} +#endif // CPython < 3.6 +#endif // CYTHON_FAST_PYCALL + +/* PyCFunctionFastCall */ + #if CYTHON_FAST_PYCCALL +static CYTHON_INLINE PyObject * __Pyx_PyCFunction_FastCall(PyObject *func_obj, PyObject **args, Py_ssize_t nargs) { + PyCFunctionObject *func = (PyCFunctionObject*)func_obj; + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + assert(PyCFunction_Check(func)); + assert(METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST))); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + /* _PyCFunction_FastCallDict() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + return (*((__Pyx_PyCFunctionFast)meth)) (self, args, nargs, NULL); +} +#endif // CYTHON_FAST_PYCCALL + +/* PyObjectCall */ + #if CYTHON_COMPILING_IN_CPYTHON +static CYTHON_INLINE PyObject* __Pyx_PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { + PyObject *result; + ternaryfunc call = func->ob_type->tp_call; + if (unlikely(!call)) + return PyObject_Call(func, arg, kw); + if (unlikely(Py_EnterRecursiveCall((char*)" while calling a Python object"))) + return NULL; + result = (*call)(func, arg, kw); + Py_LeaveRecursiveCall(); + if (unlikely(!result) && unlikely(!PyErr_Occurred())) { + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + } + return result; +} +#endif + +/* CodeObjectCache */ + static int __pyx_bisect_code_objects(__Pyx_CodeObjectCacheEntry* entries, int count, int code_line) { + int start = 0, mid = 0, end = count - 1; + if (end >= 0 && code_line > entries[end].code_line) { + return count; + } + while (start < end) { + mid = start + (end - start) / 2; + if (code_line < entries[mid].code_line) { + end = mid; + } else if (code_line > entries[mid].code_line) { + start = mid + 1; + } else { + return mid; + } + } + if (code_line <= entries[mid].code_line) { + return mid; + } else { + return mid + 1; + } +} +static PyCodeObject *__pyx_find_code_object(int code_line) { + PyCodeObject* code_object; + int pos; + if (unlikely(!code_line) || unlikely(!__pyx_code_cache.entries)) { + return NULL; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if (unlikely(pos >= __pyx_code_cache.count) || unlikely(__pyx_code_cache.entries[pos].code_line != code_line)) { + return NULL; + } + code_object = __pyx_code_cache.entries[pos].code_object; + Py_INCREF(code_object); + return code_object; +} +static void __pyx_insert_code_object(int code_line, PyCodeObject* code_object) { + int pos, i; + __Pyx_CodeObjectCacheEntry* entries = __pyx_code_cache.entries; + if (unlikely(!code_line)) { + return; + } + if (unlikely(!entries)) { + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Malloc(64*sizeof(__Pyx_CodeObjectCacheEntry)); + if (likely(entries)) { + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = 64; + __pyx_code_cache.count = 1; + entries[0].code_line = code_line; + entries[0].code_object = code_object; + Py_INCREF(code_object); + } + return; + } + pos = __pyx_bisect_code_objects(__pyx_code_cache.entries, __pyx_code_cache.count, code_line); + if ((pos < __pyx_code_cache.count) && unlikely(__pyx_code_cache.entries[pos].code_line == code_line)) { + PyCodeObject* tmp = entries[pos].code_object; + entries[pos].code_object = code_object; + Py_DECREF(tmp); + return; + } + if (__pyx_code_cache.count == __pyx_code_cache.max_count) { + int new_max = __pyx_code_cache.max_count + 64; + entries = (__Pyx_CodeObjectCacheEntry*)PyMem_Realloc( + __pyx_code_cache.entries, (size_t)new_max*sizeof(__Pyx_CodeObjectCacheEntry)); + if (unlikely(!entries)) { + return; + } + __pyx_code_cache.entries = entries; + __pyx_code_cache.max_count = new_max; + } + for (i=__pyx_code_cache.count; i>pos; i--) { + entries[i] = entries[i-1]; + } + entries[pos].code_line = code_line; + entries[pos].code_object = code_object; + __pyx_code_cache.count++; + Py_INCREF(code_object); +} + +/* AddTraceback */ + #include "compile.h" +#include "frameobject.h" +#include "traceback.h" +static PyCodeObject* __Pyx_CreateCodeObjectForTraceback( + const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyObject *py_srcfile = 0; + PyObject *py_funcname = 0; + #if PY_MAJOR_VERSION < 3 + py_srcfile = PyString_FromString(filename); + #else + py_srcfile = PyUnicode_FromString(filename); + #endif + if (!py_srcfile) goto bad; + if (c_line) { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + #else + py_funcname = PyUnicode_FromFormat( "%s (%s:%d)", funcname, __pyx_cfilenm, c_line); + #endif + } + else { + #if PY_MAJOR_VERSION < 3 + py_funcname = PyString_FromString(funcname); + #else + py_funcname = PyUnicode_FromString(funcname); + #endif + } + if (!py_funcname) goto bad; + py_code = __Pyx_PyCode_New( + 0, + 0, + 0, + 0, + 0, + __pyx_empty_bytes, /*PyObject *code,*/ + __pyx_empty_tuple, /*PyObject *consts,*/ + __pyx_empty_tuple, /*PyObject *names,*/ + __pyx_empty_tuple, /*PyObject *varnames,*/ + __pyx_empty_tuple, /*PyObject *freevars,*/ + __pyx_empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + py_line, + __pyx_empty_bytes /*PyObject *lnotab*/ + ); + Py_DECREF(py_srcfile); + Py_DECREF(py_funcname); + return py_code; +bad: + Py_XDECREF(py_srcfile); + Py_XDECREF(py_funcname); + return NULL; +} +static void __Pyx_AddTraceback(const char *funcname, int c_line, + int py_line, const char *filename) { + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + py_code = __pyx_find_code_object(c_line ? c_line : py_line); + if (!py_code) { + py_code = __Pyx_CreateCodeObjectForTraceback( + funcname, c_line, py_line, filename); + if (!py_code) goto bad; + __pyx_insert_code_object(c_line ? c_line : py_line, py_code); + } + py_frame = PyFrame_New( + PyThreadState_GET(), /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + __pyx_d, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + __Pyx_PyFrame_SetLineNumber(py_frame, py_line); + PyTraceBack_Here(py_frame); +bad: + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} + +/* CIntFromPyVerify */ + #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 0) +#define __PYX_VERIFY_RETURN_INT_EXC(target_type, func_type, func_value)\ + __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, 1) +#define __PYX__VERIFY_RETURN_INT(target_type, func_type, func_value, exc)\ + {\ + func_type value = func_value;\ + if (sizeof(target_type) < sizeof(func_type)) {\ + if (unlikely(value != (func_type) (target_type) value)) {\ + func_type zero = 0;\ + if (exc && unlikely(value == (func_type)-1 && PyErr_Occurred()))\ + return (target_type) -1;\ + if (is_unsigned && unlikely(value < zero))\ + goto raise_neg_overflow;\ + else\ + goto raise_overflow;\ + }\ + }\ + return (target_type) value;\ + } + +/* CIntToPy */ + static CYTHON_INLINE PyObject* __Pyx_PyInt_From_long(long value) { + const long neg_one = (long) -1, const_zero = (long) 0; + const int is_unsigned = neg_one > const_zero; + if (is_unsigned) { + if (sizeof(long) < sizeof(long)) { + return PyInt_FromLong((long) value); + } else if (sizeof(long) <= sizeof(unsigned long)) { + return PyLong_FromUnsignedLong((unsigned long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value); +#endif + } + } else { + if (sizeof(long) <= sizeof(long)) { + return PyInt_FromLong((long) value); +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + return PyLong_FromLongLong((PY_LONG_LONG) value); +#endif + } + } + { + int one = 1; int little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&value; + return _PyLong_FromByteArray(bytes, sizeof(long), + little, !is_unsigned); + } +} + +/* CIntFromPy */ + static CYTHON_INLINE int __Pyx_PyInt_As_int(PyObject *x) { + const int neg_one = (int) -1, const_zero = (int) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(int) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(int, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (int) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case 1: __PYX_VERIFY_RETURN_INT(int, digit, digits[0]) + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 2 * PyLong_SHIFT) { + return (int) (((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 3 * PyLong_SHIFT) { + return (int) (((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) >= 4 * PyLong_SHIFT) { + return (int) (((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (int) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(int) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (int) 0; + case -1: __PYX_VERIFY_RETURN_INT(int, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(int, digit, +digits[0]) + case -2: + if (8 * sizeof(int) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(int) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + return (int) ((((((int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(int) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(int) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + return (int) ((((((((int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(int) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) (((int)-1)*(((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(int) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(int, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(int) - 1 > 4 * PyLong_SHIFT) { + return (int) ((((((((((int)digits[3]) << PyLong_SHIFT) | (int)digits[2]) << PyLong_SHIFT) | (int)digits[1]) << PyLong_SHIFT) | (int)digits[0]))); + } + } + break; + } +#endif + if (sizeof(int) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(int, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(int) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(int, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + int val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (int) -1; + } + } else { + int val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (int) -1; + val = __Pyx_PyInt_As_int(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to int"); + return (int) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to int"); + return (int) -1; +} + +/* CIntFromPy */ + static CYTHON_INLINE long __Pyx_PyInt_As_long(PyObject *x) { + const long neg_one = (long) -1, const_zero = (long) 0; + const int is_unsigned = neg_one > const_zero; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_Check(x))) { + if (sizeof(long) < sizeof(long)) { + __PYX_VERIFY_RETURN_INT(long, long, PyInt_AS_LONG(x)) + } else { + long val = PyInt_AS_LONG(x); + if (is_unsigned && unlikely(val < 0)) { + goto raise_neg_overflow; + } + return (long) val; + } + } else +#endif + if (likely(PyLong_Check(x))) { + if (is_unsigned) { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case 1: __PYX_VERIFY_RETURN_INT(long, digit, digits[0]) + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 2 * PyLong_SHIFT) { + return (long) (((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 3 * PyLong_SHIFT) { + return (long) (((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) >= 4 * PyLong_SHIFT) { + return (long) (((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0])); + } + } + break; + } +#endif +#if CYTHON_COMPILING_IN_CPYTHON + if (unlikely(Py_SIZE(x) < 0)) { + goto raise_neg_overflow; + } +#else + { + int result = PyObject_RichCompareBool(x, Py_False, Py_LT); + if (unlikely(result < 0)) + return (long) -1; + if (unlikely(result == 1)) + goto raise_neg_overflow; + } +#endif + if (sizeof(long) <= sizeof(unsigned long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned long, PyLong_AsUnsignedLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, unsigned PY_LONG_LONG, PyLong_AsUnsignedLongLong(x)) +#endif + } + } else { +#if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)x)->ob_digit; + switch (Py_SIZE(x)) { + case 0: return (long) 0; + case -1: __PYX_VERIFY_RETURN_INT(long, sdigit, (sdigit) (-(sdigit)digits[0])) + case 1: __PYX_VERIFY_RETURN_INT(long, digit, +digits[0]) + case -2: + if (8 * sizeof(long) - 1 > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 2: + if (8 * sizeof(long) > 1 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 2 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + return (long) ((((((long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -3: + if (8 * sizeof(long) - 1 > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 3: + if (8 * sizeof(long) > 2 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 3 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + return (long) ((((((((long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case -4: + if (8 * sizeof(long) - 1 > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, long, -(long) (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) (((long)-1)*(((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + case 4: + if (8 * sizeof(long) > 3 * PyLong_SHIFT) { + if (8 * sizeof(unsigned long) > 4 * PyLong_SHIFT) { + __PYX_VERIFY_RETURN_INT(long, unsigned long, (((((((((unsigned long)digits[3]) << PyLong_SHIFT) | (unsigned long)digits[2]) << PyLong_SHIFT) | (unsigned long)digits[1]) << PyLong_SHIFT) | (unsigned long)digits[0]))) + } else if (8 * sizeof(long) - 1 > 4 * PyLong_SHIFT) { + return (long) ((((((((((long)digits[3]) << PyLong_SHIFT) | (long)digits[2]) << PyLong_SHIFT) | (long)digits[1]) << PyLong_SHIFT) | (long)digits[0]))); + } + } + break; + } +#endif + if (sizeof(long) <= sizeof(long)) { + __PYX_VERIFY_RETURN_INT_EXC(long, long, PyLong_AsLong(x)) +#ifdef HAVE_LONG_LONG + } else if (sizeof(long) <= sizeof(PY_LONG_LONG)) { + __PYX_VERIFY_RETURN_INT_EXC(long, PY_LONG_LONG, PyLong_AsLongLong(x)) +#endif + } + } + { +#if CYTHON_COMPILING_IN_PYPY && !defined(_PyLong_AsByteArray) + PyErr_SetString(PyExc_RuntimeError, + "_PyLong_AsByteArray() not available in PyPy, cannot convert large numbers"); +#else + long val; + PyObject *v = __Pyx_PyNumber_IntOrLong(x); + #if PY_MAJOR_VERSION < 3 + if (likely(v) && !PyLong_Check(v)) { + PyObject *tmp = v; + v = PyNumber_Long(tmp); + Py_DECREF(tmp); + } + #endif + if (likely(v)) { + int one = 1; int is_little = (int)*(unsigned char *)&one; + unsigned char *bytes = (unsigned char *)&val; + int ret = _PyLong_AsByteArray((PyLongObject *)v, + bytes, sizeof(val), + is_little, !is_unsigned); + Py_DECREF(v); + if (likely(!ret)) + return val; + } +#endif + return (long) -1; + } + } else { + long val; + PyObject *tmp = __Pyx_PyNumber_IntOrLong(x); + if (!tmp) return (long) -1; + val = __Pyx_PyInt_As_long(tmp); + Py_DECREF(tmp); + return val; + } +raise_overflow: + PyErr_SetString(PyExc_OverflowError, + "value too large to convert to long"); + return (long) -1; +raise_neg_overflow: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to long"); + return (long) -1; +} + +/* CheckBinaryVersion */ + static int __Pyx_check_binary_version(void) { + char ctversion[4], rtversion[4]; + PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION); + PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion()); + if (ctversion[0] != rtversion[0] || ctversion[2] != rtversion[2]) { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compiletime version %s of module '%.100s' " + "does not match runtime version %s", + ctversion, __Pyx_MODULE_NAME, rtversion); + return PyErr_WarnEx(NULL, message, 1); + } + return 0; +} + +/* InitStrings */ + static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) { + while (t->p) { + #if PY_MAJOR_VERSION < 3 + if (t->is_unicode) { + *t->p = PyUnicode_DecodeUTF8(t->s, t->n - 1, NULL); + } else if (t->intern) { + *t->p = PyString_InternFromString(t->s); + } else { + *t->p = PyString_FromStringAndSize(t->s, t->n - 1); + } + #else + if (t->is_unicode | t->is_str) { + if (t->intern) { + *t->p = PyUnicode_InternFromString(t->s); + } else if (t->encoding) { + *t->p = PyUnicode_Decode(t->s, t->n - 1, t->encoding, NULL); + } else { + *t->p = PyUnicode_FromStringAndSize(t->s, t->n - 1); + } + } else { + *t->p = PyBytes_FromStringAndSize(t->s, t->n - 1); + } + #endif + if (!*t->p) + return -1; + ++t; + } + return 0; +} + +static CYTHON_INLINE PyObject* __Pyx_PyUnicode_FromString(const char* c_str) { + return __Pyx_PyUnicode_FromStringAndSize(c_str, (Py_ssize_t)strlen(c_str)); +} +static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject* o) { + Py_ssize_t ignore; + return __Pyx_PyObject_AsStringAndSize(o, &ignore); +} +static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) { +#if CYTHON_COMPILING_IN_CPYTHON && (__PYX_DEFAULT_STRING_ENCODING_IS_ASCII || __PYX_DEFAULT_STRING_ENCODING_IS_DEFAULT) + if ( +#if PY_MAJOR_VERSION < 3 && __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + __Pyx_sys_getdefaultencoding_not_ascii && +#endif + PyUnicode_Check(o)) { +#if PY_VERSION_HEX < 0x03030000 + char* defenc_c; + PyObject* defenc = _PyUnicode_AsDefaultEncodedString(o, NULL); + if (!defenc) return NULL; + defenc_c = PyBytes_AS_STRING(defenc); +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + { + char* end = defenc_c + PyBytes_GET_SIZE(defenc); + char* c; + for (c = defenc_c; c < end; c++) { + if ((unsigned char) (*c) >= 128) { + PyUnicode_AsASCIIString(o); + return NULL; + } + } + } +#endif + *length = PyBytes_GET_SIZE(defenc); + return defenc_c; +#else + if (__Pyx_PyUnicode_READY(o) == -1) return NULL; +#if __PYX_DEFAULT_STRING_ENCODING_IS_ASCII + if (PyUnicode_IS_ASCII(o)) { + *length = PyUnicode_GET_LENGTH(o); + return PyUnicode_AsUTF8(o); + } else { + PyUnicode_AsASCIIString(o); + return NULL; + } +#else + return PyUnicode_AsUTF8AndSize(o, length); +#endif +#endif + } else +#endif +#if (!CYTHON_COMPILING_IN_PYPY) || (defined(PyByteArray_AS_STRING) && defined(PyByteArray_GET_SIZE)) + if (PyByteArray_Check(o)) { + *length = PyByteArray_GET_SIZE(o); + return PyByteArray_AS_STRING(o); + } else +#endif + { + char* result; + int r = PyBytes_AsStringAndSize(o, &result, length); + if (unlikely(r < 0)) { + return NULL; + } else { + return result; + } + } +} +static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject* x) { + int is_true = x == Py_True; + if (is_true | (x == Py_False) | (x == Py_None)) return is_true; + else return PyObject_IsTrue(x); +} +static CYTHON_INLINE PyObject* __Pyx_PyNumber_IntOrLong(PyObject* x) { +#if CYTHON_USE_TYPE_SLOTS + PyNumberMethods *m; +#endif + const char *name = NULL; + PyObject *res = NULL; +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(x) || PyLong_Check(x)) +#else + if (PyLong_Check(x)) +#endif + return __Pyx_NewRef(x); +#if CYTHON_USE_TYPE_SLOTS + m = Py_TYPE(x)->tp_as_number; + #if PY_MAJOR_VERSION < 3 + if (m && m->nb_int) { + name = "int"; + res = PyNumber_Int(x); + } + else if (m && m->nb_long) { + name = "long"; + res = PyNumber_Long(x); + } + #else + if (m && m->nb_int) { + name = "int"; + res = PyNumber_Long(x); + } + #endif +#else + res = PyNumber_Int(x); +#endif + if (res) { +#if PY_MAJOR_VERSION < 3 + if (!PyInt_Check(res) && !PyLong_Check(res)) { +#else + if (!PyLong_Check(res)) { +#endif + PyErr_Format(PyExc_TypeError, + "__%.4s__ returned non-%.4s (type %.200s)", + name, name, Py_TYPE(res)->tp_name); + Py_DECREF(res); + return NULL; + } + } + else if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "an integer is required"); + } + return res; +} +static CYTHON_INLINE Py_ssize_t __Pyx_PyIndex_AsSsize_t(PyObject* b) { + Py_ssize_t ival; + PyObject *x; +#if PY_MAJOR_VERSION < 3 + if (likely(PyInt_CheckExact(b))) { + if (sizeof(Py_ssize_t) >= sizeof(long)) + return PyInt_AS_LONG(b); + else + return PyInt_AsSsize_t(x); + } +#endif + if (likely(PyLong_CheckExact(b))) { + #if CYTHON_USE_PYLONG_INTERNALS + const digit* digits = ((PyLongObject*)b)->ob_digit; + const Py_ssize_t size = Py_SIZE(b); + if (likely(__Pyx_sst_abs(size) <= 1)) { + ival = likely(size) ? digits[0] : 0; + if (size == -1) ival = -ival; + return ival; + } else { + switch (size) { + case 2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return (Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -2: + if (8 * sizeof(Py_ssize_t) > 2 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -3: + if (8 * sizeof(Py_ssize_t) > 3 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case 4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return (Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + case -4: + if (8 * sizeof(Py_ssize_t) > 4 * PyLong_SHIFT) { + return -(Py_ssize_t) (((((((((size_t)digits[3]) << PyLong_SHIFT) | (size_t)digits[2]) << PyLong_SHIFT) | (size_t)digits[1]) << PyLong_SHIFT) | (size_t)digits[0])); + } + break; + } + } + #endif + return PyLong_AsSsize_t(b); + } + x = PyNumber_Index(b); + if (!x) return -1; + ival = PyInt_AsSsize_t(x); + Py_DECREF(x); + return ival; +} +static CYTHON_INLINE PyObject * __Pyx_PyInt_FromSize_t(size_t ival) { + return PyInt_FromSize_t(ival); +} + + +#endif /* Py_PYTHON_H */ diff --git a/src/svg_parser/svg_parser.pyx b/src/svg_parser/svg_parser.pyx new file mode 100644 index 0000000..b9b54e3 --- /dev/null +++ b/src/svg_parser/svg_parser.pyx @@ -0,0 +1,113 @@ +import cython +cdef extern from "nanosvg.h": + cdef struct NSVGpath: + char closed + float* pts + int npts + NSVGpath* next + cdef struct NSVGshape: + char id[64] + NSVGpath* paths + NSVGshape* next + + ctypedef struct NSVGimage: + float width + float height + NSVGshape* shapes + + NSVGimage* nsvgParse(char* input, const char* units, float dpi); + +def distPtSeg(float x, float y, float px, float py, float qx, float qy): + cdef float pqx, pqy, dx, dy, d, t + pqx = qx-px + pqy = qy-py + dx = x-px + dy = y-py + d = pqx*pqx + pqy*pqy + t = pqx*dx + pqy*dy + if d > 0: + t = t/d + if t < 0: + t = 0 + elif t > 1: + t = 1 + dx = px + t*pqx - x + dy = py + t*pqy - y + return dx*dx + dy*dy + +def cubicBez(float x1, float y1, float x2, float y2,float x3, float y3, float x4, float y4,float tol, int level): + cdef float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234 + cdef float d + if level > 12: + return [] + + x12 = (x1 + x2) * 0.5 + y12 = (y1 + y2) * 0.5 + x23 = (x2+x3)*0.5 + y23 = (y2+y3)*0.5 + x34 = (x3+x4)*0.5 + y34 = (y3+y4)*0.5 + x123 = (x12+x23)*0.5 + y123 = (y12+y23)*0.5 + x234 = (x23+x34)*0.5 + y234 = (y23+y34)*0.5 + x1234 = (x123+x234)*0.5 + y1234 = (y123+y234)*0.5 + d = distPtSeg(x1234, y1234, x1,y1, x4,y4) + if d > tol*tol: + point_lst = [] + a = cubicBez(x1,y1, x12,y12, x123,y123, x1234,y1234, tol, level+1) + b = cubicBez(x1234,y1234, x234,y234, x34,y34, x4,y4, tol, level+1) + point_lst.extend(a) + point_lst.extend(b) + return point_lst + else: + + return [(x4,y4)] + +cpdef get_all_points(char* svg_data): + cdef NSVGimage* g_image + cdef NSVGpath * path + cdef float* p + cdef int i + cdef float cx,cy,hw,hh + cdef float width,height + cdef float view_2,view_1,px,aspect + g_image = nsvgParse(svg_data, "px", 96.0) + + cx = g_image.width * 0.5 + cy = g_image.height * 0.5 + hw = g_image.width * 0.5 + hh = g_image.height * 0.5 + width = 1880.0 + height = 955.0 + if width/hw < height/hh: + aspect = height / width + view_2 = cx + hw * 1.2 + view_1 = cy - hw * 1.2 * aspect + + else: + aspect = width / height + view_2 = cx + hh * 1.2 * aspect + view_1 = cy - hh * 1.2 + + px = (view_2 - view_1) / width; + + cdef NSVGshape * shape = g_image.shapes + path_lst = [] + while shape != NULL: + path = shape.paths + while path != NULL: + point_lst = [] + p = path.pts + point_lst.append((p[0],p[1])) + for i in range(0,path.npts-1,3): + p = path.pts + i*2 + #point_lst.extend(cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], px * 1.5, 0)) + point_lst.extend(cubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7], px * 0.001, 0)) + #if path.closed: + #point_lst.append((path.pts[0],path.pts[1])) + path_lst.append(point_lst) + path = path.next + shape = shape.next + return path_lst diff --git a/src/toolpath/_toolpath.pyx b/src/toolpath/_toolpath.pyx index 5460114..d0f4dad 100644 --- a/src/toolpath/_toolpath.pyx +++ b/src/toolpath/_toolpath.pyx @@ -12,6 +12,13 @@ from _toolpathlib cimport (ToolpathProcessor as _ToolpathProcessor, FCodeV1FileWriter as _FCodeV1FileWriter, PythonToolpathProcessor) +from libc.math cimport floor, ceil, round + +import numpy as np +cimport numpy as np + +DTYPE = np.uint8 +ctypedef np.uint8_t NP_CHAR cdef class ToolpathProcessor: cdef _ToolpathProcessor *_proc @@ -190,3 +197,60 @@ cdef class GCodeParser: cpdef parse_from_file(self, filename): self._parser.parse_from_file(filename.encode()) + +cdef class DitheringProcessor: + cdef dither_c(self, np.ndarray[NP_CHAR, ndim=3] data): + cdef int xmax = data.shape[0], ymax = data.shape[1], x, y + cdef float old_pixel, lumin_error + cdef NP_CHAR new_pix + # Default luminance formula + cdef float MB = 0.0722, MG = 0.7152, MR = 0.216 + # Define float as C constant 7/16, 3/16, 5/16, 1/16 + cdef float q1 = 0.4375, q2 = 0.1875, q3 = 0.3125, q4 = 0.0625 + cdef np.ndarray[np.float32_t, ndim=2] temp_data = np.zeros([xmax, ymax], dtype=np.float32) + # Convert data into float 3d array, the data type must be able to store negative numbers + for y in range(1, ymax): + for x in range(1, xmax): + temp_data[x, y] = data[x, y, 0] * MB + data[x, y, 1] * MG + data[x, y, 2] * MR + + # Floyd-Steinberg dithering (https://en.wikipedia.org/wiki/Floyd%E2%80%93Steinberg_dithering) + for y in range(1, ymax): + for x in range(1, xmax): + old_pixel = temp_data[x, y] + + if old_pixel > 128: + new_pix = 255 + else: + new_pix = 0 + + temp_data[x, y] = new_pix + + lumin_error = old_pixel - new_pix + + if x < xmax - 1: + temp_data[x+1, y] += lumin_error * q1 + + if x > 1 and y < ymax - 1: + temp_data[x-1, y+1] += lumin_error * q2 + + if y < ymax - 1: + temp_data[x, y+1] += lumin_error * q3 + + if x < xmax - 1 and y < ymax - 1: + temp_data[x+1, y+1] += lumin_error * q4 + + for y in range(1, ymax): + for x in range(1, xmax): + if temp_data[x, y] > 128: + data[x, y, 0] = 255 + data[x, y, 1] = 255 + data[x, y, 2] = 255 + else: + data[x, y, 0] = 0 + data[x, y, 1] = 0 + data[x, y, 2] = 0 + + return data + + def dither(self, np.ndarray[NP_CHAR, ndim=3] data): + return self.dither_c(data) \ No newline at end of file