diff --git a/extensions/fablabchemnitz_realscale.inx b/extensions/fablabchemnitz_realscale.inx
new file mode 100644
index 00000000..a75b02de
--- /dev/null
+++ b/extensions/fablabchemnitz_realscale.inx
@@ -0,0 +1,92 @@
+
+
+ <_name>Scale To Real
+ fablabchemnitz.de.realscale
+
+
+ <_param name="measurement" type="description" appearance="header">Measurement
+ 100.0
+
+
+
+
+
+
+
+
+
+
+
+ <_param name="scale_drawing" type="description" appearance="header">Scale Drawing
+
+
+
+
+
+
+ 1:1
+ 1:2
+ 1:5
+ 1:10
+ 1:20
+ 1:25
+ 1:50
+ 1:100
+ 1:200
+ 1:250
+ 1:500
+ 1:1000
+ 1:1250
+ 1:2500
+
+
+ 1:1
+ 1:2
+ 1:4
+ 1:8
+ 1:16
+ 1:24
+ 1:32
+ 1:48
+ 1:64
+ 1:96
+ 1:128
+
+ 45
+ <_param name="scale_rule" type="description" appearance="header">Scale Rule
+ true
+
+
+
+
+
+
+
+ <_param name="usage" type="description" appearance="header">Usage
+ <_param name="Instructions" type="description" xml:space="preserve">Scale an object (or a group) by indicating the length of a scaling path in real-life units (useful for scaling architectural drawings, for example):
+
+• Create a straight two-point line of known length by drawing on the object you want to scale (e.g. if you know how long a wall is in your drawing, draw the line from one end of the wall to the other).
+
+• Select the line first, then the drawing (which must be a group or a single object).
+
+• Length: indicate how long the line you drew is in the real world (e.g. how long the wall is).
+
+• Unit: indicate the unit the measurement is in, but remember that your drawing can become huge if you choose km or even m. Fix this with "Scale Drawing".
+
+• Scale Drawing: Select a scale category, then a value other than 1:1 from the dropdown for the selected scale category to scale the drawing. For upscaling, select "Custom" and enter a custom value smaller than 1.
+
+• Scale Rule: You can display the scale with a ruler. The number of units used along the ruler can be selected (e.g. to make the ruler show marks for one, ten or one hundred centimeters).
+
+
+
+ all
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/extensions/fablabchemnitz_realscale.py b/extensions/fablabchemnitz_realscale.py
new file mode 100644
index 00000000..527edd93
--- /dev/null
+++ b/extensions/fablabchemnitz_realscale.py
@@ -0,0 +1,244 @@
+"""
+Copyright (C) 2015 Maren Hachmann, marenhachmann@yahoo.com
+Copyright (C) 2010 Blair Bonnett, blair.bonnett@gmail.com (parts from multiscale extension)
+Copyright (C) 2005 Aaron Spike, aaron@ekips.org (parts from perspective extension)
+Copyright (C) 2015 Giacomo Mirabassi, giacomo@mirabassi.it (parts from jpeg export extension)
+Copyright (C) 2016 Neon22 @github (scale ruler)
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+"""
+
+import math
+import inkex
+from inkex import Transform
+from inkex.paths import CubicSuperPath
+from lxml import etree
+
+inkex.localization.localize
+
+### Scale Ruler
+# inches = [1, 2, 4, 8, 16, 24, 32, 48, 64, 96, 128]
+# metric = [1,2,5,10,20,50,100,200,250,500,1000,1250,2500]
+
+# TODO:
+# - maybe turn dropdown for choosing scale type (metric/imperial/custom) into radio buttons?
+# - scale font size
+# - scale box-height better for small boxes
+# - add ruler into current layer
+# - add magnification e.g. 2:1 for small drawings
+
+class Realscale(inkex.Effect):
+ def __init__(self):
+ inkex.Effect.__init__(self)
+ self.arg_parser.add_argument('--tab')
+ self.arg_parser.add_argument('--length', type=float, default=100.0, help='Length of scaling path in real-world units')
+ self.arg_parser.add_argument('--unit', default='cm', help='Real-world unit')
+ self.arg_parser.add_argument('--showscale', default='false', help='Show Scale Ruler')
+ self.arg_parser.add_argument('--choosescale', default='all', help='Choose Scale')
+ self.arg_parser.add_argument('--metric', default='1', help='Common metric scales')
+ self.arg_parser.add_argument('--imperial',default='1', help='Common imperial scales')
+ self.arg_parser.add_argument('--custom_scale', type=float, default=45, help='Custom scale')
+ self.arg_parser.add_argument('--unitlength', type=int, default='1', help='Length of scale ruler')
+
+ def calc_scale_center(self, p1x, p1y, p2x, p2y):
+ """ Use straight line as scaling center.
+ - determine which point is center on basis of quadrant the line is in.
+ - approx this by using center of line
+ 0,0 corresponds to UL corner of page
+ """
+ scale_center = (0,0) # resulting scaling point
+ # calc page center
+ pagecenter_x = self.svg.unittouu(self.document.getroot().get('width'))/2
+ pagecenter_y = self.svg.unittouu(self.document.getroot().get('height'))/2
+ # calc minmax of straightline ref points
+ minx = min(p1x, p2x)
+ maxx = max(p1x, p2x)
+ miny = min(p1y, p2y)
+ maxy = max(p1y, p2y)
+ # simplifiy calc by using center of line to determine quadrant
+ line_x = p1x + (p2x - p1x)/2
+ line_y = p1y + (p2y - p1y)/2
+ # determine quadrant
+ if line_x < pagecenter_x:
+ # Left hand side
+ if line_y < pagecenter_y:
+ scale_center = (minx,miny) # UL
+ else:
+ scale_center = (minx,maxy) # LL
+ else: # Right hand side
+ if line_y < pagecenter_y:
+ scale_center = (maxx,miny) # UR
+ else:
+ scale_center = (maxx,maxy) # LR
+ #inkex.debug("%s %s,%s" % (scale_center, pagecenter_x*2, pagecenter_y*2))
+ return scale_center
+
+ def create_ruler(self, parent, width, pos, value, drawing_scale):
+ """ Draw Scale ruler
+ - Position above user's straightline.
+ - Ruler shows two units together. First one cut into 5
+ - pos is a tuple e.g. (0,0)
+
+ TODO:
+ - Fix font size for large and small rulers
+ - Fix line width for large and small rulers
+ """
+ " Ruler is always 2 units long with 5 divs in the left half "
+ # Draw two boxes next to each other. Top half of right half of ruler is filled black
+ line_width = self.svg.unittouu('0.25 mm')
+ box_height = max(width/15, self.svg.unittouu('2 mm'))
+ font_height = 8
+ White = '#ffffff'
+ Black = '#000000'
+ t = 'translate' + str(pos)
+
+ # create clip in order to get an exact ruler width (without the outer half of the stroke)
+ path = '//svg:defs'
+ defslist = self.document.getroot().xpath(path, namespaces=inkex.NSS)
+ if len(defslist) > 0:
+ defs = defslist[0]
+
+ clipPathData = {inkex.addNS('label', 'inkscape'):'rulerClipPath', 'clipPathUnits':'userSpaceOnUse', 'id':'rulerClipPath'}
+ clipPath = etree.SubElement(defs, 'clipPath', clipPathData)
+ clipBox = {'x':str(-width), 'y':'0.0',
+ 'width':str(width*2), 'height':str(box_height),
+ 'style':'fill:%s; stroke:none; fill-opacity:1;' % (Black)}
+
+ etree.SubElement(clipPath, 'rect', clipBox)
+
+ # create groups for scale rule and ruler
+ scale_group = etree.SubElement(parent, 'g', {inkex.addNS('label','inkscape'):'scale_group', 'transform':t})
+ ruler_group = etree.SubElement(scale_group, 'g', {inkex.addNS('label','inkscape'):'ruler', 'clip-path':"url(#rulerClipPath)"})
+
+ # box for right half of ruler
+ boxR = {'x':'0.0', 'y':'0.0',
+ 'width':str(width), 'height':str(box_height),
+ 'style':'fill:%s; stroke:%s; stroke-width:%s; stroke-opacity:1; fill-opacity:1;' % (White, Black, line_width)}
+ etree.SubElement(ruler_group, 'rect', boxR)
+ # top half black
+ boxRf = {'x':'0.0', 'y':'0.0',
+ 'width':str(width), 'height':str(box_height/2),
+ 'style':'fill:%s; stroke:none; fill-opacity:1;' % (Black)}
+ etree.SubElement(ruler_group, 'rect', boxRf)
+ # Left half of ruler
+ boxL = {'x':str(-width), 'y':'0.0',
+ 'width':str(width), 'height':str(box_height),
+ 'style':'fill:%s; stroke:%s; stroke-width:%s; stroke-opacity:1; fill-opacity:1;' % (White, Black, line_width)}
+ etree.SubElement(ruler_group, 'rect', boxL)
+ # staggered black fills on left half
+ start = -width
+ for i in range(5):
+ boxRf = {'x':str(start), 'y':str((i+1)%2 * box_height/2),
+ 'width':str(width/5), 'height':str(box_height/2),
+ 'style':'fill:%s; stroke:none; fill-opacity:1;' % (Black)}
+ etree.SubElement(ruler_group, 'rect', boxRf)
+ start += width/5
+ # text
+ textstyle = {'font-size': str(font_height)+ " px",
+ 'font-family': 'sans-serif',
+ 'text-anchor': 'middle',
+ 'text-align': 'center',
+ 'fill': Black }
+ text_atts = {'style': str(inkex.Style(textstyle)),
+ 'x': '0', 'y': str(-font_height/2) }
+ text = etree.SubElement(scale_group, 'text', text_atts)
+ text.text = "0"
+ text_atts = {'style': str(inkex.Style(textstyle)),
+ 'x': str(width), 'y': str(-font_height/2) }
+ text = etree.SubElement(scale_group, 'text', text_atts)
+ text.text = str(value)
+
+ text_atts = {'style':str(inkex.Style(textstyle)),
+ 'x': str(-width), 'y': str(-font_height/2) }
+ text = etree.SubElement(scale_group, 'text', text_atts)
+ text.text = str(value)
+ # Scale note
+ text_atts = {'style':str(inkex.Style(textstyle)),
+ 'x': '0', 'y': str(-font_height*2.5) }
+ text = etree.SubElement(scale_group, 'text', text_atts)
+ text.text = "Scale 1:" + str(drawing_scale) + " (" + self.options.unit + ")"
+
+
+ def effect(self):
+ if len(self.options.ids) != 2:
+ inkex.errormsg(_("This extension requires two selected objects. The first selected object must be the straight line with two nodes."))
+ exit()
+
+ # drawing that will be scaled is selected second, must be a single object
+ scalepath = self.svg.selected[self.options.ids[0]]
+ drawing = self.svg.selected[self.options.ids[1]]
+
+ if scalepath.tag != inkex.addNS('path','svg'):
+ inkex.errormsg(_("The first selected object is not a path.\nPlease select a straight line with two nodes instead."))
+ exit()
+
+ # apply its transforms to the scaling path, so we get the correct coordinates to calculate path length
+ scalepath.apply_transform()
+
+ path = CubicSuperPath(scalepath.get('d'))
+ if len(path) < 1 or len(path[0]) < 2:
+ inkex.errormsg(_("This extension requires that the first selected path be two nodes long."))
+ exit()
+
+ # calculate path length
+ p1_x = path[0][0][1][0]
+ p1_y = path[0][0][1][1]
+ p2_x = path[0][1][1][0]
+ p2_y = path[0][1][1][1]
+
+ p_length = self.svg.unittouu(str(distance((p1_x, p1_y),(p2_x, p2_y))) + self.svg.unit)
+
+ # Find Drawing Scale
+ if self.options.choosescale == 'metric':
+ drawing_scale = int(self.options.metric)
+ elif self.options.choosescale == 'imperial':
+ drawing_scale = int(self.options.imperial)
+ elif self.options.choosescale == 'custom':
+ drawing_scale = self.options.custom_scale
+
+ # calculate scaling center
+ center = self.calc_scale_center(p1_x, p1_y, p2_x, p2_y)
+
+ # calculate scaling factor
+ target_length = self.svg.unittouu(str(self.options.length) + self.options.unit)
+ factor = (target_length / p_length) / drawing_scale
+ # inkex.debug("%s, %s %s" % (target_length, p_length, factor))
+
+ # Add scale ruler
+ if self.options.showscale == "true":
+ dist = int(self.options.unitlength)
+
+ ruler_length = self.svg.unittouu(str(dist) + self.options.unit) / drawing_scale
+ ruler_pos = (p1_x + (p2_x - p1_x)/2, (p1_y + (p2_y - p1_y)/2) - self.svg.unittouu('4 mm'))
+
+ # TODO: add into current layer instead
+ self.create_ruler(self.document.getroot(), ruler_length, ruler_pos, dist, drawing_scale)
+
+ # Get drawing and current transformations
+ for obj in (scalepath, drawing):
+ # Scale both objects about the center, first translate back to origin
+ scale_matrix = [[1, 0.0, -center[0]], [0.0, 1, -center[1]]]
+ obj.transform = Transform(scale_matrix) * obj.transform
+ # Then scale
+ scale_matrix = [[factor, 0.0, 0.0], [0.0, factor, 0.0]]
+ obj.transform = Transform(scale_matrix) * obj.transform
+ # Then translate back to original scale center location
+ scale_matrix = [[1, 0.0, center[0]], [0.0, 1, center[1]]]
+ obj.transform = Transform(scale_matrix) * obj.transform
+
+# Helper function
+def distance(xy0, xy1):
+ x0, y0 = xy0
+ x1, y1 = xy1
+ return math.sqrt((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1))
+
+if __name__ == '__main__':
+ Realscale().run()
\ No newline at end of file