Added can generator from erfindergarden

This commit is contained in:
Mario Voigt 2020-08-02 19:42:20 +02:00
parent 38f9545e31
commit 51bff15185
2 changed files with 407 additions and 0 deletions

View 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>

View 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()