From 9188d71e5ed3c1e0ad2b5c5a6e85e280d69d550f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Ecorchard?= Date: Fri, 2 Oct 2015 21:55:37 +0200 Subject: [PATCH 1/4] Add an example with a polyline from a numpy array --- CadQuery/Examples/Ex028_Numpy.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 CadQuery/Examples/Ex028_Numpy.py diff --git a/CadQuery/Examples/Ex028_Numpy.py b/CadQuery/Examples/Ex028_Numpy.py new file mode 100644 index 0000000..0aa12a0 --- /dev/null +++ b/CadQuery/Examples/Ex028_Numpy.py @@ -0,0 +1,26 @@ +# This example is meant to be used from within the CadQuery module of FreeCAD. +import numpy as np +import cadquery +from Helpers import show + +# Square side and offset in x and y. +side = 10 +offset = 5 + +# Define the locations that the polyline will be drawn to/thru. +# The polyline is defined as numpy.array so that operations like translation +# of all points are simplified. +pts = np.array([ + (0, 0), + (side, 0), + (side, side), + (0, side), + (0, 0), +]) + [offset, offset] + +result = cadquery.Workplane('XY') \ + .polyline(pts).extrude(2) \ + .faces('+Z').workplane().circle(side / 2).extrude(1) + +# Render the solid +show(result) From 317a8e19de8fb56edbebb54e6ac97756dacc048c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Ecorchard?= Date: Fri, 2 Oct 2015 21:57:13 +0200 Subject: [PATCH 2/4] Remove flipLid parameter from Parametric Enclosure The parameter didn't work anyway --- CadQuery/Examples/Ex023_Parametric_Enclosure.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CadQuery/Examples/Ex023_Parametric_Enclosure.py b/CadQuery/Examples/Ex023_Parametric_Enclosure.py index 5de638d..82ebee4 100644 --- a/CadQuery/Examples/Ex023_Parametric_Enclosure.py +++ b/CadQuery/Examples/Ex023_Parametric_Enclosure.py @@ -19,7 +19,6 @@ p_boreDiameter = 8.0 # Diameter of the counterbore hole, if any p_boreDepth = 1.0 # Depth of the counterbore hole, if p_countersinkDiameter = 0.0 # Outer diameter of countersink. Should roughly match the outer diameter of the screw head p_countersinkAngle = 90.0 # Countersink angle (complete angle between opposite sides, not from center to one side) -p_flipLid = True # Whether to place the lid with the top facing down or not. p_lipHeight = 1.0 # Height of lip on the underside of the lid. Sits inside the box body for a snug fit. # Outer shell @@ -73,10 +72,6 @@ elif p_countersinkDiameter > 0 and p_countersinkAngle > 0: else: topOfLid= topOfLidCenters.hole(p_screwpostID, 2.0 * p_thickness) -# Flip lid upside down if desired -if p_flipLid: - topOfLid.rotateAboutCenter((1, 0, 0), 180) - # Return the combined result result = topOfLid.combineSolids(bottom) From 49823b9d454c24d413c2b88acf0ec37373ca473a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Ecorchard?= Date: Mon, 12 Oct 2015 21:55:57 +0200 Subject: [PATCH 3/4] Support unicode in scripts --- CadQuery/Gui/Command.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CadQuery/Gui/Command.py b/CadQuery/Gui/Command.py index 906d33d..d7d156d 100644 --- a/CadQuery/Gui/Command.py +++ b/CadQuery/Gui/Command.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """Adds all of the commands that are used for the menus of the CadQuery module""" # (c) 2014-2015 Jeremy Wright LGPL v3 @@ -160,7 +161,7 @@ class CadQueryExecuteScript: #Save our code to a tempfile and render it tempFile = tempfile.NamedTemporaryFile(delete=False) - tempFile.write(cqCodePane.toPlainText()) + tempFile.write(cqCodePane.toPlainText().encode('utf-8')) tempFile.close() FreeCAD.Console.PrintMessage("\r\n") From 6fc456bca6cc06406a4d43b8e471bf9e5cc7658b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Ecorchard?= Date: Mon, 12 Oct 2015 21:57:02 +0200 Subject: [PATCH 4/4] Add Braille example --- CadQuery/Examples/Ex029_Braille.py | 183 +++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 CadQuery/Examples/Ex029_Braille.py diff --git a/CadQuery/Examples/Ex029_Braille.py b/CadQuery/Examples/Ex029_Braille.py new file mode 100644 index 0000000..c366f4a --- /dev/null +++ b/CadQuery/Examples/Ex029_Braille.py @@ -0,0 +1,183 @@ +# -*- coding: utf-8 -*- + +from __future__ import unicode_literals, division + +from collections import namedtuple + +import cadquery as cq +from Helpers import show + +# text_lines is a list of text lines. +# FreeCAD in braille (converted with braille-converter: +# https://github.com/jpaugh/braille-converter.git). +text_lines = ['⠠ ⠋ ⠗ ⠑ ⠑ ⠠ ⠉ ⠠ ⠁ ⠠ ⠙'] +# See http://www.tiresias.org/research/reports/braille_cell.htm for examples +# of braille cell geometry. +horizontal_interdot = 2.5 +vertical_interdot = 2.5 +horizontal_intercell = 6 +vertical_interline = 10 +dot_height = 0.5 +dot_diameter = 1.3 + +base_thickness = 1.5 + +# End of configuration. +BrailleCellGeometry = namedtuple('BrailleCellGeometry', + ('horizontal_interdot', + 'vertical_interdot', + 'intercell', + 'interline', + 'dot_height', + 'dot_diameter')) + + +class Point(object): + def __init__(self, x, y): + self.x = x + self.y = y + + def __add__(self, other): + return Point(self.x + other.x, self.y + other.y) + + def __len__(self): + return 2 + + def __getitem__(self, index): + return (self.x, self.y)[index] + + def __str__(self): + return '({}, {})'.format(self.x, self.y) + + +def brailleToPoints(text, cell_geometry): + # Unicode bit pattern (cf. https://en.wikipedia.org/wiki/Braille_Patterns). + mask1 = 0b00000001 + mask2 = 0b00000010 + mask3 = 0b00000100 + mask4 = 0b00001000 + mask5 = 0b00010000 + mask6 = 0b00100000 + mask7 = 0b01000000 + mask8 = 0b10000000 + masks = (mask1, mask2, mask3, mask4, mask5, mask6, mask7, mask8) + + # Corresponding dot position + w = cell_geometry.horizontal_interdot + h = cell_geometry.vertical_interdot + pos1 = Point(0, 2 * h) + pos2 = Point(0, h) + pos3 = Point(0, 0) + pos4 = Point(w, 2 * h) + pos5 = Point(w, h) + pos6 = Point(w, 0) + pos7 = Point(0, -h) + pos8 = Point(w, -h) + pos = (pos1, pos2, pos3, pos4, pos5, pos6, pos7, pos8) + + # Braille blank pattern (u'\u2800'). + blank = '⠀' + points = [] + # Position of dot1 along the x-axis (horizontal). + character_origin = 0 + for c in text: + for m, p in zip(masks, pos): + delta_to_blank = ord(c) - ord(blank) + if (m & delta_to_blank): + points.append(p + Point(character_origin, 0)) + character_origin += cell_geometry.intercell + return points + + +def get_plate_height(text_lines, cell_geometry): + # cell_geometry.vertical_interdot is also used as space between base + # borders and characters. + return (2 * cell_geometry.vertical_interdot + + 2 * cell_geometry.vertical_interdot + + (len(text_lines) - 1) * cell_geometry.interline) + + +def get_plate_width(text_lines, cell_geometry): + # cell_geometry.horizontal_interdot is also used as space between base + # borders and characters. + max_len = max([len(t) for t in text_lines]) + return (2 * cell_geometry.horizontal_interdot + + cell_geometry.horizontal_interdot + + (max_len - 1) * cell_geometry.intercell) + + +def get_cylinder_radius(cell_geometry): + """Return the radius the cylinder should have + + The cylinder have the same radius as the half-sphere make the dots (the + hidden and the shown part of the dots). + The radius is such that the spherical cap with diameter + cell_geometry.dot_diameter has a height of cell_geometry.dot_height. + """ + h = cell_geometry.dot_height + r = cell_geometry.dot_diameter / 2 + return (r ** 2 + h ** 2) / 2 / h + + +def get_base_plate_thickness(plate_thickness, cell_geometry): + """Return the height on which the half spheres will sit""" + return (plate_thickness + + get_cylinder_radius(cell_geometry) - + cell_geometry.dot_height) + + +def make_base(text_lines, cell_geometry, plate_thickness): + base_width = get_plate_width(text_lines, cell_geometry) + base_height = get_plate_height(text_lines, cell_geometry) + base_thickness = get_base_plate_thickness(plate_thickness, cell_geometry) + base = cq.Workplane('XY').box(base_width, base_height, base_thickness, + centered=(False, False, False)) + return base + + +def make_embossed_plate(text_lines, cell_geometry): + """Make an embossed plate with dots as spherical caps + + Method: + - make a thin plate on which sit cylinders + - fillet the upper edge of the cylinders so to get pseudo half-spheres + - make the union with a thicker plate so that only the sphere caps stay + "visible". + """ + base = make_base(text_lines, cell_geometry, base_thickness) + + dot_pos = [] + base_width = get_plate_width(text_lines, cell_geometry) + base_height = get_plate_height(text_lines, cell_geometry) + y = base_height - 3 * cell_geometry.vertical_interdot + line_start_pos = Point(cell_geometry.horizontal_interdot, y) + for text in text_lines: + dots = brailleToPoints(text, cell_geometry) + dots = [p + line_start_pos for p in dots] + dot_pos += dots + line_start_pos += Point(0, -cell_geometry.interline) + + r = get_cylinder_radius(cell_geometry) + base = base.faces('>Z').vertices('Z').edges() \ + .fillet(r - 0.001) + hidding_box = cq.Workplane('XY').box( + base_width, base_height, base_thickness, centered=(False, False, False)) + result = hidding_box.union(base) + return result + +_cell_geometry = BrailleCellGeometry( + horizontal_interdot, + vertical_interdot, + horizontal_intercell, + vertical_interline, + dot_height, + dot_diameter) + +if base_thickness < get_cylinder_radius(_cell_geometry): + raise ValueError('Base thickness should be at least {}'.format(dot_height)) + +show(make_embossed_plate(text_lines, _cell_geometry))