41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
74 |
--------------------------------------------------------------------------------
/Image2Surface.manifest:
--------------------------------------------------------------------------------
1 | {
2 | "autodeskProduct": "Fusion360",
3 | "type": "addin",
4 | "id": "8292ed75-c934-42d6-a7b3-65ac1c3a4102",
5 | "author": "Hans Kellner",
6 | "description": {
7 | "": "This is an Autodesk Fusion 360 script that's used for generating surfaces from images."
8 | },
9 | "version": "2.0",
10 | "runOnStartup": false,
11 | "supportedOS": "windows|mac",
12 | "editEnabled": true
13 | }
--------------------------------------------------------------------------------
/Image2Surface.py:
--------------------------------------------------------------------------------
1 | #Author-Hans Kellner
2 | #Description-This is an Autodesk Fusion 360 script that's used for generating surfaces from images.
3 | #Copyright (C) 2015-2018 Hans Kellner: https://github.com/hanskellner/Fusion360Image2Surface
4 | #MIT License: See https://github.com/hanskellner/Fusion360Image2Surface/LICENSE.md
5 |
6 | import adsk.core, adsk.fusion, adsk.cam, traceback
7 | import json, tempfile, platform
8 |
9 | # global set of event handlers to keep them referenced for the duration of the command
10 | handlers = []
11 | _app = adsk.core.Application.cast(None)
12 | _ui = adsk.core.UserInterface.cast(None)
13 |
14 | # Event handler for the commandExecuted event.
15 | class ShowPaletteCommandExecuteHandler(adsk.core.CommandEventHandler):
16 | def __init__(self):
17 | super().__init__()
18 | def notify(self, args):
19 | try:
20 |
21 | global _app, _ui
22 |
23 | # Verify that in parametric design mode
24 | design = _app.activeProduct
25 | if design.designType != adsk.fusion.DesignTypes.ParametricDesignType:
26 | _ui.messageBox('The "Image2Surface" command must be run in parametric modeling mode.\n\nPlease enable "Capture design history" for your document.')
27 | return
28 |
29 | # Create and display the palette.
30 | palette = _ui.palettes.itemById('Image2SurfacePalette')
31 | if not palette:
32 | palette = _ui.palettes.add('Image2SurfacePalette', 'Image2Surface', 'image2surface.html', True, True, True, 1200, 800)
33 |
34 | # Float the palette.
35 | palette.dockingState = adsk.core.PaletteDockingStates.PaletteDockStateFloating
36 |
37 | # Add handler to HTMLEvent of the palette.
38 | onHTMLEvent = MyHTMLEventHandler()
39 | palette.incomingFromHTML.add(onHTMLEvent)
40 | handlers.append(onHTMLEvent)
41 |
42 | # Add handler to CloseEvent of the palette.
43 | onClosed = MyCloseEventHandler()
44 | palette.closed.add(onClosed)
45 | handlers.append(onClosed)
46 | else:
47 | palette.isVisible = True
48 | except:
49 | _ui.messageBox('Command executed failed: {}'.format(traceback.format_exc()))
50 |
51 |
52 | # Event handler for the commandCreated event.
53 | class ShowPaletteCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
54 | def __init__(self):
55 | super().__init__()
56 | def notify(self, args):
57 | try:
58 | command = args.command
59 | onExecute = ShowPaletteCommandExecuteHandler()
60 | command.execute.add(onExecute)
61 | handlers.append(onExecute)
62 | except:
63 | _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
64 |
65 |
66 | # Event handler for the commandExecuted event.
67 | class SendInfoCommandExecuteHandler(adsk.core.CommandEventHandler):
68 | def __init__(self):
69 | super().__init__()
70 | def notify(self, args):
71 | try:
72 | # Send information to the palette. This will trigger an event in the javascript
73 | # within the html so that it can be handled.
74 | palette = _ui.palettes.itemById('Image2SurfacePalette')
75 | if palette:
76 | palette.sendInfoToHTML('send', 'This is a message sent to the palette from Fusion.')
77 | except:
78 | _ui.messageBox('Command executed failed: {}'.format(traceback.format_exc()))
79 |
80 |
81 | # Event handler for the commandCreated event.
82 | class SendInfoCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
83 | def __init__(self):
84 | super().__init__()
85 | def notify(self, args):
86 | try:
87 | command = args.command
88 | onExecute = SendInfoCommandExecuteHandler()
89 | command.execute.add(onExecute)
90 | handlers.append(onExecute)
91 | except:
92 | _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
93 |
94 |
95 | # Event handler for the palette close event.
96 | class MyCloseEventHandler(adsk.core.UserInterfaceGeneralEventHandler):
97 | def __init__(self):
98 | super().__init__()
99 | def notify(self, args):
100 | try:
101 | # _ui.messageBox('Close button is clicked.')
102 | foo = 1
103 | if foo == 2:
104 | foo = 2
105 | except:
106 | _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
107 |
108 |
109 | # Event handler for the palette HTML event.
110 | class MyHTMLEventHandler(adsk.core.HTMLEventHandler):
111 | def __init__(self):
112 | super().__init__()
113 | def notify(self, args):
114 | try:
115 | htmlArgs = adsk.core.HTMLEventArgs.cast(args)
116 | data = json.loads(htmlArgs.data)
117 |
118 | objStr = data['obj']
119 | objStrLen = len(data['obj'])
120 |
121 | if objStrLen > 0:
122 |
123 | fp = tempfile.NamedTemporaryFile(mode='w', suffix='.obj', delete=False)
124 | fp.writelines(objStr)
125 | fp.close()
126 | objFilePath = fp.name
127 | print ("Generated OBJ File: " + objFilePath)
128 |
129 | global _app
130 |
131 | # Get the current document, otherwise create a new one.
132 | doc = _app.activeDocument
133 | if not doc:
134 | doc = _app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)
135 |
136 | design = _app.activeProduct
137 |
138 | # Get the root component of the active design.
139 | rootComp = design.rootComponent
140 |
141 | # Need to place the mesh in a BaseFeature (non-parametric)
142 | baseFeats = rootComp.features.baseFeatures
143 | baseFeat = baseFeats.add()
144 | baseFeat.startEdit()
145 |
146 | # Add a mesh body by importing this data (OBJ) file.
147 | meshList = rootComp.meshBodies.add(objFilePath, adsk.fusion.MeshUnits.MillimeterMeshUnit, baseFeat)
148 |
149 | # Need to finish the base feature edit
150 | baseFeat.finishEdit()
151 |
152 | if meshList.count > 0:
153 | # Success - close palette
154 | palette = _ui.palettes.itemById('Image2SurfacePalette')
155 | if palette:
156 | palette.isVisible = False
157 |
158 | # HACK: bug causes mesh to be placed away from origin
159 | # therefore zoom to fit so mesh appears to user
160 | vp = _app.activeViewport
161 | vp.fit()
162 | else:
163 | _ui.messageBox('Failed to generate mesh body from file: {}'.format(objFilePath))
164 |
165 | else:
166 | _ui.messageBox('Failed to generate mesh OBJ')
167 |
168 | except:
169 | _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
170 |
171 |
172 | def run(context):
173 | try:
174 | global _ui, _app
175 | _app = adsk.core.Application.get()
176 | _ui = _app.userInterface
177 |
178 | # Add a command that displays the panel.
179 | showPaletteCmdDef = _ui.commandDefinitions.itemById('showImage2SurfacePalette')
180 | if not showPaletteCmdDef:
181 | #strTooltip = '
Image 2 Surface
Use this add-in to convert an image into a surface (mesh).'
182 | showPaletteCmdDef = _ui.commandDefinitions.addButtonDefinition('showImage2SurfacePalette', 'Show Image 2 Surface', '', './/Resources//image2surface')
183 | showPaletteCmdDef.toolClipFilename = './/Resources//image2surface//image2surface-tooltip.png'
184 |
185 | # Connect to Command Created event.
186 | onCommandCreated = ShowPaletteCommandCreatedHandler()
187 | showPaletteCmdDef.commandCreated.add(onCommandCreated)
188 | handlers.append(onCommandCreated)
189 |
190 | # Add the command to the toolbar.
191 | panel = _ui.allToolbarPanels.itemById('SolidScriptsAddinsPanel')
192 | cntrl = panel.controls.itemById('showImage2SurfacePalette')
193 | if not cntrl:
194 | panel.controls.addCommand(showPaletteCmdDef)
195 |
196 | if context['IsApplicationStartup'] is False:
197 | _ui.messageBox('The "Image2Surface" command has been added\nto the ADD-INS panel dropdown of the MODEL workspace.\n\nTo run the command, select the ADD-INS dropdown\nthen select "Show Image 2 Surface".')
198 | except:
199 | if _ui:
200 | _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
201 |
202 |
203 | def stop(context):
204 | try:
205 | # Delete the palette created by this add-in.
206 | palette = _ui.palettes.itemById('Image2SurfacePalette')
207 | if palette:
208 | palette.deleteMe()
209 |
210 | # Delete controls and associated command definitions created by this add-ins
211 | panel = _ui.allToolbarPanels.itemById('SolidScriptsAddinsPanel')
212 | cmd = panel.controls.itemById('showImage2SurfacePalette')
213 | if cmd:
214 | cmd.deleteMe()
215 | cmdDef = _ui.commandDefinitions.itemById('showImage2SurfacePalette')
216 | if cmdDef:
217 | cmdDef.deleteMe()
218 | except:
219 | if _ui:
220 | _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (C) 2015-2018 Hans Kellner
2 | https://github.com/hanskellner/Fusion360Image2Surface
3 |
4 | Licensed under The MIT License
5 | http://en.wikipedia.org/wiki/MIT_License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #  Fusion 360 Image 2 Surface Add-In
2 |
3 | This is an [Autodesk Fusion 360](http://fusion360.autodesk.com/) add-in that's used for generating surfaces from images.
4 |
5 | 
6 |
7 | ##  Moon Surface Example
8 |
9 | This surface was created from a small height map of a crater on Earth's moon. The first image is the mesh created from the script. The second is the T-Spline surface created from the mesh.
10 |
11 | 
12 |
13 | 
14 |
15 | ##  Milled Penny Example
16 |
17 | This is a penny that was milled out of a 4"x4" block of 6061 Aluminum. The surface was created from a height map of a penny. The mesh was then converted to a T-Spline then merged onto a cube. That model was brought into the CAM environment where the various milling operations were defined. Finally, it was milled on a Haas CNC vertical milling machine.
18 |
19 | 
20 |
21 | 
22 |
23 | 
24 |
25 | ## How to install a Fusion 360 Add-In
26 |
27 | Please see the most recent add-in install instructions here:
28 |
29 | https://knowledge.autodesk.com/support/fusion-360/troubleshooting/caas/sfdcarticles/sfdcarticles/How-to-install-an-ADD-IN-and-Script-in-Fusion-360.html
30 |
31 | Download the archive file (ZIP) from Github by clicking on the "Clone or download" button and then selecting "Download ZIP":
32 |
33 | 
34 |
35 | Unarchive this file into the Addins folder and once created, rename the folder created from the Zip archive name "Fusion360Image2Surface-master.zip" to "Image2Surface":
36 |
37 | 
38 |
39 | You will then be able to use the Fusion 360 Scripts and Addins Manager to add this folder, and thus the addin, to Fusion. Note, select the "Run on Startup" checkbox if you would like the add-in automatically started when Fusion 360 starts up. This is useful if you will be using the add-in often.
40 |
41 | The first time you run the Image2Surface add-in, it will add itself to the Add-ins panel dropdown of the Model environment. It should appear as an entry with the label "Show Image 2 Surface".
42 |
43 | ## Usage
44 |
45 | **Important: This add-in requires the document to be in parametric modeling mode (i.e. Capturing design history).**
46 |
47 | 1. Enter the Model environment
48 | 2. Run the Image2Surface add-in from the Scripts and Add-Ins Manager. Note, select the "Run on Startup" checkbox if you would like the add-in automatically started when Fusion 360 starts up and avoid having to manually run each time.
49 |
50 | 
51 |
52 | 3. Display the Image 2 Surface Palette.
53 |
54 | 
55 |
56 | - Click on the ADD-INS dropdown and then click on the "Image 2 Surface" menu item. This should display the palette.
57 | - If the menu item isn't there then there might have been a problem running the add-in. Go back to step 2 and try again.
58 |
59 | 
60 |
61 | - This palette window contains a preview of the surface mesh that will be generated as well as controls for adjusting the mesh.
62 | 4. Select an image file
63 | - Drag and Drop an image file onto the palette window. It should be displaying the text "Drop Image Here". If not, click the "Clear Image" button.
64 | - *TODO: Alternatively, click the "Open Image File" button and then select the file in the fial dialog.*
65 | - WARNING: overly large images may cause problems (even crash the app). Please work with images under 1000x1000 at first. If you would like to try larger images, please save your work first in case loading the large image causes a crash.
66 | 5. Preview the surface mesh
67 | - If the image is loaded correctly, it we be converted to a prelimary mesh and displayed in the view.
68 | - Adjust View
69 | - Left mouse button to rotate the view
70 | - Middle mouse button to pan the view
71 | - Mousewheel to zoom in/out
72 | 6. Adjust the mesh parameters
73 |
74 | 
75 |
76 | - In the upper right of the view is small dialog containing parameters that control the mesh:
77 | - Pixels to Skip:
78 | - This is the number of pixels to skip over for each row and column on the source image
79 | - Stepover (mm):
80 | - This is the distance in millimeters between each mesh grid line.
81 | - Max Height (mm):
82 | - This is the max height in millimeters of each grid node. Each node's height is based on the color of the associate image pixel. Black maps to zero (0) and pure white to the "Max Height" value. Or the inverse if Invert checked.
83 | - Invert Heights:
84 | - If checked then black maps to "Max Height" and pure white to zero (0).
85 | - Smooth:
86 | - Apply a smoothing to the values to help reduce sharp ridges.
87 | - Absolute (B&W):
88 | - If checked then the height is based on the average of the pixel RGB value. Otherwise, it takes into account the human perceptual bias of the RGB individual values.
89 | 7. Generate a surface/mesh
90 | - When ready to generate a mesh within the active document, click the "Generate Surface" button.
91 |
92 | Once the mesh generated it will be added to the active drawing. You might have to "fit" the view to see it.
93 |
94 | If you have created a mesh then it's useful to convert it to a T-Spline or BREP for further modification. Note, Fusion has a limitation on the size of the mesh that can be converted to a BREP (around 10K faces). With a T-Spline or BREP surface it's possible to CNC or 3D print.
95 |
96 | - Convert the Mesh to a T-Spline
97 |
98 | 1. Click on the "Create Form" button on the toolbar to enter the "Sculpt" environment
99 | 2. Click on the "Utilities" button and then the "Convert" item to display the dialog:
100 |
101 | 
102 |
103 | 3. In the dialog, select the "Quad Mesh to T-Spline" type
104 | 4. For the "Selection", select the mesh in the drawing then click OK
105 |
106 | - Convert the Mesh to a BREP
107 |
108 | 1. Enter the Model environment
109 | 2. Select the Create->Create a Base Feature item from the toolbar
110 | 3. Right-click/Ctrl-click on the mesh and in the context menu, select Mesh to BRep.
111 | 4. In the dialog displayed, the mesh should already be selected. Click OK.
112 |
113 | Here's the heightmap image of the moon's surface that was used to generate the mesh and t-spline shown at the top of the page.
114 |
115 | 
116 |
117 | And here's the t-spline in the CAM environment being used to create toolpaths for milling:
118 |
119 | 
120 |
121 | More examples posted on my [Fusion 360 project gallery](https://fusion360.autodesk.com/users/hans-kellner).
122 |
123 | ## Trouble Shooting
124 |
125 | - Add-in fails to load. Verify that the add-in has been placed in its own folder within the Addins folder. If the files are not placed in their own folder then Fusion 360 will tend to fail loadin the add-in.
126 | - Large images can create large meshes which can cause Fusion 360 to take a very long time to process. Or the app may just fail. Try using a smaller resolution image.
127 |
128 | ## Issues
129 |
130 | - 2016.02 : Fusion 360 has a 10K limitation on mesh size when converting to a BREP. Any larger and it fails.
131 |
--------------------------------------------------------------------------------
/Resources/ConvertMeshToTSpline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/ConvertMeshToTSpline.png
--------------------------------------------------------------------------------
/Resources/ConvertMoonMeshToTSpline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/ConvertMoonMeshToTSpline.png
--------------------------------------------------------------------------------
/Resources/CreateBaseFeature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/CreateBaseFeature.png
--------------------------------------------------------------------------------
/Resources/Fusion360AddinsFolder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/Fusion360AddinsFolder.png
--------------------------------------------------------------------------------
/Resources/GitHubDownloadZIP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/GitHubDownloadZIP.png
--------------------------------------------------------------------------------
/Resources/Image2SurfacePalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/Image2SurfacePalette.png
--------------------------------------------------------------------------------
/Resources/MoonCAMToolpaths.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/MoonCAMToolpaths.png
--------------------------------------------------------------------------------
/Resources/MoonHeightmap.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/MoonHeightmap.jpg
--------------------------------------------------------------------------------
/Resources/MoonMesh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/MoonMesh.png
--------------------------------------------------------------------------------
/Resources/MoonTSpline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/MoonTSpline.png
--------------------------------------------------------------------------------
/Resources/ParametersDialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/ParametersDialog.png
--------------------------------------------------------------------------------
/Resources/Penny_CNC_Size_-_IMG_3813-sm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/Penny_CNC_Size_-_IMG_3813-sm.jpg
--------------------------------------------------------------------------------
/Resources/Penny_F360CAMAdaptive3D.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/Penny_F360CAMAdaptive3D.jpg
--------------------------------------------------------------------------------
/Resources/Penny_F360CAMMorphedSpiral3D.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/Penny_F360CAMMorphedSpiral3D.jpg
--------------------------------------------------------------------------------
/Resources/ScriptsAndAdd-Ins.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/ScriptsAndAdd-Ins.png
--------------------------------------------------------------------------------
/Resources/ShowImage2SurfacePalette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/ShowImage2SurfacePalette.png
--------------------------------------------------------------------------------
/Resources/image2surface/.gitignore:
--------------------------------------------------------------------------------
1 | *.psd
2 |
3 |
--------------------------------------------------------------------------------
/Resources/image2surface/16x16-disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/16x16-disabled.png
--------------------------------------------------------------------------------
/Resources/image2surface/16x16-disabled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/16x16-disabled@2x.png
--------------------------------------------------------------------------------
/Resources/image2surface/16x16-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/16x16-pressed.png
--------------------------------------------------------------------------------
/Resources/image2surface/16x16-pressed@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/16x16-pressed@2x.png
--------------------------------------------------------------------------------
/Resources/image2surface/16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/16x16.png
--------------------------------------------------------------------------------
/Resources/image2surface/16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/16x16@2x.png
--------------------------------------------------------------------------------
/Resources/image2surface/32x32-disabled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/32x32-disabled.png
--------------------------------------------------------------------------------
/Resources/image2surface/32x32-disabled@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/32x32-disabled@2x.png
--------------------------------------------------------------------------------
/Resources/image2surface/32x32-pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/32x32-pressed.png
--------------------------------------------------------------------------------
/Resources/image2surface/32x32-pressed@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/32x32-pressed@2x.png
--------------------------------------------------------------------------------
/Resources/image2surface/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/32x32.png
--------------------------------------------------------------------------------
/Resources/image2surface/32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/32x32@2x.png
--------------------------------------------------------------------------------
/Resources/image2surface/image2surface-tooltip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/image2surface/image2surface-tooltip.png
--------------------------------------------------------------------------------
/Resources/samples/Grid 100x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/samples/Grid 100x100.png
--------------------------------------------------------------------------------
/Resources/samples/Hairy Dog.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/samples/Hairy Dog.jpg
--------------------------------------------------------------------------------
/Resources/samples/mona-lisa-twin.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/samples/mona-lisa-twin.jpeg
--------------------------------------------------------------------------------
/Resources/samples/moonsurfcontrast.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/samples/moonsurfcontrast.jpg
--------------------------------------------------------------------------------
/Resources/samples/penny_depthmap_500-sm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/samples/penny_depthmap_500-sm.jpg
--------------------------------------------------------------------------------
/Resources/samples/penny_depthmap_500.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanskellner/Fusion360Image2Surface/e54a567ce123b1365f6a253e9df91f54e561aea6/Resources/samples/penny_depthmap_500.jpg
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | width: 100%;
3 | height: 100%;
4 | background-color: rgb(102, 255, 0);
5 | margin: 0px;
6 | overflow: hidden;
7 | font-family: Helvetica Neue, Arial, sans-serif;
8 | font-size: 12px;
9 | line-height: 1.5em;
10 | color: #ccc;
11 | }
12 | a {
13 | color: #fff;
14 | text-decoration: none;
15 | }
16 | #controls {
17 | position: fixed;
18 | top: 10px;
19 | left: 10px;
20 | width: 250px;
21 | background-color:rgb(0, 32, 70);
22 | padding:10px;
23 | margin:0;
24 | border: 2px solid rgb(80, 80, 80, 0.5);
25 | border-radius: 4px;
26 | -moz-box-shadow: 0 0 15px rgba(0, 0, 0, .6);
27 | -webkit-box-shadow: 0 0 15px rgba(0, 0, 0, .6);
28 | box-shadow: 0 0 15px rgba(0, 0, 0, .6);
29 | }
30 | #content {
31 | height: 100%;
32 | width: 100%;
33 | background-color: rgb(0, 0, 0);
34 | -moz-box-shadow: 0 0 15px rgba(0, 0, 0, .6);
35 | -webkit-box-shadow: 0 0 15px rgba(0, 0, 0, .6);
36 | box-shadow: 0 0 15px rgba(0, 0, 0, .6);
37 | }
38 | #dropzone {
39 | position: fixed;
40 | display: none;
41 | width: 400;
42 | height: 200;
43 | top: 0;
44 | left: 0;
45 | right: 0;
46 | bottom: 0;
47 | background-color: rgb(0, 0, 0, 0.8); /* Black background with opacity */
48 | }
49 | #dropzone span {
50 | position: absolute;
51 | top: 50%;
52 | left: 50%;
53 | font-size: 50px;
54 | color: white;
55 | transform: translate(-50%,-50%);
56 | -ms-transform: translate(-50%,-50%);
57 | font-family: Helvetica Neue, Arial, sans-serif;
58 | }
59 |
--------------------------------------------------------------------------------
/js/DAT.GUI.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * dat-gui JavaScript Controller Library
3 | * http://code.google.com/p/dat-gui
4 | *
5 | * Copyright 2011 Data Arts Team, Google Creative Lab
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | */
13 | var dat=dat||{};dat.gui=dat.gui||{};dat.utils=dat.utils||{};dat.controllers=dat.controllers||{};dat.dom=dat.dom||{};dat.color=dat.color||{};dat.utils.css=function(){return{load:function(e,a){var a=a||document,c=a.createElement("link");c.type="text/css";c.rel="stylesheet";c.href=e;a.getElementsByTagName("head")[0].appendChild(c)},inject:function(e,a){var a=a||document,c=document.createElement("style");c.type="text/css";c.innerHTML=e;a.getElementsByTagName("head")[0].appendChild(c)}}}();
14 | dat.utils.common=function(){var e=Array.prototype.forEach,a=Array.prototype.slice;return{BREAK:{},extend:function(c){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(a[f])||(c[f]=a[f])},this);return c},defaults:function(c){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(c[f])&&(c[f]=a[f])},this);return c},compose:function(){var c=a.call(arguments);return function(){for(var d=a.call(arguments),f=c.length-1;f>=0;f--)d=[c[f].apply(this,d)];return d[0]}},
15 | each:function(a,d,f){if(e&&a.forEach===e)a.forEach(d,f);else if(a.length===a.length+0)for(var b=0,n=a.length;b-1?d.length-d.indexOf(".")-1:0};c.superclass=e;a.extend(c.prototype,e.prototype,{setValue:function(a){if(this.__min!==void 0&&athis.__max)a=this.__max;this.__step!==void 0&&a%this.__step!=0&&(a=Math.round(a/this.__step)*this.__step);return c.superclass.prototype.setValue.call(this,a)},min:function(a){this.__min=a;return this},max:function(a){this.__max=a;return this},step:function(a){this.__step=a;return this}});return c}(dat.controllers.Controller,dat.utils.common);
29 | dat.controllers.NumberControllerBox=function(e,a,c){var d=function(f,b,e){function h(){var a=parseFloat(l.__input.value);c.isNaN(a)||l.setValue(a)}function j(a){var b=o-a.clientY;l.setValue(l.getValue()+b*l.__impliedStep);o=a.clientY}function m(){a.unbind(window,"mousemove",j);a.unbind(window,"mouseup",m)}this.__truncationSuspended=false;d.superclass.call(this,f,b,e);var l=this,o;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"change",h);
30 | a.bind(this.__input,"blur",function(){h();l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())});a.bind(this.__input,"mousedown",function(b){a.bind(window,"mousemove",j);a.bind(window,"mouseup",m);o=b.clientY});a.bind(this.__input,"keydown",function(a){if(a.keyCode===13)l.__truncationSuspended=true,this.blur(),l.__truncationSuspended=false});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;c.extend(d.prototype,e.prototype,{updateDisplay:function(){var a=this.__input,
31 | b;if(this.__truncationSuspended)b=this.getValue();else{b=this.getValue();var c=Math.pow(10,this.__precision);b=Math.round(b*c)/c}a.value=b;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.NumberController,dat.dom.dom,dat.utils.common);
32 | dat.controllers.NumberControllerSlider=function(e,a,c,d,f){var b=function(d,c,f,e,l){function o(b){b.preventDefault();var d=a.getOffset(g.__background),c=a.getWidth(g.__background);g.setValue(g.__min+(g.__max-g.__min)*((b.clientX-d.left)/(d.left+c-d.left)));return false}function y(){a.unbind(window,"mousemove",o);a.unbind(window,"mouseup",y);g.__onFinishChange&&g.__onFinishChange.call(g,g.getValue())}b.superclass.call(this,d,c,{min:f,max:e,step:l});var g=this;this.__background=document.createElement("div");
33 | this.__foreground=document.createElement("div");a.bind(this.__background,"mousedown",function(b){a.bind(window,"mousemove",o);a.bind(window,"mouseup",y);o(b)});a.addClass(this.__background,"slider");a.addClass(this.__foreground,"slider-fg");this.updateDisplay();this.__background.appendChild(this.__foreground);this.domElement.appendChild(this.__background)};b.superclass=e;b.useDefaultStyles=function(){c.inject(f)};d.extend(b.prototype,e.prototype,{updateDisplay:function(){this.__foreground.style.width=
34 | (this.getValue()-this.__min)/(this.__max-this.__min)*100+"%";return b.superclass.prototype.updateDisplay.call(this)}});return b}(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,".slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}");
35 | dat.controllers.FunctionController=function(e,a,c){var d=function(c,b,e){d.superclass.call(this,c,b);var h=this;this.__button=document.createElement("div");this.__button.innerHTML=e===void 0?"Fire":e;a.bind(this.__button,"click",function(a){a.preventDefault();h.fire();return false});a.addClass(this.__button,"button");this.domElement.appendChild(this.__button)};d.superclass=e;c.extend(d.prototype,e.prototype,{fire:function(){this.__onChange&&this.__onChange.call(this);this.__onFinishChange&&this.__onFinishChange.call(this,
36 | this.getValue());this.getValue().call(this.object)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
37 | dat.controllers.BooleanController=function(e,a,c){var d=function(c,b){d.superclass.call(this,c,b);var e=this;this.__prev=this.getValue();this.__checkbox=document.createElement("input");this.__checkbox.setAttribute("type","checkbox");a.bind(this.__checkbox,"change",function(){e.setValue(!e.__prev)},false);this.domElement.appendChild(this.__checkbox);this.updateDisplay()};d.superclass=e;c.extend(d.prototype,e.prototype,{setValue:function(a){a=d.superclass.prototype.setValue.call(this,a);this.__onFinishChange&&
38 | this.__onFinishChange.call(this,this.getValue());this.__prev=this.getValue();return a},updateDisplay:function(){this.getValue()===true?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=true):this.__checkbox.checked=false;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
39 | dat.color.toString=function(e){return function(a){if(a.a==1||e.isUndefined(a.a)){for(a=a.hex.toString(16);a.length<6;)a="0"+a;return"#"+a}else return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}}(dat.utils.common);
40 | dat.color.interpret=function(e,a){var c,d,f=[{litmus:a.isString,conversions:{THREE_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return a===null?false:{space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}},write:e},SIX_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9]{6})$/i);return a===null?false:{space:"HEX",hex:parseInt("0x"+a[1].toString())}},write:e},CSS_RGB:{read:function(a){a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
41 | return a===null?false:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}},write:e},CSS_RGBA:{read:function(a){a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);return a===null?false:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}},write:e}}},{litmus:a.isNumber,conversions:{HEX:{read:function(a){return{space:"HEX",hex:a,conversionName:"HEX"}},write:function(a){return a.hex}}}},{litmus:a.isArray,conversions:{RGB_ARRAY:{read:function(a){return a.length!=
42 | 3?false:{space:"RGB",r:a[0],g:a[1],b:a[2]}},write:function(a){return[a.r,a.g,a.b]}},RGBA_ARRAY:{read:function(a){return a.length!=4?false:{space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}},write:function(a){return[a.r,a.g,a.b,a.a]}}}},{litmus:a.isObject,conversions:{RGBA_OBJ:{read:function(b){return a.isNumber(b.r)&&a.isNumber(b.g)&&a.isNumber(b.b)&&a.isNumber(b.a)?{space:"RGB",r:b.r,g:b.g,b:b.b,a:b.a}:false},write:function(a){return{r:a.r,g:a.g,b:a.b,a:a.a}}},RGB_OBJ:{read:function(b){return a.isNumber(b.r)&&
43 | a.isNumber(b.g)&&a.isNumber(b.b)?{space:"RGB",r:b.r,g:b.g,b:b.b}:false},write:function(a){return{r:a.r,g:a.g,b:a.b}}},HSVA_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)&&a.isNumber(b.a)?{space:"HSV",h:b.h,s:b.s,v:b.v,a:b.a}:false},write:function(a){return{h:a.h,s:a.s,v:a.v,a:a.a}}},HSV_OBJ:{read:function(b){return a.isNumber(b.h)&&a.isNumber(b.s)&&a.isNumber(b.v)?{space:"HSV",h:b.h,s:b.s,v:b.v}:false},write:function(a){return{h:a.h,s:a.s,v:a.v}}}}}];return function(){d=
44 | false;var b=arguments.length>1?a.toArray(arguments):arguments[0];a.each(f,function(e){if(e.litmus(b))return a.each(e.conversions,function(e,f){c=e.read(b);if(d===false&&c!==false)return d=c,c.conversionName=f,c.conversion=e,a.BREAK}),a.BREAK});return d}}(dat.color.toString,dat.utils.common);
45 | dat.GUI=dat.gui.GUI=function(e,a,c,d,f,b,n,h,j,m,l,o,y,g,i){function q(a,b,r,c){if(b[r]===void 0)throw Error("Object "+b+' has no property "'+r+'"');c.color?b=new l(b,r):(b=[b,r].concat(c.factoryArgs),b=d.apply(a,b));if(c.before instanceof f)c.before=c.before.__li;t(a,b);g.addClass(b.domElement,"c");r=document.createElement("span");g.addClass(r,"property-name");r.innerHTML=b.property;var e=document.createElement("div");e.appendChild(r);e.appendChild(b.domElement);c=s(a,e,c.before);g.addClass(c,k.CLASS_CONTROLLER_ROW);
46 | g.addClass(c,typeof b.getValue());p(a,c,b);a.__controllers.push(b);return b}function s(a,b,d){var c=document.createElement("li");b&&c.appendChild(b);d?a.__ul.insertBefore(c,params.before):a.__ul.appendChild(c);a.onResize();return c}function p(a,d,c){c.__li=d;c.__gui=a;i.extend(c,{options:function(b){if(arguments.length>1)return c.remove(),q(a,c.object,c.property,{before:c.__li.nextElementSibling,factoryArgs:[i.toArray(arguments)]});if(i.isArray(b)||i.isObject(b))return c.remove(),q(a,c.object,c.property,
47 | {before:c.__li.nextElementSibling,factoryArgs:[b]})},name:function(a){c.__li.firstElementChild.firstElementChild.innerHTML=a;return c},listen:function(){c.__gui.listen(c);return c},remove:function(){c.__gui.remove(c);return c}});if(c instanceof j){var e=new h(c.object,c.property,{min:c.__min,max:c.__max,step:c.__step});i.each(["updateDisplay","onChange","onFinishChange"],function(a){var b=c[a],H=e[a];c[a]=e[a]=function(){var a=Array.prototype.slice.call(arguments);b.apply(c,a);return H.apply(e,a)}});
48 | g.addClass(d,"has-slider");c.domElement.insertBefore(e.domElement,c.domElement.firstElementChild)}else if(c instanceof h){var f=function(b){return i.isNumber(c.__min)&&i.isNumber(c.__max)?(c.remove(),q(a,c.object,c.property,{before:c.__li.nextElementSibling,factoryArgs:[c.__min,c.__max,c.__step]})):b};c.min=i.compose(f,c.min);c.max=i.compose(f,c.max)}else if(c instanceof b)g.bind(d,"click",function(){g.fakeEvent(c.__checkbox,"click")}),g.bind(c.__checkbox,"click",function(a){a.stopPropagation()});
49 | else if(c instanceof n)g.bind(d,"click",function(){g.fakeEvent(c.__button,"click")}),g.bind(d,"mouseover",function(){g.addClass(c.__button,"hover")}),g.bind(d,"mouseout",function(){g.removeClass(c.__button,"hover")});else if(c instanceof l)g.addClass(d,"color"),c.updateDisplay=i.compose(function(a){d.style.borderLeftColor=c.__color.toString();return a},c.updateDisplay),c.updateDisplay();c.setValue=i.compose(function(b){a.getRoot().__preset_select&&c.isModified()&&B(a.getRoot(),true);return b},c.setValue)}
50 | function t(a,b){var c=a.getRoot(),d=c.__rememberedObjects.indexOf(b.object);if(d!=-1){var e=c.__rememberedObjectIndecesToControllers[d];e===void 0&&(e={},c.__rememberedObjectIndecesToControllers[d]=e);e[b.property]=b;if(c.load&&c.load.remembered){c=c.load.remembered;if(c[a.preset])c=c[a.preset];else if(c[w])c=c[w];else return;if(c[d]&&c[d][b.property]!==void 0)d=c[d][b.property],b.initialValue=d,b.setValue(d)}}}function I(a){var b=a.__save_row=document.createElement("li");g.addClass(a.domElement,
51 | "has-save");a.__ul.insertBefore(b,a.__ul.firstChild);g.addClass(b,"save-row");var c=document.createElement("span");c.innerHTML=" ";g.addClass(c,"button gears");var d=document.createElement("span");d.innerHTML="Save";g.addClass(d,"button");g.addClass(d,"save");var e=document.createElement("span");e.innerHTML="New";g.addClass(e,"button");g.addClass(e,"save-as");var f=document.createElement("span");f.innerHTML="Revert";g.addClass(f,"button");g.addClass(f,"revert");var m=a.__preset_select=document.createElement("select");
52 | a.load&&a.load.remembered?i.each(a.load.remembered,function(b,c){C(a,c,c==a.preset)}):C(a,w,false);g.bind(m,"change",function(){for(var b=0;b0){a.preset=this.preset;if(!a.remembered)a.remembered={};a.remembered[this.preset]=z(this)}a.folders={};i.each(this.__folders,function(b,
69 | c){a.folders[c]=b.getSaveObject()});return a},save:function(){if(!this.load.remembered)this.load.remembered={};this.load.remembered[this.preset]=z(this);B(this,false)},saveAs:function(a){if(!this.load.remembered)this.load.remembered={},this.load.remembered[w]=z(this,true);this.load.remembered[a]=z(this);this.preset=a;C(this,a,true)},revert:function(a){i.each(this.__controllers,function(b){this.getRoot().load.remembered?t(a||this.getRoot(),b):b.setValue(b.initialValue)},this);i.each(this.__folders,
70 | function(a){a.revert(a)});a||B(this.getRoot(),false)},listen:function(a){var b=this.__listening.length==0;this.__listening.push(a);b&&E(this.__listening)}});return k}(dat.utils.css,'