Skip to content

Commit

Permalink
Add command to scale the image
Browse files Browse the repository at this point in the history
The command lets the user choose either the new length or width of the
image. Afterwards it adjusts the ppi value to get close to the user
entered size.

Also adds the new feature to the documentation

 #7
  • Loading branch information
furti committed Sep 18, 2018
1 parent 4c7a18e commit 4e08692
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 36 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ The name of the imported image object will be taken from the image file.

The image is also shown in the 3D View. The image is converted to grayscale and the size is the same as the final geometry created with the `Create Box` command. So you get a feeling for the final geometry even before creating it. The image is displayed 1 mm beneath the XY Plane. This makes it possible to trace over the image when needed.

To hide or show the image in the 3D view, select it and hit `Space`.

**The pixel data whil be computed every time you recompute the image object!** This can happen when you change some settings of the image or force a recompute of the whole document.
For performance reasons the calculated point cloud is stored inside the FreeCAD file. So your files can get pretty big real fast when you import big images.

Expand Down Expand Up @@ -120,6 +122,16 @@ The name of the resulting mesh will be taken from the selected LithophaneImage.

More Features might follow: https://github.com/furti/FreeCAD-Lithophane/issues/15

### Scale Image
![Scale Image](./Resources/Icons/Scale.svg)

This command can be used to scale the selected LithophaneImage. When executed, a task dialog will be shown. You can enter either the new length or width of the image. Entering one value will adjust the other value accordingly.

- OK will apply the new size to the image
- Cancel will simply close the dialog and nothing will be applied

![Scale Dialog](./Resources/Documentation/scale_dialog.png)

### Make Solid
![Import Image](./Resources/Icons/MakeSolid.svg)

Expand Down
Binary file added Resources/Documentation/scale_dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 11 additions & 23 deletions Resources/Icons/Resize.svg → Resources/Icons/Scale.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
72 changes: 72 additions & 0 deletions Resources/UI/scale_dialog.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Length (X)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="LengthBox">
<property name="suffix">
<string>mm</string>
</property>
<property name="maximum">
<double>100000.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="WidthBox">
<property name="suffix">
<string>mm</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Width (Y)</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="InfoLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
21 changes: 15 additions & 6 deletions lithophane_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from image_viewer import ImageViewer
from utils.geometry_utils import pointCloudToLines
from lithophane_utils import toChunks, tupleToVector, vectorToTuple, convertImageToTexture
from lithophane_utils import toChunks, tupleToVector, vectorToTuple, convertImageToTexture, recomputeView
from utils.timer import Timer, computeOverallTime
import utils.qtutils as qtutils

Expand Down Expand Up @@ -225,6 +225,12 @@ def execute(self, fp):

fp.UpdateNotifier += 1

def length(self):
return self.lines[-1][-1].x

def width(self):
return self.lines[-1][-1].y

def __getstate__(self):
'''Store the image as base64 inside the document'''

Expand Down Expand Up @@ -257,7 +263,7 @@ def __setstate__(self,state):
self.isLithophaneImage = True

return None

class ViewProviderLithophaneImage:
def __init__(self, vobj):
'''Only set our viewprovider as proxy. No properties needed'''
Expand Down Expand Up @@ -314,11 +320,12 @@ def updateData(self, fp, prop):

self.texture.image = convertImageToTexture(lithophaneImage.image)

topRight = lithophaneImage.lines[-1][-1]
length = lithophaneImage.length()
width = lithophaneImage.width()

self.coords.point.set1Value(1, topRight.x, 0, -1)
self.coords.point.set1Value(2, topRight.x, topRight.y, -1)
self.coords.point.set1Value(3, 0, topRight.y, -1)
self.coords.point.set1Value(1, length, 0, -1)
self.coords.point.set1Value(2, length, width, -1)
self.coords.point.set1Value(3, 0, width, -1)

return

Expand All @@ -344,6 +351,8 @@ def createImage(imagePath):
image = LithophaneImage(a, imagePath)
ViewProviderLithophaneImage(a.ViewObject)

recomputeView()

return image

if __name__ == "__main__":
Expand Down
18 changes: 13 additions & 5 deletions lithophane_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,29 @@ def recomputeView():
FreeCADGui.activeDocument().activeView().viewAxonometric()
FreeCADGui.SendMsgToActiveView("ViewFit")

def findSelectedImage():
def findSelectedImage(includeObject=False):
selection = FreeCADGui.Selection.getSelection()

if includeObject:
notFound = (None, None, None)
else:
notFound = (None, None)

if len(selection) != 1:
return (None, None)
return notFound

selectedObject = selection[0]

if not hasattr(selectedObject, 'Proxy') or selectedObject.Proxy is None:
return (None, None)
return notFound

if not hasattr(selectedObject.Proxy, 'isLithophaneImage') or not selectedObject.Proxy.isLithophaneImage:
return (None, None)
return notFound

return (selection[0].Proxy, selection[0].Label)
if includeObject:
return (selection[0].Proxy, selection[0].Label, selection[0])
else:
return (selection[0].Proxy, selection[0].Label)

def findSelectedMesh():
selection = FreeCADGui.Selection.getSelection()
Expand Down
96 changes: 96 additions & 0 deletions scale.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import FreeCAD, FreeCADGui

import lithophane_utils
from utils.resource_utils import iconPath, uiPath
from utils.format_utils import formatLength
import utils.qtutils as qtutils

class ScalePanel():
def __init__(self, image, freeCadObject):
self.image = image
self.freeCadObject = freeCadObject
self.originalLength = image.length()
self.originalWidth = image.width()
self.scaleFactor = 1

self.form = FreeCADGui.PySideUic.loadUi(uiPath('scale_dialog.ui'))

self.LengthBox = self.form.LengthBox
self.WidthBox = self.form.WidthBox
self.InfoLabel = self.form.InfoLabel
self.LengthBox.setValue(self.originalLength)
self.WidthBox.setValue(self.originalWidth)

self.LengthBox.valueChanged.connect(self.lengthChanged)
self.WidthBox.valueChanged.connect(self.widthChanged)

def accept(self):
FreeCADGui.Control.closeDialog()

if self.scaleFactor != 1:
self.InfoLabel.setText('The image is recomputed. This might take a while...')
qtutils.processEvents()

originalPpi = self.freeCadObject.ppi

# smaller ppi means larger image. So division not multiplication
self.freeCadObject.ppi = originalPpi / self.scaleFactor

lithophane_utils.recomputeView()

def reject(self):
FreeCADGui.Control.closeDialog()

def lengthChanged(self):
self.updateScaleFactor(self.originalLength, self.LengthBox.value())

newWidth = self.originalWidth * self.scaleFactor

if self.WidthBox.value() != newWidth:
self.WidthBox.setValue(newWidth)

def widthChanged(self):
self.updateScaleFactor(self.originalWidth, self.WidthBox.value())

newLength = self.originalLength * self.scaleFactor

if self.LengthBox.value() != newLength:
self.LengthBox.setValue(newLength)

def updateScaleFactor(self, old, new):
self.scaleFactor = new / old

class ScaleCommand:
toolbarName = 'Image_Tools'
commandName = 'Scale_Image'

def GetResources(self):
return {'MenuText': "Scale",
'ToolTip' : "Adjusts the dpi value to scale the final geometry",
'Pixmap': iconPath('Scale.svg')}

def Activated(self):
(image, label, freeCadObject) = lithophane_utils.findSelectedImage(includeObject=True)

if image is None:
qtutils.showInfo("No LithophaneImage selected", "Select exactly one LithophaneImage to continue")

return

panel = ScalePanel(image, freeCadObject)
FreeCADGui.Control.showDialog(panel)

def IsActive(self):
"""There should be at least an active document."""
return not FreeCAD.ActiveDocument is None

if __name__ == "__main__":
command = ScaleCommand();

if command.IsActive():
command.Activated()
else:
qtutils.showInfo("No open Document", "There is no open document")
else:
import toolbars
toolbars.toolbarManager.registerCommand(ScaleCommand())
1 change: 1 addition & 0 deletions toolbars.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def registerCommand(self, command):
# geometry tools
import import_image
import create_box
import scale

# solid tools
import make_solid
Expand Down
11 changes: 9 additions & 2 deletions utils/resource_utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import FreeCAD
from os import path

utils_path = path.join(path.dirname(path.realpath(__file__)), '../Resources/Icons')
resources_path = path.join(path.dirname(path.realpath(__file__)), '../Resources')
icons_path = path.join(resources_path, 'Icons')
ui_path = path.join(resources_path, 'UI')

def iconPath(name):
f = path.join(utils_path, name)
f = path.join(icons_path, name)

return f

def uiPath(name):
f = path.join(ui_path, name)

return f

0 comments on commit 4e08692

Please sign in to comment.