Added can generator from erfindergarden
This commit is contained in:
parent
38f9545e31
commit
51bff15185
30
extensions/fablabchemnitz_can_generator.inx
Normal file
30
extensions/fablabchemnitz_can_generator.inx
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||
<_name>Can Generator</_name>
|
||||
<id>fablabchemnitz.de.can_generator</id>
|
||||
<param name="active-tab" type="notebook">
|
||||
<page name="config" _gui-text="Configuration">
|
||||
<param name="diameter" type="int" min="3" max="1200" _gui-text="Diameter of the can in mm">30</param>
|
||||
<param name="overhang" type="int" min="0" max="1200" _gui-text="Overhang of the can in mm">5</param>
|
||||
<param name="height" type="int" min="3" max="1000" _gui-text="Height of the can in mm">50</param>
|
||||
<param name="angle" type="float" min="8" max="22.5" _gui-text="Angle of the segments ( number of segments divisible by 2!)">22.5</param>
|
||||
<param name="material" type="float" min="0.2" max="5" _gui-text="Material thickness in mm">3.6</param>
|
||||
<param name="bottom" type="boolean" _gui-text="Top and bottom?">false</param>
|
||||
</page>
|
||||
<page name="hilfe" _gui-text="Hilfe">
|
||||
<_param name="use2" type="description" xml:space="preserve">The idea of the can generator is to cut plywood so deep that it can be bent without breaking. From the bent wood the side of the can is formed. The lid is not completely round, but cut in segments. The number of segments corresponds to the cuts in the side of the can. For this purpose, the wood must be cut across the grain direction. The angle determines the number of segments. For example, 22.5 degrees gives 16 segments. Less should not be less.
|
||||
</_param>
|
||||
</page>
|
||||
</param>
|
||||
<effect>
|
||||
<object-type>all</object-type>
|
||||
<effects-menu>
|
||||
<submenu _name="FabLab Chemnitz">
|
||||
<submenu _name="Finger-jointed/Tabbed Boxes" />
|
||||
</submenu>
|
||||
</effects-menu>
|
||||
</effect>
|
||||
<script>
|
||||
<command reldir="extensions" interpreter="python">fablabchemnitz_can_generator.py</command>
|
||||
</script>
|
||||
</inkscape-extension>
|
377
extensions/fablabchemnitz_can_generator.py
Normal file
377
extensions/fablabchemnitz_can_generator.py
Normal file
@ -0,0 +1,377 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
@author: mini@revollo.de
|
||||
member of the erfindergarden
|
||||
|
||||
Inkscape Erweiterung - Dosen Generator
|
||||
13.01.2019
|
||||
|
||||
Danke an neon22 https://github.com/Neon22/inkscape_extension_template
|
||||
Nach seiner Anleitung konnte ich dieses Programm erstellen.
|
||||
|
||||
'''
|
||||
|
||||
import inkex
|
||||
from lxml import etree
|
||||
from math import *
|
||||
|
||||
__version__ = '0.2'
|
||||
|
||||
inkex.localization.localize
|
||||
|
||||
def points_to_svgd(p, close = True):
|
||||
""" convert list of points (x,y) pairs
|
||||
into a closed SVG path list
|
||||
"""
|
||||
f = p[0]
|
||||
p = p[1:]
|
||||
svgd = 'M %.2f,%.2f ' % f
|
||||
for x in p:
|
||||
svgd += ' %.4f,%.4f' % x
|
||||
if close:
|
||||
svgd += 'z'
|
||||
return svgd
|
||||
|
||||
def punkte_erstellen(punkte, x, y):
|
||||
###Schreibt die aktuellen Koordinaten in die Punkteliste
|
||||
punkte.append((x, y))
|
||||
|
||||
class Dose(inkex.Effect):
|
||||
def __init__(self):
|
||||
inkex.Effect.__init__(self)
|
||||
self.arg_parser.add_argument("--height", type=int, default = 50, help="Höhe der Dose")
|
||||
self.arg_parser.add_argument("--overhang", type=int, default = 40, help="Überstand des Deckels")
|
||||
self.arg_parser.add_argument("--diameter", type=int, default = 40, help="diameter der Dose")
|
||||
self.arg_parser.add_argument("--angle", type=float, default = 22.5, help="angle der segments")
|
||||
self.arg_parser.add_argument("--material", type=float, default = 3.6, help="Materialstärke")
|
||||
self.arg_parser.add_argument("--bottom", type=inkex.Boolean, default = False, help="Deckel und bottom?")
|
||||
self.arg_parser.add_argument("--active-tab", default='title', help="Active tab.")
|
||||
|
||||
self.deckel_punkte = []
|
||||
self.deckel_pfad = []
|
||||
self.seite_punkte = []
|
||||
self.seite_pfad = []
|
||||
self.ausschnitt_punkte = []
|
||||
self.ausschnitt_pfad = []
|
||||
self.ausschnitt_nummer = 0
|
||||
self.einschnitt_punkte = []
|
||||
self.einschnitt_pfad = []
|
||||
self.einschnitt_nummer = 0
|
||||
self.einschnitt_breite = 0.2 #Abstand zwischen den beiden Einschnittlinien
|
||||
|
||||
|
||||
def pfad_erstellen(self, pfad, punkte):
|
||||
# Die gesammelten x und y Koordinaten der Punkte werden in Pfade (d) umgewandelt.
|
||||
|
||||
pfad.append(points_to_svgd(punkte))
|
||||
del punkte[:]
|
||||
|
||||
def pfade_schreiben(self):
|
||||
###Schreibt alle Pfade nacheinander in die Szene
|
||||
|
||||
path_stroke = '#101010' # Farbe für die Dose
|
||||
path_fill = 'none' # keine Füllung, nur eine Linie
|
||||
path_stroke_width = '0.4' # can also be in form '0.6mm'
|
||||
|
||||
for nummer in range(len(self.pfade)):
|
||||
# define style using basic dictionary
|
||||
pfad_attribute = {'id': "pfad%d"%nummer, 'stroke': path_stroke,
|
||||
'fill': path_fill, 'stroke-width': path_stroke_width,
|
||||
'd': self.pfade[nummer]}
|
||||
# add path to scene
|
||||
pfad = etree.SubElement(self.topgroup, inkex.addNS('path','svg'), pfad_attribute )
|
||||
|
||||
def deckel_erstellen(self):
|
||||
###Erstellt alle Punkte für den Aussenkreis des Deckels.
|
||||
angle = self.angle
|
||||
|
||||
segments = int(360 / angle)
|
||||
for segment_nr in range(segments + 1):
|
||||
#y berechnen = Gegenkathete
|
||||
y = sin(radians(angle)) * self.radius_mit_overhang * -1
|
||||
#Innenangle berechnen
|
||||
beta = 180 - 90 - angle
|
||||
#Ankathete berechnen
|
||||
b = sin(radians(beta)) * self.radius_mit_overhang
|
||||
#x berechnen
|
||||
x = self.radius_mit_overhang - b - self.overhang
|
||||
punkte_erstellen(self.deckel_punkte, x, y)
|
||||
angle += self.angle
|
||||
self.deckel_schreiben()
|
||||
|
||||
def deckel_schreiben(self):
|
||||
###Schreibt den Deckel ohne Ausschnitte in die Szene
|
||||
|
||||
path_stroke = '#0000ff' # Farbe für den Rand
|
||||
path_fill = 'none' # keine Füllung, nur eine Linie
|
||||
path_stroke_width = '0.6' # can also be in form '0.6mm'
|
||||
#Punkte zu Pfad umwandeln
|
||||
self.deckel_pfad = points_to_svgd(self.deckel_punkte, False)
|
||||
|
||||
# define style using basic dictionary
|
||||
deckel_attribute = {'id': "rand", 'stroke': path_stroke, 'fill': path_fill,
|
||||
'stroke-width': path_stroke_width , 'x': '0', 'y': '0', 'd': self.deckel_pfad}
|
||||
# add path to scene
|
||||
deckel = etree.SubElement(self.topgroup, inkex.addNS('path','svg'), deckel_attribute )
|
||||
|
||||
def ausschnitt_erstellen(self):
|
||||
###Erstellt alle Punkte für den Aussenkreis des Deckels.
|
||||
|
||||
angle = self.angle
|
||||
|
||||
for segment_nr in range(self.segments):
|
||||
|
||||
###Punkt 1 wird berechnet
|
||||
#y berechnen = Gegenkathete
|
||||
y = sin(radians(angle)) * self.radius * -1
|
||||
#Innenangle berechnen
|
||||
beta = 180 - 90 - angle
|
||||
#Ankathete berechnen
|
||||
b = sin(radians(beta)) * self.radius
|
||||
#x berechnen
|
||||
x = self.radius - b
|
||||
punkte_erstellen(self.ausschnitt_punkte, x, y)
|
||||
angle += self.angle
|
||||
|
||||
###Punkt 2 wird berechnet
|
||||
#y berechnen = Gegenkathete
|
||||
y = sin(radians(angle)) * self.radius * -1
|
||||
#Innenangle berechnen
|
||||
beta = 180 - 90 - angle
|
||||
#Ankathete berechnen
|
||||
b = sin(radians(beta)) * self.radius
|
||||
#x berechnen
|
||||
x = self.radius - b
|
||||
|
||||
punkte_erstellen(self.ausschnitt_punkte, x, y)
|
||||
|
||||
###Punkt 3 wird berechnet
|
||||
|
||||
alpha = angle - (self.angle / 2)
|
||||
beta = 180 - 90 - alpha
|
||||
y += sin(radians(alpha)) * self.material
|
||||
x += sin(radians(beta)) * self.material
|
||||
angle += self.angle
|
||||
punkte_erstellen(self.ausschnitt_punkte, x, y)
|
||||
|
||||
### Punkt 4 wird berechnet
|
||||
alpha = 180 - alpha
|
||||
beta = 180 - 90 - alpha
|
||||
x -= sin(radians(alpha)) * self.ausschnitt_breite
|
||||
y -= sin(radians(beta)) * self.ausschnitt_breite
|
||||
punkte_erstellen(self.ausschnitt_punkte, x, y)
|
||||
#
|
||||
self.ausschnitt_schreiben()
|
||||
del self.ausschnitt_punkte[:]
|
||||
|
||||
def ausschnitt_schreiben(self):
|
||||
###Schreibt den Ausschnitte in die Szene
|
||||
|
||||
path_stroke = '#ff0000' # Farbe für den Rand
|
||||
path_fill = 'none' # keine Füllung, nur eine Linie
|
||||
path_stroke_width = '0.6' # can also be in form '0.6mm'
|
||||
#Punkte zu Pfad umwandeln
|
||||
self.ausschnitt_pfad = points_to_svgd(self.ausschnitt_punkte, True)
|
||||
|
||||
# define style using basic dictionary
|
||||
ausschnitt_attribute = {'id': "ausschnitt_%s"%self.ausschnitt_nummer, 'stroke': path_stroke, 'fill': path_fill,
|
||||
'stroke-width': path_stroke_width , 'x': '0', 'y': '0', 'd': self.ausschnitt_pfad}
|
||||
self.ausschnitt_nummer += 1
|
||||
# add path to scene
|
||||
ausschnitt = etree.SubElement(self.topgroup, inkex.addNS('path','svg'), ausschnitt_attribute )
|
||||
|
||||
|
||||
def seite_erstellen(self):
|
||||
###Erstellt die Seite der Dose mit den Zinken und den Einschnitten###
|
||||
|
||||
x = 0
|
||||
y = self.radius_mit_overhang + 10
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
for item in range(int(self.segments / 2)):
|
||||
y -= self.material
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
x += self.ausschnitt_breite
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
y += self.material
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
x += self.ausschnitt_breite
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
if self.bottom == False:
|
||||
y += self.height - self.material
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
x -= self.segments * self.ausschnitt_breite
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
y -= self.height - self.material
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
else:
|
||||
y += self.height - self.material - self.material
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
for item in range(int(self.segments / 2)):
|
||||
x -= self.ausschnitt_breite
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
y += self.material
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
x -= self.ausschnitt_breite
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
y -= self.material
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
y -= self.height
|
||||
punkte_erstellen(self.seite_punkte, x, y)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
self.seite_schreiben()
|
||||
|
||||
def seite_schreiben(self):
|
||||
###Schreibt die Seite in die Szene
|
||||
|
||||
path_stroke = '#0000ff' # Farbe für den Rand
|
||||
path_fill = 'none' # keine Füllung, nur eine Linie
|
||||
path_stroke_width = '0.6' # can also be in form '0.6mm'
|
||||
#Punkte zu Pfad umwandeln
|
||||
self.seite_pfad = points_to_svgd(self.seite_punkte, True)
|
||||
|
||||
# define style using basic dictionary
|
||||
seite_attribute = {'id': "seite", 'stroke': path_stroke, 'fill': path_fill,
|
||||
'stroke-width': path_stroke_width , 'x': '0', 'y': '0', 'd': self.seite_pfad}
|
||||
# add path to scene
|
||||
seite = etree.SubElement(self.topgroup, inkex.addNS('path','svg'), seite_attribute )
|
||||
|
||||
def einschnitte_erstellen(self):
|
||||
###Erstellt die Einschnitte in die Seite
|
||||
|
||||
x = self.einschnitt_breite / -2
|
||||
y = self.radius_mit_overhang + 10 - self.material
|
||||
|
||||
for segment_nr in range(self.segments - 1):
|
||||
|
||||
###Punkt 1 wird berechnet
|
||||
x += self.ausschnitt_breite
|
||||
punkte_erstellen(self.einschnitt_punkte, x, y)
|
||||
###Punkt 2 wird berechnet
|
||||
x += self.einschnitt_breite
|
||||
punkte_erstellen(self.einschnitt_punkte, x, y)
|
||||
###Punkt 3 wird berechnet
|
||||
y += self.height
|
||||
punkte_erstellen(self.einschnitt_punkte, x, y)
|
||||
### Punkt 4 wird berechnet
|
||||
x -= self.einschnitt_breite
|
||||
punkte_erstellen(self.einschnitt_punkte, x, y)
|
||||
y -= self.height
|
||||
|
||||
self.einschnitte_schreiben()
|
||||
del self.einschnitt_punkte[:]
|
||||
|
||||
|
||||
|
||||
def einschnitte_schreiben(self):
|
||||
###Schreibt die Einschnitte in die Seite
|
||||
|
||||
path_stroke = '#00ff00' # Farbe für die Einschnitte
|
||||
path_fill = 'none' # keine Füllung, nur eine Linie
|
||||
path_stroke_width = '0.6' # can also be in form '0.6mm'
|
||||
#Punkte zu Pfad umwandeln
|
||||
self.einschnitt_pfad = points_to_svgd(self.einschnitt_punkte, True)
|
||||
|
||||
# define style using basic dictionary
|
||||
einschnitt_attribute = {'id': "einschnitt_%s"%self.einschnitt_nummer, 'stroke': path_stroke, 'fill': path_fill,
|
||||
'stroke-width': path_stroke_width , 'x': '0', 'y': '0', 'd': self.einschnitt_pfad}
|
||||
self.einschnitt_nummer += 1
|
||||
# add path to scene
|
||||
einschnitt = etree.SubElement(self.undergroup, inkex.addNS('path','svg'), einschnitt_attribute )
|
||||
|
||||
### -------------------------------------------------------------------
|
||||
### This is your main function and is called when the extension is run.
|
||||
|
||||
def effect(self):
|
||||
###Hauptprogramm
|
||||
|
||||
|
||||
# holt die Parameter aus Inkscape
|
||||
self.height = self.options.height
|
||||
self.diameter = self.options.diameter
|
||||
self.overhang = self.options.overhang
|
||||
self.radius = self.diameter / 2
|
||||
self.radius_mit_overhang = self.radius + self.overhang
|
||||
self.angle = self.options.angle
|
||||
self.bottom = self.options.bottom
|
||||
self.material = self.options.material
|
||||
self.segments = int(360 / self.angle)
|
||||
#Ausschnittbreite errechnen
|
||||
y = sin(radians(self.angle)) * self.radius
|
||||
beta = 180 - 90 - self.angle
|
||||
b = sin(radians(beta)) * self.radius
|
||||
x = self.radius - b
|
||||
self.ausschnitt_breite = sqrt((x * x) + (y * y))
|
||||
# what page are we on
|
||||
page_id = self.options.active_tab # sometimes wrong the very first time
|
||||
|
||||
#Eigenschaften der SVG auslesen und die Größe der Dose anpassen
|
||||
svg = self.document.getroot()
|
||||
#viewbox_size = '0 0 ' + str(self.breite) + ' ' + str(self.height)
|
||||
#svg.set('viewBox', viewbox_size)
|
||||
#svg.set('height', str(self.height))
|
||||
#svg.set('width', str(self.breite))
|
||||
|
||||
# Embed the path in a group to make animation easier:
|
||||
# Be sure to examine the internal structure by looking in the xml editor inside inkscape
|
||||
|
||||
# Make a nice useful name
|
||||
g_attribs = { inkex.addNS('label','inkscape'): 'dosen-gruppe', 'id': "dose",}
|
||||
# add the group to the document's current layer
|
||||
self.topgroup = etree.SubElement(self.svg.get_current_layer(), 'g', g_attribs )
|
||||
# Create SVG Path under this top level group
|
||||
# Make a nice useful name
|
||||
g_attribs = { inkex.addNS('label','inkscape'): 'einschnitt-gruppe', 'id': "einschnitte",}
|
||||
# add the group to the document's current layer
|
||||
self.undergroup = etree.SubElement(self.svg.get_current_layer(), 'g', g_attribs )
|
||||
# Create SVG Path under this top level group
|
||||
|
||||
self.deckel_erstellen()
|
||||
self.ausschnitt_erstellen()
|
||||
self.seite_erstellen()
|
||||
self.einschnitte_erstellen()
|
||||
|
||||
|
||||
# Make a nice useful name
|
||||
text_g_attribs = { inkex.addNS('label','inkscape'): 'dosen-gruppe', 'id': "Branding",}
|
||||
# add the group to the document's current layer
|
||||
textgroup = etree.SubElement(self.svg.get_current_layer(), 'g', text_g_attribs )
|
||||
|
||||
line_style = {'font-size': '10px', 'font-style':'normal', 'font-weight': 'normal',
|
||||
'fill': '#ff0000', 'font-family': 'Consolas',
|
||||
'text-anchor': 'start'}
|
||||
branding_line_attribs = {inkex.addNS('label','inkscape'): 'branding-text',
|
||||
'id': 'front text',
|
||||
'style': str(inkex.Style(line_style)),
|
||||
'x': str(0),
|
||||
'y': str(0)
|
||||
}
|
||||
|
||||
branding_line = etree.SubElement(textgroup, inkex.addNS('text','svg'), branding_line_attribs)
|
||||
branding_line.text = 'dosen-generator by mini revollo member of the erfindergarden'
|
||||
|
||||
# Make a nice useful name
|
||||
einschnitt_text_g_attribs = { inkex.addNS('label','inkscape'): 'einschnitt-gruppe', 'id': "Einschnitte_Text",}
|
||||
# add the group to the document's current layer
|
||||
textgroup = etree.SubElement(self.svg.get_current_layer(), 'g', einschnitt_text_g_attribs )
|
||||
|
||||
line_style = {'font-size': '5px', 'font-style':'normal', 'font-weight': 'normal',
|
||||
'fill': '#00ff00', 'font-family': 'Consolas',
|
||||
'text-anchor': 'start'}
|
||||
einschnitt_line_attribs = {inkex.addNS('label','inkscape'): 'Einschnitte_text',
|
||||
'id': 'front text',
|
||||
'style': str(inkex.Style(line_style)),
|
||||
'x': str(0),
|
||||
'y': str(self.radius_mit_overhang + self.height / 2)
|
||||
}
|
||||
|
||||
branding_line = etree.SubElement(textgroup, inkex.addNS('text','svg'), einschnitt_line_attribs)
|
||||
branding_line.text = 'Die Einschnitte nur zu 70 Prozent in das Material lasern'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
Dose().run()
|
Reference in New Issue
Block a user