├── .gitignore ├── README.md ├── SketchIt ├── Insomnia.REST │ ├── README.md │ ├── SketchIt-App_Insomnia.json │ ├── Sketchit-App_Insomnia-ENV.json │ ├── env-preview.png │ └── insomnia-preview.png └── Revit.Addin │ ├── README.md │ ├── SketchIt.sln │ ├── SketchItApp │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SketchIt.bundle │ │ ├── Contents │ │ │ └── SketchIt.addin │ │ └── PackageContents.xml │ ├── SketchIt.cs │ ├── SketchIt.csproj │ ├── SketchItParams.cs │ ├── bundles │ │ └── SketchIt.zip │ └── packages.config │ └── reference_path.png ├── package-lock.json ├── package.json ├── server └── src │ ├── app_utils.js │ ├── forge_utils.js │ ├── main.js │ ├── ngrok_utils.js │ └── socket_utils.js ├── thumbnail.gif └── www ├── css └── style.css ├── elements ├── curve.js ├── element.js ├── floor.js └── wall.js ├── entry └── app.js ├── generated ├── .gitkeep ├── sketch_it_bundle.js.tmp-browserify-06042699962653919066 ├── sketch_it_bundle.js.tmp-browserify-35300449065229422274 └── sketch_it_bundle.js.tmp-browserify-67279445076799904157 ├── index.ejs ├── mathutils ├── angle_converter.js └── gl_matrix_wrapper.js ├── react ├── canvas.js ├── canvas_events.js ├── editor.js ├── editor_button.js ├── side_bar.js ├── sketch_it.js ├── thumbnail.js └── viewer.js ├── res ├── ceiling.png ├── column.png ├── component.png ├── door.png ├── favicon.png ├── floor.png ├── forge-logo.png ├── roof.png ├── wall.png └── window.png ├── store ├── action_creators.js ├── action_types.js ├── reducers.js └── store.js └── utils ├── array_utils.js ├── element_utils.js ├── redux_utils.js ├── request_utils.js └── transform_utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | .vscode 8 | .DS_Store 9 | /server/generated 10 | /www/generated 11 | *.dll 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | 19 | # Directory for instrumented libs generated by jscoverage/JSCover 20 | lib-cov 21 | 22 | # Coverage directory used by tools like istanbul 23 | coverage 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # Optional npm cache directory 48 | .npm 49 | 50 | # Optional eslint cache 51 | .eslintcache 52 | 53 | # Optional REPL history 54 | .node_repl_history 55 | 56 | # Output of 'npm pack' 57 | *.tgz 58 | 59 | # Yarn Integrity file 60 | .yarn-integrity 61 | 62 | # dotenv environment variables file 63 | .env 64 | 65 | # next.js build output 66 | .next 67 | 68 | 69 | ## Ignore Visual Studio temporary files, build results, and 70 | ## files generated by popular Visual Studio add-ons. 71 | ## 72 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 73 | 74 | # User-specific files 75 | *.suo 76 | *.user 77 | *.userosscache 78 | *.sln.docstates 79 | 80 | # User-specific files (MonoDevelop/Xamarin Studio) 81 | *.userprefs 82 | 83 | # Build results 84 | [Dd]ebug/ 85 | [Dd]ebugPublic/ 86 | [Rr]elease/ 87 | [Rr]eleases/ 88 | x64/ 89 | x86/ 90 | bld/ 91 | [Bb]in/ 92 | [Oo]bj/ 93 | [Ll]og/ 94 | 95 | # Visual Studio 2015/2017 cache/options directory 96 | .vs/ 97 | # Uncomment if you have tasks that create the project's static files in wwwroot 98 | #wwwroot/ 99 | 100 | # Visual Studio 2017 auto generated files 101 | Generated\ Files/ 102 | 103 | # MSTest test Results 104 | [Tt]est[Rr]esult*/ 105 | [Bb]uild[Ll]og.* 106 | 107 | # NUNIT 108 | *.VisualState.xml 109 | TestResult.xml 110 | 111 | # Build Results of an ATL Project 112 | [Dd]ebugPS/ 113 | [Rr]eleasePS/ 114 | dlldata.c 115 | 116 | # Benchmark Results 117 | BenchmarkDotNet.Artifacts/ 118 | 119 | # .NET Core 120 | project.lock.json 121 | project.fragment.lock.json 122 | artifacts/ 123 | **/Properties/launchSettings.json 124 | 125 | # StyleCop 126 | StyleCopReport.xml 127 | 128 | # Files built by Visual Studio 129 | *_i.c 130 | *_p.c 131 | *_i.h 132 | *.ilk 133 | *.meta 134 | *.obj 135 | *.iobj 136 | *.pch 137 | *.pdb 138 | *.ipdb 139 | *.pgc 140 | *.pgd 141 | *.rsp 142 | *.sbr 143 | *.tlb 144 | *.tli 145 | *.tlh 146 | *.tmp 147 | *.tmp_proj 148 | *.log 149 | *.vspscc 150 | *.vssscc 151 | .builds 152 | *.pidb 153 | *.svclog 154 | *.scc 155 | 156 | # Chutzpah Test files 157 | _Chutzpah* 158 | 159 | # Visual C++ cache files 160 | ipch/ 161 | *.aps 162 | *.ncb 163 | *.opendb 164 | *.opensdf 165 | *.sdf 166 | *.cachefile 167 | *.VC.db 168 | *.VC.VC.opendb 169 | 170 | # Visual Studio profiler 171 | *.psess 172 | *.vsp 173 | *.vspx 174 | *.sap 175 | 176 | # Visual Studio Trace Files 177 | *.e2e 178 | 179 | # TFS 2012 Local Workspace 180 | $tf/ 181 | 182 | # Guidance Automation Toolkit 183 | *.gpState 184 | 185 | # ReSharper is a .NET coding add-in 186 | _ReSharper*/ 187 | *.[Rr]e[Ss]harper 188 | *.DotSettings.user 189 | 190 | # JustCode is a .NET coding add-in 191 | .JustCode 192 | 193 | # TeamCity is a build add-in 194 | _TeamCity* 195 | 196 | # DotCover is a Code Coverage Tool 197 | *.dotCover 198 | 199 | # AxoCover is a Code Coverage Tool 200 | .axoCover/* 201 | !.axoCover/settings.json 202 | 203 | # Visual Studio code coverage results 204 | *.coverage 205 | *.coveragexml 206 | 207 | # NCrunch 208 | _NCrunch_* 209 | .*crunch*.local.xml 210 | nCrunchTemp_* 211 | 212 | # MightyMoose 213 | *.mm.* 214 | AutoTest.Net/ 215 | 216 | # Web workbench (sass) 217 | .sass-cache/ 218 | 219 | # Installshield output folder 220 | [Ee]xpress/ 221 | 222 | # DocProject is a documentation generator add-in 223 | DocProject/buildhelp/ 224 | DocProject/Help/*.HxT 225 | DocProject/Help/*.HxC 226 | DocProject/Help/*.hhc 227 | DocProject/Help/*.hhk 228 | DocProject/Help/*.hhp 229 | DocProject/Help/Html2 230 | DocProject/Help/html 231 | 232 | # Click-Once directory 233 | publish/ 234 | 235 | # Publish Web Output 236 | *.[Pp]ublish.xml 237 | *.azurePubxml 238 | # Note: Comment the next line if you want to checkin your web deploy settings, 239 | # but database connection strings (with potential passwords) will be unencrypted 240 | *.pubxml 241 | *.publishproj 242 | 243 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 244 | # checkin your Azure Web App publish settings, but sensitive information contained 245 | # in these scripts will be unencrypted 246 | PublishScripts/ 247 | 248 | # NuGet Packages 249 | *.nupkg 250 | # The packages folder can be ignored because of Package Restore 251 | **/[Pp]ackages/* 252 | # except build/, which is used as an MSBuild target. 253 | !**/[Pp]ackages/build/ 254 | # Uncomment if necessary however generally it will be regenerated when needed 255 | #!**/[Pp]ackages/repositories.config 256 | # NuGet v3's project.json files produces more ignorable files 257 | *.nuget.props 258 | *.nuget.targets 259 | 260 | # Microsoft Azure Build Output 261 | csx/ 262 | *.build.csdef 263 | 264 | # Microsoft Azure Emulator 265 | ecf/ 266 | rcf/ 267 | 268 | # Windows Store app package directories and files 269 | AppPackages/ 270 | BundleArtifacts/ 271 | Package.StoreAssociation.xml 272 | _pkginfo.txt 273 | *.appx 274 | 275 | # Visual Studio cache files 276 | # files ending in .cache can be ignored 277 | *.[Cc]ache 278 | # but keep track of directories ending in .cache 279 | !*.[Cc]ache/ 280 | 281 | # Others 282 | ClientBin/ 283 | ~$* 284 | *~ 285 | *.dbmdl 286 | *.dbproj.schemaview 287 | *.jfm 288 | *.pfx 289 | *.publishsettings 290 | orleans.codegen.cs 291 | 292 | # Including strong name files can present a security risk 293 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 294 | #*.snk 295 | 296 | # Since there are multiple workflows, uncomment next line to ignore bower_components 297 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 298 | #bower_components/ 299 | 300 | # RIA/Silverlight projects 301 | Generated_Code/ 302 | 303 | # Backup & report files from converting an old project file 304 | # to a newer Visual Studio version. Backup files are not needed, 305 | # because we have git ;-) 306 | _UpgradeReport_Files/ 307 | Backup*/ 308 | UpgradeLog*.XML 309 | UpgradeLog*.htm 310 | ServiceFabricBackup/ 311 | *.rptproj.bak 312 | 313 | # SQL Server files 314 | *.mdf 315 | *.ldf 316 | *.ndf 317 | 318 | # Business Intelligence projects 319 | *.rdl.data 320 | *.bim.layout 321 | *.bim_*.settings 322 | *.rptproj.rsuser 323 | 324 | # Microsoft Fakes 325 | FakesAssemblies/ 326 | 327 | # GhostDoc plugin setting file 328 | *.GhostDoc.xml 329 | 330 | # Node.js Tools for Visual Studio 331 | .ntvs_analysis.dat 332 | node_modules/ 333 | 334 | # Visual Studio 6 build log 335 | *.plg 336 | 337 | # Visual Studio 6 workspace options file 338 | *.opt 339 | 340 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 341 | *.vbw 342 | 343 | # Visual Studio LightSwitch build output 344 | **/*.HTMLClient/GeneratedArtifacts 345 | **/*.DesktopClient/GeneratedArtifacts 346 | **/*.DesktopClient/ModelManifest.xml 347 | **/*.Server/GeneratedArtifacts 348 | **/*.Server/ModelManifest.xml 349 | _Pvt_Extensions 350 | 351 | # Paket dependency manager 352 | .paket/paket.exe 353 | paket-files/ 354 | 355 | # FAKE - F# Make 356 | .fake/ 357 | 358 | # JetBrains Rider 359 | .idea/ 360 | *.sln.iml 361 | 362 | # CodeRush 363 | .cr/ 364 | 365 | # Python Tools for Visual Studio (PTVS) 366 | __pycache__/ 367 | *.pyc 368 | 369 | # Cake - Uncomment if you are using it 370 | # tools/** 371 | # !tools/packages.config 372 | 373 | # Tabs Studio 374 | *.tss 375 | 376 | # Telerik's JustMock configuration file 377 | *.jmconfig 378 | 379 | # BizTalk build output 380 | *.btp.cs 381 | *.btm.cs 382 | *.odx.cs 383 | *.xsd.cs 384 | 385 | # OpenCover UI analysis results 386 | OpenCover/ 387 | 388 | # Azure Stream Analytics local run output 389 | ASALocalRun/ 390 | 391 | # MSBuild Binary and Structured Log 392 | *.binlog 393 | 394 | # NVidia Nsight GPU debugger configuration file 395 | *.nvuser 396 | 397 | # MFractors (Xamarin productivity tool) working folder 398 | .mfractor/ 399 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sketch on the browser and generate Revit models 2 | 3 | [![Node.js](https://img.shields.io/badge/Node.js-8.0-blue.svg)](https://nodejs.org/) 4 | [![npm](https://img.shields.io/badge/npm-4.0-blue.svg)](https://www.npmjs.com/) 5 | ![Platforms](https://img.shields.io/badge/Web-Windows%20%7C%20MacOS%20%7C%20Linux-lightgray.svg) 6 | [![Design-Automation](https://img.shields.io/badge/Design%20Automation-v3-green.svg)](http://forge.autodesk.com/) 7 | 8 | [![Viewer](https://img.shields.io/badge/Viewer-v6.5-green.svg)](http://forge.autodesk.com/) 9 | 10 | 11 | ![Windows](https://img.shields.io/badge/Plugins-Windows-lightgrey.svg) 12 | ![.NET](https://img.shields.io/badge/.NET%20Framework-4.7-blue.svg) 13 | [![Revit-2019](https://img.shields.io/badge/Revit-2019-lightgrey.svg)](http://autodesk.com/revit) 14 | 15 | 16 | ![Advanced](https://img.shields.io/badge/Level-Advanced-red.svg) 17 | [![MIT](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT) 18 | 19 | # Description 20 | 21 | This NodeJS app demonstrates an end to end use case for external developers using Design Automation for Revit. In addition to using Design Automation for Revit REST APIs, this app also leverages other Autodesk Forge services like Data Management API (OSS), Viewer API and Model Derivative services. 22 | 23 | The sketcher is built using Redux with React and makes use of Flux architecture extensively. 24 | 25 | # How does it work? 26 | ![thumbnail](thumbnail.gif) 27 | 28 | # Main Parts of The Work 29 | 1. Create a Revit Plugin to be used within AppBundle of Design Automation for Revit. Please check [PlugIn](./SketchIt/Revit.Addin/README.md) 30 | 2. Create your App, upload the AppBundle, define your Activity and test the workitem with [Insomnia Rest](./SketchIt/Insomnia.REST/README.md) workflow. 31 | 32 | 3. Create the Web App to call the workitem. 33 | 34 | # Web App Setup 35 | 36 | ## Prerequisites 37 | 38 | For using this sample, you need an Autodesk developer credentials. Visit the [Forge Developer Portal](https://developer.autodesk.com), sign up for an account, then [create an app](https://developer.autodesk.com/myapps/create). For this new app, use `http://localhost:3000/api/forge/callback/oauth` as Callback URL, although is not used on 2-legged flow. Finally take note of the **Client ID** and **Client Secret**. 39 | 40 | 1. **Forge Account**: Learn how to create a Forge Account, activate subscription and create an app at [this tutorial](http://learnforge.autodesk.io/#/account/). 41 | 2. **Visual Code**: Visual Code (Windows or MacOS). 42 | 3. **ngrok**: Routing tool, [download here](https://ngrok.com/) 43 | 4. **Revit 2019**: required to compile changes into the plugin 44 | 5. **JavaScript ES6** syntax for server-side. 45 | 6. **JavaScript** basic knowledge with **jQuery** 46 | 7. **React & Redux & Flux** framework architecture 47 | 48 | ## Running locally 49 | 50 | Install [NodeJS](https://nodejs.org), version 8 or newer. 51 | 52 | Clone this project or download it (this `nodejs` branch only). It's recommended to install [GitHub desktop](https://desktop.github.com/). To clone it via command line, use the following (**Terminal** on MacOSX/Linux, **Git Shell** on Windows): 53 | 54 | git clone https://github.com/autodesk-forge/design.automation-nodejs-sketchIt.git 55 | 56 | To run it, install the required packages, set the enviroment variables with your Client ID, Secret, Bucket Key and Nickname value and finally start it. Via command line, navigate to the folder where this repository was cloned and use the following: 57 | 58 | Mac OSX/Linux (Terminal) 59 | 60 | npm install 61 | export FORGE_CLIENT_ID=<> 62 | export FORGE_CLIENT_SECRET=<> 63 | export FORGE_BUCKET_KEY=<> 64 | export FORGE_ACTIVITY_ID=<> 65 | export FORGE_WEBHOOK_URL=<> 66 | npm start 67 | 68 | Windows (use **Node.js command line** from Start menu) 69 | 70 | npm install 71 | set FORGE_CLIENT_ID=<> 72 | set FORGE_CLIENT_SECRET=<> 73 | set FORGE_BUCKET_KEY=<> 74 | set FORGE_ACTIVITY_ID=<> 75 | set FORGE_WEBHOOK_URL=<> 76 | npm start 77 | 78 | 79 | ### Start the app 80 | 81 | Open the browser: [http://localhost:3000](http://localhost:3000). Select the element to create (top-right buttons). Click on `Generate Revit Model`, wait until is ready to view. 82 | 83 | 84 | ## Further Reading 85 | 86 | Documentation: 87 | 88 | - [Design Automation API](https://forge.autodesk.com/en/docs/design-automation/v3/developers_guide/overview/) 89 | - [Data Management API](https://developer.autodesk.com/en/docs/data/v2/overview/) 90 | 91 | Desktop APIs: 92 | 93 | - [Revit](https://knowledge.autodesk.com/support/revit-products/learn-explore/caas/simplecontent/content/my-first-revit-plug-overview.html) 94 | 95 | ## License 96 | 97 | This sample is licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT). Please see the [LICENSE](LICENSE) file for full details. 98 | 99 | ## Written by 100 | 101 | 102 | Jaime Rosales D. [![Twitter Follow](https://img.shields.io/twitter/follow/afrojme.svg?style=social&label=Follow)](https://twitter.com/AfroJme) 103 | 104 | [Forge Partner Development](http://forge.autodesk.com) 105 | -------------------------------------------------------------------------------- /SketchIt/Insomnia.REST/README.md: -------------------------------------------------------------------------------- 1 | # Create App, Define Activity, Call the WorkItem 2 | 3 | ## Description 4 | Insomnia.REST workflow to create App, define activity, and call the WorkItem. 5 | 6 | ## Setup 7 | `Before start with Design Automaiton workflow, I strongly recommend you to read throught all the details at` [Design Automation for Revit Documenation](https://forge.autodesk.com/en/docs/design-automation/v3),` and check the following steps if you already have basic understanding.` 8 | 9 | 1. Download or update Insomnia.REST from [here](https://insomnia.rest/download). 10 | 11 | 2. Create a Forge App. If you have already created a Forge App then you can skip this and proceed to the next step. 12 | 13 | 3. From your local clone of the repository, import our `Insomnia data` [Sketchit-App_Insomnia](./SketchIt-App_Insomnia.json) into the Insomnia REST application. You can find more details about it [here](https://support.insomnia.rest/article/52-importing-and-exporting-data) 14 | 15 | ![thumbnail](./insomnia-preview.png) 16 | 17 | 4. After the import to Insomnia, we can see there is a predefined Enviorment called [SketchIt-RevitIO-Env](Sketchit-App_Insomnia-ENV.json) 18 | which will need your input for the variable values (client ID, client Secret...) This will make the process smoother and faster to use. You can find more details about it [here](https://support.insomnia.rest/article/18-environment-variables) 19 | 20 | ![thumbnail](./env-preview.png) 21 | 22 | 5. Select the environment and enter your [Forge App's](https://developer.autodesk.com/myapps) `Client ID` and `Client Secret`. This is used for authentication. In the environment variables give your app an easy to manage unique nickname. 23 | 24 | 6. Compile and package the sample applications as noted [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step4-publish-appbundle/). You will need this to upload the app to Design Automation. Alternatively you may also download the packages from [SketchIt.zip](../Revit.Addin/SketchItApp/bundles/SketchIt.zip). 25 | 26 | 7. Create a nickname for your Forge App. 27 | 28 | 8. Publish your Design Automation appbundle. 29 | 30 | Create an `appbundle` zip package from the build outputs and publish the `appbundle` to Design Automation. 31 | 32 | The `JSON` in your appbundle POST should look like this: 33 | ```json 34 | { 35 | "id": "SketchItApp", 36 | "engine": "Autodesk.Revit+2019", 37 | "description": "SketchIt appbundle based on Revit 2019" 38 | } 39 | ``` 40 | Notes: 41 | * `engine` = `Autodesk.Revit+2019` - A list of engine versions can be found [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step4-publish-appbundle/#engine-version-aliases). 42 | 43 | After you upload the `appbundle` zip package, you should create an alias for this appbundle. The `JSON` in the POST should look like this: 44 | ```json 45 | { 46 | "version": 1, 47 | "id": "test" 48 | } 49 | ``` 50 | 51 | > **The instructions for these steps and more about `appbundle` are [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step4-publish-appbundle/)**. 52 | 53 | 9. Publish your Design Automation activity. 54 | 55 | Define an `activity` to run against the `appbundle`. 56 | 57 | The `JSON` that accompanies the `activity` POST will look like this: 58 | 59 | ```json 60 | { 61 | "id": "SketchItActivity", 62 | "commandLine": [ "$(engine.path)\\\\revitcoreconsole.exe /al $(appbundles[SketchItApp].path)" ], 63 | "parameters": { 64 | "sketchItInput": { 65 | "zip": false, 66 | "ondemand": false, 67 | "verb": "get", 68 | "description": "SketchIt input parameters", 69 | "required": true, 70 | "localName": "SketchItInput.json" 71 | }, 72 | "result": { 73 | "zip": false, 74 | "ondemand": false, 75 | "verb": "put", 76 | "description": "Results", 77 | "required": true, 78 | "localName": "sketchIt.rvt" 79 | } 80 | }, 81 | "engine": "Autodesk.Revit+2019", 82 | "appbundles": [ "YourNickname.SketchItApp+test" ], 83 | "description": "Creates walls and floors from an input JSON file." 84 | } 85 | ``` 86 | Notes: 87 | * `engine` = `Autodesk.Revit+2019` - A list of engine versions can be found [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step4-publish-appbundle/#engine-version-aliases). 88 | * `YourNickname` - The owner of appbundle `SketchItApp`. More information can be found [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step3-create-nickname/). 89 | 90 | Then you should create an alias for this activity. The `JSON` in the POST should look like this: 91 | ```json 92 | { 93 | "version": 1, 94 | "id": "test" 95 | } 96 | ``` 97 | 98 | > **The instructions for these steps and more about `activity` are [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step5-publish-activity/)**. 99 | 100 | 10. Prepare your input and output url. 101 | 102 | 11. Post your Design Automation workitem. 103 | 104 | Now POST a `workitem` against the `activity` to run a job on your `appbundle`. 105 | 106 | The `JSON` that accompanies the `workitem` POST will look like this: 107 | 108 | ```json 109 | { 110 | "activityId": "YourNickname.SketchItActivity+test", 111 | "arguments": { 112 | "sketchItInput": { 113 | "url": "data:application/json,{ 'walls': [ {'start': { 'x': -100, 'y': 100, 'z': 0.0}, 'end': { 'x': 100, 'y': 100, 'z': 0.0}}, {'start': { 'x': -100, 'y': 100, 'z': 0.0}, 'end': { 'x': 100, 'y': 100, 'z': 0.0}}, {'start': { 'x': 100, 'y': 100, 'z': 0.0}, 'end': { 'x': 100, 'y': -100, 'z': 0.0}}, {'start': { 'x': 100, 'y': -100, 'z': 0.0}, 'end': { 'x': -100, 'y': -100, 'z': 0.0}}, {'start': { 'x': -100, 'y': -100, 'z': 0.0}, 'end': { 'x': -100, 'y': 100, 'z': 0.0}}, {'start': { 'x': -500, 'y': -300, 'z': 0.0}, 'end': { 'x': -300, 'y': -300, 'z': 0.0}}, {'start': { 'x': -300, 'y': -300, 'z': 0.0}, 'end': { 'x': -300, 'y': -500, 'z': 0.0}}, {'start': { 'x': -300, 'y': -500, 'z': 0.0}, 'end': { 'x': -500, 'y': -500, 'z': 0.0}}, {'start': { 'x': -500, 'y': -500, 'z': 0.0}, 'end': { 'x': -500, 'y': -300, 'z': 0.0}}],'floors' : [ [{'x': -100, 'y': 100, 'z':0.0}, {'x': 100, 'y': 100, 'z': 0.0}, {'x': 100, 'y': -100, 'z': 0.0}, {'x': -100, 'y': -100, 'z': 0.0}], [{'x': -500, 'y': -300, 'z':0.0}, {'x': -300, 'y': -300, 'z': 0.0}, {'x': -300, 'y': -500, 'z': 0.0}, {'x': -500, 'y': -500, 'z': 0.0}] ]}" 114 | }, 115 | "result": { 116 | "verb": "put", 117 | "url": "https://myWebsite/signed/url/to/sketchIt.rvt" 118 | } 119 | } 120 | } 121 | ``` 122 | Notes: 123 | * `YourNickname` - The owner of activity `SketchItActivity`. More information can be found [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step3-create-nickname/). 124 | 125 | > **The instructions for this step and more about `workitem` are [here](https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/step6-post-workitem/)**. 126 | 127 | 128 | 129 | 130 | ## Usage 131 | 132 | These Insomnia samples will allow you to easily issue REST API calls without using cumbersome cURL commands. 133 | 134 | Note that you will have to carefully read through the requests - `DELETE`-ing an `app` or `activity` will delete all its associated versions! 135 | 136 | Note that for all `workitems` kindly provide signed URL for the expected output file. Else the `workitem` post will result with `failedUpload`. 137 | 138 | REST API documentation on Design Automation V3 can be found [here](https://forge.autodesk.com/en/docs/design-automation/v3/reference/http/). 139 | 140 | ## Written by 141 | 142 | Jaime Rosales D. [![Twitter Follow](https://img.shields.io/twitter/follow/afrojme.svg?style=social&label=Follow)](https://twitter.com/AfroJme) 143 | 144 | [Forge Partner Development](http://forge.autodesk.com) -------------------------------------------------------------------------------- /SketchIt/Insomnia.REST/SketchIt-App_Insomnia.json: -------------------------------------------------------------------------------- 1 | { 2 | "_type": "export", 3 | "__export_format": 3, 4 | "__export_date": "2019-03-06T22:24:30.310Z", 5 | "__export_source": "insomnia.desktop.app:v6.3.2", 6 | "resources": [ 7 | { 8 | "_id": "wrk_d7f919c34c82455c93305b6280d8c1b4", 9 | "created": 1551907819414, 10 | "description": "", 11 | "modified": 1551907819414, 12 | "name": "SketchIt App", 13 | "parentId": null, 14 | "_type": "workspace" 15 | }, 16 | { 17 | "_id": "env_230605c04fd747a6926c1728ad93c27a", 18 | "color": null, 19 | "created": 1551907820035, 20 | "data": {}, 21 | "isPrivate": false, 22 | "metaSortKey": 1551907820035, 23 | "modified": 1551910901324, 24 | "name": "New Environment", 25 | "parentId": "wrk_d7f919c34c82455c93305b6280d8c1b4", 26 | "_type": "environment" 27 | }, 28 | { 29 | "_id": "jar_c055d6bcc9df4b6dae4c0d2d6f11e802", 30 | "cookies": [ 31 | { 32 | "creation": "2019-03-06T21:54:23.806Z", 33 | "domain": "developer.api.autodesk.com", 34 | "hostOnly": true, 35 | "httpOnly": true, 36 | "id": "5351723910900108", 37 | "key": "PF", 38 | "lastAccessed": "2019-03-06T21:54:23.806Z", 39 | "path": "/", 40 | "secure": true, 41 | "value": "An4JvqRJdSH7LjShNyrARU" 42 | } 43 | ], 44 | "created": 1551907820038, 45 | "modified": 1551909263811, 46 | "name": "Default Jar", 47 | "parentId": "wrk_d7f919c34c82455c93305b6280d8c1b4", 48 | "_type": "cookie_jar" 49 | }, 50 | { 51 | "_id": "fld_6685d58f7c444080abdc6f59919b26f5", 52 | "created": 1551908186520, 53 | "description": "", 54 | "environment": {}, 55 | "metaSortKey": -1551908186520, 56 | "modified": 1551908204384, 57 | "name": "RevitIO.SketchIt", 58 | "parentId": "wrk_d7f919c34c82455c93305b6280d8c1b4", 59 | "_type": "request_group" 60 | }, 61 | { 62 | "_id": "env_6951f68d1e4446018e757e572a8e9107", 63 | "color": "#3458cb", 64 | "created": 1551910848288, 65 | "data": { 66 | "activityAlias": "dev", 67 | "activityName": "", 68 | "appBundleAlias": "dev", 69 | "appBundleFormDataCredential": "", 70 | "appBundleFormDataDate": "", 71 | "appBundleFormDataKey": "", 72 | "appBundleFormDataPolicy": "", 73 | "appBundleFormDataSignature": "", 74 | "appBundleFormDataToken": "", 75 | "appBundleFormRedirect": "", 76 | "appBundleName": "SketchItAppInsomnia", 77 | "appBundleUrl": "", 78 | "baseUrl": "https://developer.api.autodesk.com", 79 | "client_id": "", 80 | "client_secret": "", 81 | "dasApiRoot": "https://developer.api.autodesk.com/da/us-east/v3", 82 | "dasApiToken": "", 83 | "dasNickName": "", 84 | "workitemId": "" 85 | }, 86 | "isPrivate": false, 87 | "metaSortKey": 1551910848288, 88 | "modified": 1551910946824, 89 | "name": "SketchIt-RevitIO-Env", 90 | "parentId": "env_230605c04fd747a6926c1728ad93c27a", 91 | "_type": "environment" 92 | }, 93 | { 94 | "_id": "req_3ff08202f8684c0bac0eab483e679300", 95 | "authentication": {}, 96 | "body": {}, 97 | "created": 1551908186454, 98 | "description": "", 99 | "headers": [ 100 | { 101 | "name": "Content-Type", 102 | "value": "application/json" 103 | }, 104 | { 105 | "name": "Authorization", 106 | "value": "Bearer {{dasApiToken}}" 107 | } 108 | ], 109 | "isPrivate": false, 110 | "metaSortKey": -1551908186454, 111 | "method": "DELETE", 112 | "modified": 1551908186454, 113 | "name": "Delete activity", 114 | "parameters": [], 115 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 116 | "settingDisableRenderRequestBody": false, 117 | "settingEncodeUrl": true, 118 | "settingMaxTimelineDataSize": 1000, 119 | "settingRebuildPath": true, 120 | "settingSendCookies": true, 121 | "settingStoreCookies": true, 122 | "url": "{{dasApiRoot}}/activities/{{activityName}}", 123 | "_type": "request" 124 | }, 125 | { 126 | "_id": "req_4f396413f73a4b4ebd4a5208c6234248", 127 | "authentication": {}, 128 | "body": {}, 129 | "created": 1551908186461, 130 | "description": "", 131 | "headers": [ 132 | { 133 | "name": "Content-Type", 134 | "value": "application/json" 135 | }, 136 | { 137 | "name": "Authorization", 138 | "value": "Bearer {{dasApiToken}}" 139 | } 140 | ], 141 | "isPrivate": false, 142 | "metaSortKey": -1551908186461, 143 | "method": "DELETE", 144 | "modified": 1551908186461, 145 | "name": "Delete app bundle", 146 | "parameters": [], 147 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 148 | "settingDisableRenderRequestBody": false, 149 | "settingEncodeUrl": true, 150 | "settingMaxTimelineDataSize": 1000, 151 | "settingRebuildPath": true, 152 | "settingSendCookies": true, 153 | "settingStoreCookies": true, 154 | "url": "{{dasApiRoot}}/appbundles/{{appBundleName}}", 155 | "_type": "request" 156 | }, 157 | { 158 | "_id": "req_496a68fcb4ae4de0a93c8d03ac638c2a", 159 | "authentication": {}, 160 | "body": {}, 161 | "created": 1551908186466, 162 | "description": "", 163 | "headers": [ 164 | { 165 | "name": "", 166 | "value": "" 167 | }, 168 | { 169 | "name": "Authorization", 170 | "value": "Bearer {{dasApiToken}}" 171 | } 172 | ], 173 | "isPrivate": false, 174 | "metaSortKey": -1551908186466, 175 | "method": "GET", 176 | "modified": 1551908186466, 177 | "name": "Get list of activities", 178 | "parameters": [], 179 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 180 | "settingDisableRenderRequestBody": false, 181 | "settingEncodeUrl": true, 182 | "settingMaxTimelineDataSize": 1000, 183 | "settingRebuildPath": true, 184 | "settingSendCookies": true, 185 | "settingStoreCookies": true, 186 | "url": "{{dasApiRoot}}/activities", 187 | "_type": "request" 188 | }, 189 | { 190 | "_id": "req_95c50c3a577f42f69d02bbf06554ecfc", 191 | "authentication": {}, 192 | "body": {}, 193 | "created": 1551908186470, 194 | "description": "", 195 | "headers": [ 196 | { 197 | "name": "", 198 | "value": "" 199 | }, 200 | { 201 | "name": "Authorization", 202 | "value": "Bearer {{dasApiToken}}" 203 | } 204 | ], 205 | "isPrivate": false, 206 | "metaSortKey": -1551908186470, 207 | "method": "GET", 208 | "modified": 1551908186470, 209 | "name": "Get list of appbundles", 210 | "parameters": [], 211 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 212 | "settingDisableRenderRequestBody": false, 213 | "settingEncodeUrl": true, 214 | "settingMaxTimelineDataSize": 1000, 215 | "settingRebuildPath": true, 216 | "settingSendCookies": true, 217 | "settingStoreCookies": true, 218 | "url": "{{dasApiRoot}}/appbundles", 219 | "_type": "request" 220 | }, 221 | { 222 | "_id": "req_71478f2ebdf64e769e003692bb34819b", 223 | "authentication": {}, 224 | "body": {}, 225 | "created": 1551908186476, 226 | "description": "", 227 | "headers": [ 228 | { 229 | "name": "Content-Type", 230 | "value": "application/json" 231 | }, 232 | { 233 | "name": "Authorization", 234 | "value": "Bearer {{dasApiToken}}" 235 | } 236 | ], 237 | "isPrivate": false, 238 | "metaSortKey": -1551908186476, 239 | "method": "GET", 240 | "modified": 1551908186476, 241 | "name": "07-Get Workitem status", 242 | "parameters": [], 243 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 244 | "settingDisableRenderRequestBody": false, 245 | "settingEncodeUrl": true, 246 | "settingMaxTimelineDataSize": 1000, 247 | "settingRebuildPath": true, 248 | "settingSendCookies": true, 249 | "settingStoreCookies": true, 250 | "url": "{{dasApiRoot}}/workitems/{{workitemId}}", 251 | "_type": "request" 252 | }, 253 | { 254 | "_id": "req_791ada76960642d0b0bead5d58594ad0", 255 | "authentication": {}, 256 | "body": { 257 | "mimeType": "", 258 | "text": "{\n \"activityId\": \"{{dasNickName}}.{{activityName}}+{{activityAlias}}\",\n \"arguments\": {\n \"sketchItInput\": {\n \"url\": \"data:application/json,{ 'walls': [ {'start': { 'x': -100, 'y': 100, 'z': 0.0}, 'end': { 'x': 100, 'y': 100, 'z': 0.0}}, {'start': { 'x': -100, 'y': 100, 'z': 0.0}, 'end': { 'x': 100, 'y': 100, 'z': 0.0}}, {'start': { 'x': 100, 'y': 100, 'z': 0.0}, 'end': { 'x': 100, 'y': -100, 'z': 0.0}}, {'start': { 'x': 100, 'y': -100, 'z': 0.0}, 'end': { 'x': -100, 'y': -100, 'z': 0.0}}, {'start': { 'x': -100, 'y': -100, 'z': 0.0}, 'end': { 'x': -100, 'y': 100, 'z': 0.0}}, {'start': { 'x': -500, 'y': -300, 'z': 0.0}, 'end': { 'x': -300, 'y': -300, 'z': 0.0}}, {'start': { 'x': -300, 'y': -300, 'z': 0.0}, 'end': { 'x': -300, 'y': -500, 'z': 0.0}}, {'start': { 'x': -300, 'y': -500, 'z': 0.0}, 'end': { 'x': -500, 'y': -500, 'z': 0.0}}, {'start': { 'x': -500, 'y': -500, 'z': 0.0}, 'end': { 'x': -500, 'y': -300, 'z': 0.0}}],'floors' : [ [{'x': -100, 'y': 100, 'z':0.0}, {'x': 100, 'y': 100, 'z': 0.0}, {'x': 100, 'y': -100, 'z': 0.0}, {'x': -100, 'y': -100, 'z': 0.0}], [{'x': -500, 'y': -300, 'z':0.0}, {'x': -300, 'y': -300, 'z': 0.0}, {'x': -300, 'y': -500, 'z': 0.0}, {'x': -500, 'y': -500, 'z': 0.0}] ]}\"\n },\n \"result\": {\n \"verb\": \"put\",\n \"url\": \"https://myWebsite/signed/url/to/sketchIt.rvt\"\n }\n }\n}\n" 259 | }, 260 | "created": 1551908186480, 261 | "description": "", 262 | "headers": [ 263 | { 264 | "id": "pair_f1731434cce5406287b982430465eb48", 265 | "name": "Content-Type", 266 | "value": "application/json" 267 | }, 268 | { 269 | "id": "pair_072cec84f0134e61b67399ec7f88ca21", 270 | "name": "Authorization", 271 | "value": "Bearer {{dasApiToken}}" 272 | } 273 | ], 274 | "isPrivate": false, 275 | "metaSortKey": -1551908186480, 276 | "method": "POST", 277 | "modified": 1551909942563, 278 | "name": "06-Send Workitem", 279 | "parameters": [], 280 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 281 | "settingDisableRenderRequestBody": false, 282 | "settingEncodeUrl": true, 283 | "settingMaxTimelineDataSize": 1000, 284 | "settingRebuildPath": true, 285 | "settingSendCookies": true, 286 | "settingStoreCookies": true, 287 | "url": "{{dasApiRoot}}/workitems", 288 | "_type": "request" 289 | }, 290 | { 291 | "_id": "req_05e7e9e17d98434a8bb5e175a7ee1ff1", 292 | "authentication": {}, 293 | "body": { 294 | "mimeType": "", 295 | "text": "{\n \"id\": \"{{activityAlias}}\",\n \"version\": 1\n}" 296 | }, 297 | "created": 1551908186485, 298 | "description": "", 299 | "headers": [ 300 | { 301 | "id": "pair_65cad6e40a5f426a9ad569a44e87d595", 302 | "name": "Content-Type", 303 | "value": "application/json" 304 | }, 305 | { 306 | "id": "pair_9dd08bd1a6be4aefaacd3f6bf56762ad", 307 | "name": "Authorization", 308 | "value": "Bearer {{dasApiToken}}" 309 | } 310 | ], 311 | "isPrivate": false, 312 | "metaSortKey": -1551908186485, 313 | "method": "POST", 314 | "modified": 1551909713942, 315 | "name": "05-Create activity alias", 316 | "parameters": [], 317 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 318 | "settingDisableRenderRequestBody": false, 319 | "settingEncodeUrl": true, 320 | "settingMaxTimelineDataSize": 1000, 321 | "settingRebuildPath": true, 322 | "settingSendCookies": true, 323 | "settingStoreCookies": true, 324 | "url": "{{dasApiRoot}}/activities/{{activityName}}/aliases", 325 | "_type": "request" 326 | }, 327 | { 328 | "_id": "req_2d691ab05d554efeba418443a56693b8", 329 | "authentication": {}, 330 | "body": { 331 | "mimeType": "", 332 | "text": "{\n\t\"id\": \"{{activityName}}\",\n\t\"commandLine\": [ \"$(engine.path)\\\\\\\\revitcoreconsole.exe /i $(args[rvtFile].path) /al $(appbundles[{{ appBundleName }}].path)\" ],\n\t\"parameters\": {\n \"sketchItInput\": {\n \"zip\": false,\n \"ondemand\": false,\n \"verb\": \"get\",\n \"description\": \"SketchIt input parameters\",\n \"required\": true,\n \"localName\": \"SketchItInput.json\"\n },\n \"result\": {\n \"zip\": false,\n \"ondemand\": false,\n \"verb\": \"put\",\n \"description\": \"Results\",\n \"required\": true,\n \"localName\": \"sketchIt.rvt\"\n }\n },\n\t\"engine\": \"Autodesk.Revit+2019\",\n\t\"appbundles\": [ \"{{dasNickName}}.{{appBundleName}}+{{appBundleAlias}}\" ],\n\t\"description\": \"Creates walls and floors from an input JSON file.\"\n}" 333 | }, 334 | "created": 1551908186490, 335 | "description": "", 336 | "headers": [ 337 | { 338 | "id": "pair_6e2c74a067ca4561b77c0626c4554d73", 339 | "name": "Content-Type", 340 | "value": "application/json" 341 | }, 342 | { 343 | "id": "pair_b7465c6879d44ecbaa564a202298dcb8", 344 | "name": "Authorization", 345 | "value": "Bearer {{dasApiToken}}" 346 | } 347 | ], 348 | "isPrivate": false, 349 | "metaSortKey": -1551908186490, 350 | "method": "POST", 351 | "modified": 1551910747043, 352 | "name": "04-Create activity", 353 | "parameters": [], 354 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 355 | "settingDisableRenderRequestBody": false, 356 | "settingEncodeUrl": true, 357 | "settingMaxTimelineDataSize": 1000, 358 | "settingRebuildPath": true, 359 | "settingSendCookies": true, 360 | "settingStoreCookies": true, 361 | "url": "{{dasApiRoot}}/activities", 362 | "_type": "request" 363 | }, 364 | { 365 | "_id": "req_dc244c1877ba4bf28240a8e8c0888091", 366 | "authentication": {}, 367 | "body": { 368 | "mimeType": "", 369 | "text": "{\n \"version\": 1,\n \"id\": \"dev\"\n}" 370 | }, 371 | "created": 1551908186496, 372 | "description": "", 373 | "headers": [ 374 | { 375 | "id": "pair_f26598ce6b8a476c935db243bd4b4d87", 376 | "name": "", 377 | "value": "" 378 | }, 379 | { 380 | "id": "pair_e7771d6f1d514b2e9de8c7739dc2a8ba", 381 | "name": "Authorization", 382 | "value": "Bearer {{dasApiToken}}" 383 | }, 384 | { 385 | "id": "pair_0d404a4a5d014461bc84843d06ea1fa0", 386 | "name": "Content-Type", 387 | "value": "application/json" 388 | } 389 | ], 390 | "isPrivate": false, 391 | "metaSortKey": -1551908186496, 392 | "method": "POST", 393 | "modified": 1551909666948, 394 | "name": "03-Create a new app bundle alias", 395 | "parameters": [], 396 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 397 | "settingDisableRenderRequestBody": false, 398 | "settingEncodeUrl": true, 399 | "settingMaxTimelineDataSize": 1000, 400 | "settingRebuildPath": true, 401 | "settingSendCookies": true, 402 | "settingStoreCookies": true, 403 | "url": "{{dasApiRoot}}/appbundles/{{appBundleName}}/aliases", 404 | "_type": "request" 405 | }, 406 | { 407 | "_id": "req_611a0824cd4b4794a250e986669d4835", 408 | "authentication": {}, 409 | "body": { 410 | "mimeType": "multipart/form-data", 411 | "params": [ 412 | { 413 | "disabled": false, 414 | "name": "key", 415 | "type": "text", 416 | "value": "{{appBundleFormDataKey}}" 417 | }, 418 | { 419 | "disabled": false, 420 | "name": "content-type", 421 | "type": "text", 422 | "value": "application/octet-stream" 423 | }, 424 | { 425 | "disabled": false, 426 | "name": "policy", 427 | "type": "text", 428 | "value": "{{appBundleFormDataPolicy}}" 429 | }, 430 | { 431 | "disabled": false, 432 | "name": "success_action_status", 433 | "type": "text", 434 | "value": "200" 435 | }, 436 | { 437 | "disabled": false, 438 | "name": "x-amz-signature", 439 | "type": "text", 440 | "value": "{{appBundleFormDataSignature}}" 441 | }, 442 | { 443 | "disabled": false, 444 | "name": "x-amz-credential", 445 | "type": "text", 446 | "value": "{{appBundleFormDataCredential}}" 447 | }, 448 | { 449 | "disabled": false, 450 | "name": "x-amz-algorithm", 451 | "type": "text", 452 | "value": "AWS4-HMAC-SHA256" 453 | }, 454 | { 455 | "disabled": false, 456 | "name": "x-amz-date", 457 | "type": "text", 458 | "value": "{{appBundleFormDataDate}}" 459 | }, 460 | { 461 | "disabled": false, 462 | "name": "x-amz-server-side-encryption", 463 | "type": "text", 464 | "value": "AES256" 465 | }, 466 | { 467 | "disabled": false, 468 | "name": "x-amz-security-token", 469 | "type": "text", 470 | "value": "{{appBundleFormDataToken}}" 471 | }, 472 | { 473 | "disabled": false, 474 | "name": "success_action_redirect", 475 | "type": "text", 476 | "value": "{{appBundleFormRedirect}}" 477 | }, 478 | { 479 | "disabled": false, 480 | "fileName": "", 481 | "name": "file", 482 | "type": "file" 483 | } 484 | ] 485 | }, 486 | "created": 1551908186501, 487 | "description": "", 488 | "headers": [], 489 | "isPrivate": false, 490 | "metaSortKey": -1551908186501, 491 | "method": "POST", 492 | "modified": 1551908186501, 493 | "name": "02-Upload app bundle to Design Automation", 494 | "parameters": [], 495 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 496 | "settingDisableRenderRequestBody": false, 497 | "settingEncodeUrl": true, 498 | "settingMaxTimelineDataSize": 1000, 499 | "settingRebuildPath": true, 500 | "settingSendCookies": true, 501 | "settingStoreCookies": true, 502 | "url": "{{appBundleUrl}}", 503 | "_type": "request" 504 | }, 505 | { 506 | "_id": "req_2347148e0f0d483da4d3cafef4b90978", 507 | "authentication": {}, 508 | "body": { 509 | "mimeType": "", 510 | "text": "{\n\t\"id\": \"{{appBundleName}}\",\n\t\"engine\": \"Autodesk.Revit+2019\",\n\t\"description\": \"SketchIt appbundle based on Revit 2019\"\n}" 511 | }, 512 | "created": 1551908186505, 513 | "description": "", 514 | "headers": [ 515 | { 516 | "id": "pair_64043b771bcb4c0c8eb0e8939dabc003", 517 | "name": "Content-Type", 518 | "value": "application/json" 519 | }, 520 | { 521 | "id": "pair_3485a61ff1fd4b708554585d5dc58d4f", 522 | "name": "Authorization", 523 | "value": "Bearer {{dasApiToken}}" 524 | } 525 | ], 526 | "isPrivate": false, 527 | "metaSortKey": -1551908186505, 528 | "method": "POST", 529 | "modified": 1551909414894, 530 | "name": "01-Create app bundle", 531 | "parameters": [], 532 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 533 | "settingDisableRenderRequestBody": false, 534 | "settingEncodeUrl": true, 535 | "settingMaxTimelineDataSize": 1000, 536 | "settingRebuildPath": true, 537 | "settingSendCookies": true, 538 | "settingStoreCookies": true, 539 | "url": "{{dasApiRoot}}/appbundles", 540 | "_type": "request" 541 | }, 542 | { 543 | "_id": "req_668349b336e84d858744e46f8c57a133", 544 | "authentication": {}, 545 | "body": { 546 | "mimeType": "", 547 | "text": "{\r\n\t\"nickname\": \"{{dasNickName}}\"\r\n}" 548 | }, 549 | "created": 1551908186512, 550 | "description": "", 551 | "headers": [ 552 | { 553 | "name": "Content-Type", 554 | "value": "application/json" 555 | }, 556 | { 557 | "name": "Authorization", 558 | "value": "Bearer {{dasApiToken}}" 559 | } 560 | ], 561 | "isPrivate": false, 562 | "metaSortKey": -1551908186512, 563 | "method": "PATCH", 564 | "modified": 1551908186512, 565 | "name": "Create nickname", 566 | "parameters": [], 567 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 568 | "settingDisableRenderRequestBody": false, 569 | "settingEncodeUrl": true, 570 | "settingMaxTimelineDataSize": 1000, 571 | "settingRebuildPath": true, 572 | "settingSendCookies": true, 573 | "settingStoreCookies": true, 574 | "url": "{{dasApiRoot}}/forgeapps/me", 575 | "_type": "request" 576 | }, 577 | { 578 | "_id": "req_1259eed555034842ba78446504f37969", 579 | "authentication": {}, 580 | "body": { 581 | "mimeType": "application/x-www-form-urlencoded", 582 | "params": [ 583 | { 584 | "disabled": false, 585 | "name": "client_id", 586 | "value": "{{client_id}}" 587 | }, 588 | { 589 | "disabled": false, 590 | "name": "client_secret", 591 | "value": "{{client_secret}}" 592 | }, 593 | { 594 | "disabled": false, 595 | "name": "grant_type", 596 | "value": "client_credentials" 597 | }, 598 | { 599 | "disabled": false, 600 | "name": "scope", 601 | "value": "code:all" 602 | } 603 | ] 604 | }, 605 | "created": 1551908186515, 606 | "description": "", 607 | "headers": [ 608 | { 609 | "name": "Content-Type", 610 | "value": "application/x-www-form-urlencoded" 611 | } 612 | ], 613 | "isPrivate": false, 614 | "metaSortKey": -1551908186515, 615 | "method": "POST", 616 | "modified": 1551908186515, 617 | "name": "00-New token", 618 | "parameters": [], 619 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 620 | "settingDisableRenderRequestBody": false, 621 | "settingEncodeUrl": true, 622 | "settingMaxTimelineDataSize": 1000, 623 | "settingRebuildPath": true, 624 | "settingSendCookies": true, 625 | "settingStoreCookies": true, 626 | "url": "{{baseUrl}}/authentication/v1/authenticate", 627 | "_type": "request" 628 | }, 629 | { 630 | "_id": "req_ddd572b3ec06424c87e9d2638a11984e", 631 | "authentication": {}, 632 | "body": {}, 633 | "created": 1551909209580, 634 | "description": "", 635 | "headers": [ 636 | { 637 | "id": "pair_47a42e8a375c4c0a84e8a2c61dac9e2c", 638 | "name": "Authorization", 639 | "value": "Bearer {{dasApiToken}}" 640 | } 641 | ], 642 | "isPrivate": false, 643 | "metaSortKey": -1551908186508.5, 644 | "method": "GET", 645 | "modified": 1551909240885, 646 | "name": "Nickname", 647 | "parameters": [], 648 | "parentId": "fld_6685d58f7c444080abdc6f59919b26f5", 649 | "settingDisableRenderRequestBody": false, 650 | "settingEncodeUrl": true, 651 | "settingMaxTimelineDataSize": 1000, 652 | "settingRebuildPath": true, 653 | "settingSendCookies": true, 654 | "settingStoreCookies": true, 655 | "url": "{{dasApiRoot}}/forgeapps/me", 656 | "_type": "request" 657 | } 658 | ] 659 | } -------------------------------------------------------------------------------- /SketchIt/Insomnia.REST/Sketchit-App_Insomnia-ENV.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl":"https://developer.api.autodesk.com", 3 | "dasApiRoot":"https://developer.api.autodesk.com/da/us-east/v3", 4 | "client_id": "", 5 | "client_secret": "", 6 | "dasNickName": "", 7 | "dasApiToken": "", 8 | "appBundleName": "SketchItApp", 9 | "activityName": "", 10 | "appBundleAlias": "dev", 11 | "activityAlias": "dev", 12 | "appBundleFormDataCredential": "", 13 | "appBundleFormDataDate": "", 14 | "appBundleFormDataKey": "", 15 | "appBundleFormDataPolicy": "", 16 | "appBundleFormDataSignature": "", 17 | "appBundleFormDataToken": "", 18 | "appBundleFormRedirect": "", 19 | "appBundleUrl": "", 20 | "workitemId": "" 21 | } -------------------------------------------------------------------------------- /SketchIt/Insomnia.REST/env-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/SketchIt/Insomnia.REST/env-preview.png -------------------------------------------------------------------------------- /SketchIt/Insomnia.REST/insomnia-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/SketchIt/Insomnia.REST/insomnia-preview.png -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/README.md: -------------------------------------------------------------------------------- 1 | # SketchIt Sample 2 | 3 | ![Platforms](https://img.shields.io/badge/Plugins-Windows-lightgray.svg) 4 | ![.NET](https://img.shields.io/badge/.NET%20Framework-4.7-blue.svg) 5 | [![Revit](https://img.shields.io/badge/Revit-2019-lightblue.svg)](http://developer.autodesk.com/) 6 | 7 | ## Description 8 | 9 | SketchIt is an application that creates walls and floors in a rvt file. It takes a JSON file that specifies the walls and floors to be created, and outputs a new rvt file. 10 | 11 | # Setup 12 | 13 | ## Prerequisites 14 | 15 | 1. **Visual Studio** 2017 16 | 2. **Revit** 2019 required to compile changes into the plugin 17 | 3. **7z zip** requires to create the bundle ZIP, [download here](https://www.7-zip.org/) 18 | 19 | ## References 20 | 21 | This Revit plugin requires **RevitAPI** and **DesignAutomationBridge** references. The `Reference Path` option should point to the folder. 22 | 23 | ![](./reference_path.png) 24 | 25 | 26 | ## Building SketchIt.sln 27 | 28 | Clone this repository and open `SketchIt.sln` in Visual Studio. 29 | 30 | Right-click on References, then Add Reference and Browse for RevitAPI.dll (by default under _C:\Program Files\Autodesk\Revit 201x_ folder). Then right-click on this RevitAPI reference, go to Properties, then set Copy Local to False. 31 | 32 | Then right-click on the project, go to Manage NuGet Packages..., under Browser you can search for DesignAutomation.Revit and install _Autodesk.Forge.DesignAutomation.Revit_ (choose the appropriate Revit version you need). Then search and install _Newtonsoft.Json_ (which is used to parse input data in JSON format). 33 | 34 | Please check Include prerelease while searching for packages. Design Automation for Revit is in beta (as of Jan/2019). 35 | 36 | In the SketchIt C# project, repair the references to `DesignAutomationBridge`, `Newtonsoft JSON framework` and `RevitAPI`. You can do this by removing and re-adding the references, or by opening the `SketchIt.csproj` for edit and manually updating the reference paths. 37 | 38 | Build `SketchIt.sln` in `Release` or `Debug` configuration. 39 | 40 | 41 | `SketchItActivity` expects an input file `SketchItInput.json`. The contents of the embedded JSON are stored in a file named `SketchItInput.json`, as specified by the `parameters` of `sketchItInput` in the activity `SketchItActivity`. The SketchIt application reads this file from current working folder, parses the JSON and creates walls and floors from the extracted specifications in a new created Revit file `sketchIt.rvt`, which will be uploaded to `url` you provide in the workitem. 42 | 43 | The function `SketchItFunc` in [SketchIt.cs](SketchItApp/SketchIt.cs) performs these operations. 44 | 45 | # Further Reading 46 | 47 | - [My First Revit Plugin](https://knowledge.autodesk.com/support/revit-products/learn-explore/caas/simplecontent/content/my-first-revit-plug-overview.html) 48 | - [Revit Developer Center](https://www.autodesk.com/developer-network/platform-technologies/revit) 49 | 50 | ## License 51 | 52 | This sample is licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT). Please see the [LICENSE](LICENSE) file for full details. 53 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchIt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2027 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchIt", "SketchItApp\SketchIt.csproj", "{EFB263DA-A3C0-4789-9D73-F74351DCC26D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EFB263DA-A3C0-4789-9D73-F74351DCC26D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EFB263DA-A3C0-4789-9D73-F74351DCC26D}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EFB263DA-A3C0-4789-9D73-F74351DCC26D}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EFB263DA-A3C0-4789-9D73-F74351DCC26D}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {66192511-4D6A-4ECE-99AA-3FB6BC1DA3F1} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SketchIt")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SketchIt")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("efb263da-a3c0-4789-9d73-f74351dcc26d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/SketchIt.bundle/Contents/SketchIt.addin: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | SketchIt 5 | .\SketchIt.dll 6 | B69A15D3-48AA-4792-8502-CB48154EE0F9 7 | SketchIt.SketchItApp 8 | "SketchIt" 9 | Autodesk 10 | Autodesk, Inc, www.autodesk.com 11 | 12 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/SketchIt.bundle/PackageContents.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 8 | 14 | 15 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/SketchIt.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | using Autodesk.Revit.ApplicationServices; 6 | using Autodesk.Revit.DB; 7 | using DesignAutomationFramework; 8 | 9 | namespace SketchIt 10 | { 11 | [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)] 12 | [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)] 13 | class SketchItApp : IExternalDBApplication 14 | { 15 | public ExternalDBApplicationResult OnStartup(Autodesk.Revit.ApplicationServices.ControlledApplication app) 16 | { 17 | DesignAutomationBridge.DesignAutomationReadyEvent += HandleDesignAutomationReadyEvent; 18 | return ExternalDBApplicationResult.Succeeded; 19 | } 20 | 21 | public ExternalDBApplicationResult OnShutdown(Autodesk.Revit.ApplicationServices.ControlledApplication app) 22 | { 23 | return ExternalDBApplicationResult.Succeeded; 24 | } 25 | 26 | public void HandleDesignAutomationReadyEvent(object sender, DesignAutomationReadyEventArgs e) 27 | { 28 | // Run the application logic. 29 | SketchItFunc(e.DesignAutomationData); 30 | 31 | e.Succeeded = true; 32 | } 33 | 34 | private static void SketchItFunc(DesignAutomationData data) 35 | { 36 | if (data == null) 37 | throw new InvalidDataException(nameof(data)); 38 | 39 | Application rvtApp = data.RevitApp; 40 | if (rvtApp == null) 41 | throw new InvalidDataException(nameof(rvtApp)); 42 | 43 | Document newDoc = rvtApp.NewProjectDocument(UnitSystem.Imperial); 44 | if (newDoc == null) 45 | throw new InvalidOperationException("Could not create new document."); 46 | string filePath = "sketchIt.rvt"; 47 | 48 | string filepathJson = "SketchItInput.json"; 49 | SketchItParams jsonDeserialized = SketchItParams.Parse(filepathJson); 50 | 51 | CreateWalls(jsonDeserialized, newDoc); 52 | 53 | CreateFloors(jsonDeserialized, newDoc); 54 | 55 | newDoc.SaveAs(filePath); 56 | } 57 | 58 | private static void CreateWalls(SketchItParams jsonDeserialized, Document newDoc) 59 | { 60 | FilteredElementCollector levelCollector = new FilteredElementCollector(newDoc); 61 | levelCollector.OfClass(typeof(Level)); 62 | ElementId someLevelId = levelCollector.FirstElementId(); 63 | if (someLevelId == null || someLevelId.IntegerValue < 0) throw new InvalidDataException("ElementID is invalid."); 64 | 65 | List curves = new List(); 66 | foreach (WallLine lines in jsonDeserialized.Walls) 67 | { 68 | XYZ start = new XYZ(lines.Start.X, lines.Start.Y, lines.Start.Z); 69 | XYZ end = new XYZ(lines.End.X, lines.End.Y, lines.End.Z); 70 | curves.Add(Line.CreateBound(start, end)); 71 | } 72 | 73 | using (Transaction wallTrans = new Transaction(newDoc, "Create some walls")) 74 | { 75 | wallTrans.Start(); 76 | 77 | foreach (Curve oneCurve in curves) 78 | { 79 | Wall.Create(newDoc, oneCurve, someLevelId, false); 80 | } 81 | 82 | wallTrans.Commit(); 83 | } 84 | } 85 | 86 | private static void CreateFloors(SketchItParams jsonDeserialized, Document newDoc) 87 | { 88 | foreach (List floorPoints in jsonDeserialized.Floors) 89 | { 90 | CurveArray floor = new CurveArray(); 91 | int lastPointOnFloor = floorPoints.Count - 1; 92 | 93 | for (int pointNum = 0; pointNum <= lastPointOnFloor; pointNum++) 94 | { 95 | XYZ startPoint = new XYZ(floorPoints[pointNum].X, floorPoints[pointNum].Y, floorPoints[pointNum].Z); 96 | XYZ endPoint; 97 | 98 | if (pointNum == lastPointOnFloor) 99 | { 100 | endPoint = new XYZ(floorPoints[0].X, floorPoints[0].Y, floorPoints[0].Z); 101 | } 102 | else 103 | { 104 | endPoint = new XYZ(floorPoints[pointNum + 1].X, floorPoints[pointNum + 1].Y, floorPoints[pointNum + 1].Z); 105 | } 106 | 107 | Curve partOfFloor = Line.CreateBound(startPoint, endPoint); 108 | floor.Append(partOfFloor); 109 | } 110 | 111 | using (Transaction floorTrans = new Transaction(newDoc, "Create a floor")) 112 | { 113 | floorTrans.Start(); 114 | newDoc.Create.NewFloor(floor, false); 115 | floorTrans.Commit(); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/SketchIt.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EFB263DA-A3C0-4789-9D73-F74351DCC26D} 8 | Library 9 | Properties 10 | SketchIt 11 | SketchIt 12 | v4.7 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Autodesk.Forge.DesignAutomation.Revit.2019.0.0-beta2\lib\net47\DesignAutomationBridge.dll 38 | 39 | 40 | False 41 | Newtonsoft.Json.dll 42 | 43 | 44 | C:\Program Files\Autodesk\Revit 2019\RevitAPI.dll 45 | False 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | Never 64 | 65 | 66 | Never 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | xcopy /Y /F "$(TargetDir)*.dll" "$(ProjectDir)SketchIt.bundle\Contents\" 75 | del /F "$(ProjectDir)\bundles\SketchIt.zip" 76 | "C:\Program Files\7-Zip\7z.exe" a -tzip "$(ProjectDir)/bundles/SketchIt.zip" "$(ProjectDir)SketchIt.bundle\" -xr0!*.pdb 77 | 78 | 79 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/SketchItParams.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace SketchIt 10 | { 11 | 12 | internal class Point 13 | { 14 | [JsonProperty(PropertyName = "x")] 15 | public double X { get; set; } = 0.0; 16 | [JsonProperty(PropertyName = "y")] 17 | public double Y { get; set; } = 0.0; 18 | [JsonProperty(PropertyName = "z")] 19 | public double Z { get; set; } = 0.0; 20 | } 21 | internal class WallLine 22 | { 23 | [JsonProperty(PropertyName = "start")] 24 | public Point Start { get; set; } 25 | [JsonProperty(PropertyName = "end")] 26 | public Point End { get; set; } 27 | } 28 | 29 | 30 | 31 | internal class SketchItParams 32 | { 33 | [JsonProperty(PropertyName = "walls")] 34 | public IList Walls { get; set; } 35 | [JsonProperty(PropertyName = "floors")] 36 | public IList> Floors { get; set; } 37 | static public SketchItParams Parse(string jsonPath) 38 | { 39 | try 40 | { 41 | if (!File.Exists(jsonPath)) 42 | return new SketchItParams(); 43 | 44 | string jsonContents = File.ReadAllText(jsonPath); 45 | return JsonConvert.DeserializeObject(jsonContents); 46 | } 47 | catch (Exception ex) 48 | { 49 | Console.WriteLine("Exception happens when parsing the json file: " + ex); 50 | return null; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/bundles/SketchIt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/SketchIt/Revit.Addin/SketchItApp/bundles/SketchIt.zip -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/SketchItApp/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /SketchIt/Revit.Addin/reference_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/SketchIt/Revit.Addin/reference_path.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sketch-it", 3 | "version": "1.0.0", 4 | "description": "Sketch It", 5 | "main": "server/generated/main.js", 6 | "scripts": { 7 | "start": "node server/generated/main.js", 8 | "postinstall": "npm run build", 9 | "clean": "git clean -fxd", 10 | "build": "npm run client-build && npm run server-build", 11 | "watch": "npm run client-watch & npm run server-watch", 12 | "debug": "npm run watch & nodemon", 13 | "client-build": "browserify -p [minifyify --no-map] -g browserify-css -t [ babelify --presets [ react env ] --plugins [ transform-class-properties transform-object-rest-spread ] ] www/entry/app.js -o www/generated/sketch_it_bundle.js", 14 | "client-watch": "watchify --debug -v -g browserify-css -t [ babelify --presets [ react env ] --plugins [ transform-class-properties transform-object-rest-spread ] ] www/entry/app.js -o www/generated/sketch_it_bundle.js", 15 | "server-build": "babel --presets env --plugins transform-class-properties server/src --out-dir server/generated", 16 | "server-watch": "babel --watch --presets env --plugins transform-class-properties server/src --out-dir server/generated" 17 | }, 18 | "repository": { 19 | "type": "git" 20 | }, 21 | "author": "", 22 | "license": "MIT", 23 | "dependencies": { 24 | "almost-equal": "1.1.0", 25 | "base-64": "0.1.0", 26 | "body-parser": "1.18.3", 27 | "bootstrap": "4.3.1", 28 | "braces": "^2.3.2", 29 | "classnames": "2.2.6", 30 | "debounce": "1.2.0", 31 | "ejs": "2.6.1", 32 | "es6-promisify": "6.0.1", 33 | "express": "4.16.4", 34 | "forge-apis": "0.4.5", 35 | "gl-matrix": "3.0.0", 36 | "is-url": "1.2.4", 37 | "jquery": "3.3.1", 38 | "popper.js": "1.14.7", 39 | "react": "16.8.4", 40 | "react-dom": "16.8.4", 41 | "react-redux": "6.0.1", 42 | "redux": "4.0.1", 43 | "redux-actions": "2.6.5", 44 | "request": "2.88.0", 45 | "serve-favicon": "2.5.0", 46 | "shortid": "2.2.14", 47 | "socket.io": "2.2.0", 48 | "socket.io-client": "2.2.0" 49 | }, 50 | "devDependencies": { 51 | "babel-core": "^6.26.0", 52 | "babel-cli": "^6.26.0", 53 | "babel-plugin-transform-class-properties": "^6.24.1", 54 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 55 | "babel-preset-env": "^1.7.0", 56 | "babel-preset-react": "^6.24.1", 57 | "babelify": "8.0.0", 58 | "browserify": "16.2.3", 59 | "browserify-css": "0.14.0", 60 | "minifyify": "7.3.5", 61 | "ngrok": "^3.1.1" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /server/src/app_utils.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import ForgeUtils from './forge_utils'; 20 | import SocketUtils from './socket_utils'; 21 | import base64 from 'base-64'; 22 | 23 | class AppUtils { 24 | static _data = []; 25 | 26 | static init () { 27 | // setInterval(_ => this.getMissingThumbnails(), 3000); 28 | }; 29 | 30 | static addJobDetails (fileId) { 31 | this._data.push({workitemId: '', fileId, thumbnail: ''}); 32 | } 33 | 34 | static getFileId (workitemId) { 35 | let data = this._data.find(d => d.workitemId === workitemId); 36 | return data.fileId; 37 | } 38 | 39 | static getThumbnail (fileId) { 40 | let data = this._data.find(d => d.fileId === fileId); 41 | return data.thumbnail; 42 | } 43 | 44 | static setThumbnail (fileId, thumbnail) { 45 | let data = this._data.find(d => d.fileId === fileId); 46 | data.thumbnail = thumbnail; 47 | } 48 | 49 | static setWorkitemId (fileId, workitemId) { 50 | let data = this._data.find(d => d.fileId === fileId); 51 | data.workitemId = workitemId; 52 | } 53 | 54 | static getMissingThumbnails () { 55 | this._data.filter(d => d.thumbnail==='').forEach(({fileId}) => { 56 | let urn = base64.encode('urn:adsk.objects:os.object:' + ForgeUtils.BUCKET_KEY + '/' + fileId); 57 | ForgeUtils.getThumbnail(urn).then(thumbnail => { 58 | if (!thumbnail) return; 59 | this.setThumbnail(fileId, thumbnail); 60 | SocketUtils.emit(fileId, 'thumbnail'); 61 | }); 62 | }); 63 | } 64 | }; 65 | 66 | export default AppUtils; 67 | -------------------------------------------------------------------------------- /server/src/forge_utils.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import ForgeSDK from 'forge-apis'; 20 | import request from 'request'; 21 | import base64 from 'base-64'; 22 | import NgrokUtils from './ngrok_utils'; 23 | import {promisify} from 'es6-promisify'; 24 | 25 | class ForgeUtils { 26 | static FORGE_URL = 'https://developer.api.autodesk.com'; 27 | static DAS_URL = 'https://developer.api.autodesk.com/da/us-east/v3'; 28 | static CLIENT_ID = process.env.FORGE_CLIENT_ID || ''; 29 | static CLIENT_SECRET = process.env.FORGE_CLIENT_SECRET || ''; 30 | static ACTIVITY_ID = process.env.FORGE_ACTIVITY_ID || ''; 31 | static AUTH_SCOPE = ['data:write', 'data:create', 'data:read', 'bucket:read', 'bucket:update', 'bucket:create', 'bucket:delete', 'viewables:read', 'code:all']; 32 | static BUCKET_KEY = process.env.FORGE_BUCKET_KEY || ''; 33 | static HOOK_WORKFLOW = NgrokUtils.isLocalUrl() ? 'local-sketchit-workflow-id' : 'fixed-sketchit-workflow-id'; 34 | static POLLING_DELAY = 5000; 35 | static _oAuth2TwoLegged = null; 36 | 37 | static init () { 38 | this._oAuth2TwoLegged = new ForgeSDK.AuthClientTwoLegged(this.CLIENT_ID, this.CLIENT_SECRET, this.AUTH_SCOPE, true); 39 | return this._oAuth2TwoLegged.authenticate().then(cr => { 40 | return Promise.all([this.getOrCreateBucket(), this.createOrModifyWebhook()]); 41 | }).catch(err => { 42 | console.error(err); 43 | }); 44 | }; 45 | 46 | static getOrCreateBucket () { 47 | let BucketsApi = new ForgeSDK.BucketsApi(); 48 | let bucketKey = this.BUCKET_KEY; 49 | 50 | return BucketsApi.getBucketDetails(bucketKey, null, this._oAuth2TwoLegged.getCredentials()).catch(err => { 51 | let policyKey = 'temporary'; 52 | return BucketsApi.createBucket({bucketKey, policyKey}, {}, null, this._oAuth2TwoLegged.getCredentials()); 53 | }).then(({body:{bucketKey}}) => { 54 | if (bucketKey !== this.BUCKET_KEY) { 55 | throw new Error('Could not find or create bucket!'); 56 | } 57 | }); 58 | }; 59 | 60 | static createEmptyResource (objectName, access='write') { 61 | let ObjectsApi = new ForgeSDK.ObjectsApi(); 62 | let bucketKey = this.BUCKET_KEY; 63 | return ObjectsApi.uploadObject(bucketKey, objectName, 0, '', {}, null, this._oAuth2TwoLegged.getCredentials()); 64 | }; 65 | 66 | static createSignedResource (objectName, access='read') { 67 | let ObjectsApi = new ForgeSDK.ObjectsApi(); 68 | let bucketKey = this.BUCKET_KEY; 69 | return ObjectsApi.createSignedResource(bucketKey, objectName, {}, {access}, null, this._oAuth2TwoLegged.getCredentials()).then(({body:{signedUrl}}) => { 70 | return signedUrl; 71 | }); 72 | }; 73 | 74 | static createOrModifyWebhook () { 75 | let params = { 76 | url: this.FORGE_URL + '/webhooks/v1/systems/derivative/events/extraction.finished/hooks', 77 | headers: { 78 | Authorization: 'Bearer ' + this._oAuth2TwoLegged.getCredentials().access_token, 79 | }, 80 | json: true 81 | }; 82 | 83 | promisify(request.get)(params).then(({body:{data}}) => { 84 | return Promise.all(data.map((d) => { 85 | let hook = d.__self__; 86 | if (d.scope.workflow !== this.HOOK_WORKFLOW) 87 | return Promise.resolve(false); 88 | if (d.callbackUrl === NgrokUtils.getServerUrl() + '/translationcomplete') 89 | return Promise.resolve(true); 90 | 91 | console.log('deleting hook - ' + hook) 92 | return this.deleteWebhook(hook).then(_ => false); 93 | })).then(values => { 94 | if (!values.includes(true)) { 95 | this.createWebhook(); 96 | } 97 | }); 98 | }); 99 | }; 100 | 101 | static createWebhook () { 102 | let params = { 103 | url: this.FORGE_URL + '/webhooks/v1/systems/derivative/events/extraction.finished/hooks', 104 | headers: { 105 | Authorization: 'Bearer ' + this._oAuth2TwoLegged.getCredentials().access_token, 106 | }, 107 | json: { 108 | callbackUrl: NgrokUtils.getServerUrl() + '/translationcomplete', 109 | scope: { 110 | workflow: this.HOOK_WORKFLOW 111 | } 112 | } 113 | }; 114 | console.log('creating hook'); 115 | return promisify(request.post)(params); 116 | }; 117 | 118 | static deleteWebhook (hook) { 119 | let params = { 120 | url: this.FORGE_URL + '/webhooks/v1' + hook, 121 | headers: { 122 | Authorization: 'Bearer ' + this._oAuth2TwoLegged.getCredentials().access_token, 123 | } 124 | } 125 | return promisify(request.delete)(params); 126 | }; 127 | 128 | static translate (objectName) { 129 | let DerivativesApi = new ForgeSDK.DerivativesApi(); 130 | let urn = base64.encode('urn:adsk.objects:os.object:' + this.BUCKET_KEY + '/' + objectName); 131 | let input = {urn}; 132 | let output = { 133 | formats: [ 134 | { 135 | type: 'svf', 136 | views: ['2d', '3d'] 137 | } 138 | ] 139 | }; 140 | let misc = { 141 | workflow: this.HOOK_WORKFLOW 142 | } 143 | return DerivativesApi.translate({input, output, misc}, {}, null, this._oAuth2TwoLegged.getCredentials()); 144 | }; 145 | 146 | static getThumbnail (urn) { 147 | let DerivativesApi = new ForgeSDK.DerivativesApi(); 148 | return DerivativesApi.getThumbnail(urn, {}, null, this._oAuth2TwoLegged.getCredentials()) 149 | .then(({body}) => new Buffer.from(body).toString('base64')) 150 | .catch(_ => ''); 151 | }; 152 | 153 | static postWorkitem(payload) { 154 | let params = { 155 | url: this.DAS_URL + '/workitems', 156 | headers: { 157 | Authorization: 'Bearer ' + this._oAuth2TwoLegged.getCredentials().access_token, 158 | }, 159 | json: payload 160 | } 161 | return promisify(request.post)(params).then(({body:{id}}) => id); 162 | }; 163 | 164 | static getWorkitemStatus (id) { 165 | let params = { 166 | url: this.DAS_URL + '/workitems/' + id, 167 | headers: { 168 | 'Authorization': 'Bearer ' + this._oAuth2TwoLegged.getCredentials().access_token, 169 | } 170 | }; 171 | return promisify(request)(params).then(({body}) => JSON.parse(body).status); 172 | }; 173 | }; 174 | 175 | export default ForgeUtils; 176 | -------------------------------------------------------------------------------- /server/src/main.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import express from 'express'; 20 | import bodyParser from 'body-parser'; 21 | import favicon from 'serve-favicon'; 22 | import shortid from 'shortid'; 23 | import ForgeSDK from 'forge-apis'; 24 | import base64 from 'base-64'; 25 | import ForgeUtils from './forge_utils'; 26 | import NgrokUtils from './ngrok_utils'; 27 | import SocketUtils from './socket_utils'; 28 | import AppUtils from './app_utils'; 29 | 30 | let app = express(); 31 | app.use(bodyParser.urlencoded({ extended: false })); 32 | app.use(bodyParser.json()); 33 | 34 | app.use('/', express.static(__dirname + '/../../www')); 35 | app.use('/node_modules', express.static(__dirname + '/../../node_modules')); 36 | app.use(favicon(__dirname + '/../../www/res/favicon.png')); 37 | app.set('views', __dirname + '/../../www'); 38 | app.set('view engine', 'ejs'); 39 | app.use(bodyParser.json()); 40 | 41 | app.get('/*', (req, res, next) => { 42 | let url = req.path.substring(1); 43 | if (!url) { 44 | res.render('index'); 45 | return; 46 | } 47 | next(); 48 | }); 49 | 50 | app.get('/token', (req, res) => { 51 | let url = ForgeUtils.DAS_URL; 52 | let clientId = ForgeUtils.CLIENT_ID; 53 | let clientSecret = ForgeUtils.CLIENT_SECRET; 54 | let authScope = ForgeUtils.AUTH_SCOPE; 55 | let oAuth2TwoLegged = new ForgeSDK.AuthClientTwoLegged(clientId, clientSecret, authScope, true); 56 | 57 | oAuth2TwoLegged.authenticate().then(token => { 58 | res.json(token); 59 | }); 60 | }); 61 | 62 | app.get('/bucket', (req, res) => { 63 | let bucket = ForgeUtils.BUCKET_KEY; 64 | res.json(bucket); 65 | }); 66 | 67 | app.get('/thumbnail', (req, res) => { 68 | let {fileId} = req.query; 69 | let thumbnail = AppUtils.getThumbnail(fileId); 70 | res.json({found: thumbnail!=='', thumbnail}); 71 | }); 72 | 73 | app.get('/download', (req, res) => { 74 | let {fileId} = req.query; 75 | ForgeUtils.createSignedResource(fileId).then(signedUrl => { 76 | res.json({found: true, signedUrl}); 77 | }).catch(_ => { 78 | res.json({found: false, signedUrl: ''}); 79 | }); 80 | }); 81 | 82 | app.post('/workitemcomplete', (req, res) => { 83 | let {status, id} = req.body; 84 | let fileId = AppUtils.getFileId(id); 85 | console.log(status, '- generated ' + fileId) 86 | if (status === 'success') { 87 | ForgeUtils.translate(fileId); 88 | SocketUtils.emit(fileId, 'workitem'); 89 | } 90 | res.json({status, id, fileId}); 91 | }); 92 | 93 | app.post('/translationcomplete', (req, res) => { 94 | let {hook, payload} = req.body; 95 | let urn = payload.URN; 96 | let fileId = base64.decode(urn).replace('urn:adsk.objects:os.object:' + ForgeUtils.BUCKET_KEY + '/', ''); 97 | 98 | ForgeUtils.getThumbnail(urn).then(thumbnail => { 99 | AppUtils.setThumbnail(fileId, thumbnail); 100 | SocketUtils.emit(fileId, 'thumbnail'); 101 | }); 102 | 103 | console.log('success', '- translated ' + fileId) 104 | res.sendStatus(200); 105 | }); 106 | 107 | app.post('/create', (req, res) => { 108 | let {elements} = req.body; 109 | let fileId = shortid.generate() + '.rvt'; 110 | AppUtils.addJobDetails(fileId); 111 | 112 | ForgeUtils.createEmptyResource(fileId).then(_ => { 113 | return ForgeUtils.createSignedResource(fileId, 'write'); 114 | }).then(signedUrl => { 115 | let payLoad = { 116 | activityId: ForgeUtils.ACTIVITY_ID, 117 | arguments: { 118 | sketchItInput: { 119 | url: 'data:application/json,'+JSON.stringify(elements) 120 | }, 121 | onComplete: { 122 | verb: 'post', 123 | url: NgrokUtils.getServerUrl() + '/workitemcomplete' 124 | }, 125 | result: { 126 | verb: 'put', 127 | url: signedUrl 128 | } 129 | } 130 | }; 131 | return ForgeUtils.postWorkitem(payLoad); 132 | }).then(id => { 133 | console.log('posted -', id); 134 | AppUtils.setWorkitemId(fileId, id); 135 | }).catch(err => { 136 | console.log(err) 137 | }); 138 | res.json({fileId}); 139 | }); 140 | 141 | 142 | app.set('port', process.env.PORT || 3000); 143 | 144 | let server = app.listen(app.get('port'), () => { 145 | console.log('Server listening on port ' + server.address().port); 146 | }); 147 | 148 | 149 | NgrokUtils.init(app.get('port')).then(_ => { 150 | ForgeUtils.init(); 151 | }).then(_ => { 152 | AppUtils.init(); 153 | }).then(_ => { 154 | SocketUtils.init(server); 155 | }); 156 | -------------------------------------------------------------------------------- /server/src/ngrok_utils.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import ngrok from 'ngrok'; 20 | 21 | class NgrokUtils { 22 | static _url = null; 23 | 24 | static getServerUrl () { 25 | return this._url; 26 | }; 27 | 28 | static isLocalUrl () { 29 | return !process.env.FORGE_WEBHOOK_URL; 30 | }; 31 | 32 | static init (port) { 33 | return NgrokUtils.generateUrl(port).then(url => { 34 | this._url = url; 35 | console.log(url); 36 | }); 37 | }; 38 | 39 | static generateUrl (port) { 40 | let url = process.env.FORGE_WEBHOOK_URL; 41 | if (url) 42 | return Promise.resolve(url); 43 | return ngrok.connect(port); 44 | }; 45 | }; 46 | 47 | export default NgrokUtils; 48 | -------------------------------------------------------------------------------- /server/src/socket_utils.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import socketio from 'socket.io'; 20 | 21 | class SocketUtils { 22 | static _sockets = []; 23 | 24 | static init (server) { 25 | let io = socketio.listen(server); 26 | 27 | io.on('connection', socket => { 28 | this._sockets.push(socket); 29 | }); 30 | 31 | io.on('disconnect', socket => { 32 | this._sockets = this._sockets.filter(s => s !== socket); 33 | }); 34 | }; 35 | 36 | static emit (fileId, msg) { 37 | this._sockets.forEach(socket => socket.emit(fileId, msg)); 38 | }; 39 | }; 40 | 41 | export default SocketUtils; 42 | -------------------------------------------------------------------------------- /thumbnail.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/thumbnail.gif -------------------------------------------------------------------------------- /www/css/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | height: 100%; 5 | background: #d3d3d3; 6 | -webkit-user-select: none; 7 | -moz-user-select: none; 8 | -ms-user-select: none; 9 | user-select: none; 10 | } 11 | 12 | 13 | #container { 14 | display: grid; 15 | height: 100vh; 16 | grid-template-columns: auto 325px; 17 | --header-height: 50px; 18 | --footer-height: 30px; 19 | grid-template-rows: var(--header-height) auto var(--footer-height); 20 | grid-template-areas: 21 | "header header" 22 | "main sidebar" 23 | "footer footer"; 24 | } 25 | 26 | #header, #footer { 27 | background: #434343; 28 | color: white; 29 | text-align: center; 30 | } 31 | 32 | #header { 33 | grid-area: header; 34 | line-height: var(--header-height) ; 35 | } 36 | 37 | #footer { 38 | grid-area: footer; 39 | line-height: var(--footer-height) ; 40 | } 41 | 42 | #viewer { 43 | grid-area: main; 44 | border: 2px solid black; 45 | } 46 | 47 | #forge-viewer { 48 | height: 100%; 49 | position: relative; 50 | overflow: hidden; 51 | } 52 | 53 | #forge-logo { 54 | position: absolute; 55 | top: 80px; 56 | left: 30px; 57 | z-index: 2; 58 | } 59 | 60 | #logo-size { 61 | width: 25%; 62 | } 63 | 64 | #canvas { 65 | grid-area: main; 66 | border: 2px solid black; 67 | } 68 | 69 | #svg { 70 | width: 100%; 71 | height: 100%; 72 | } 73 | 74 | #side-bar { 75 | grid-area: sidebar; 76 | background: #a3a3a3; 77 | border: 2px solid black; 78 | border-left: none; 79 | display: grid; 80 | grid-template-rows: auto 200px; 81 | grid-template-columns: auto; 82 | grid-template-areas: 83 | "editors" 84 | "thumbnail"; 85 | } 86 | 87 | #editors { 88 | grid-area: editors; 89 | } 90 | 91 | #thumbnail { 92 | grid-area: thumbnail; 93 | } 94 | 95 | .editor-button { 96 | border: 1px solid #666666; 97 | margin: 3px; 98 | border-radius: 3px; 99 | box-shadow: 0 3px 0 2px #777777; 100 | } 101 | 102 | .editor-button:hover { 103 | background-color: #cbcbcb; 104 | box-shadow: 0 0px 0 1px #666666; 105 | transform: translateY(3px); 106 | } 107 | 108 | .editor-button-active, .editor-button:active, .editor-button:hover { 109 | background-color: #cbcbcb; 110 | box-shadow: 0 1px 0 1px #666666; 111 | transform: translateY(2px); 112 | } 113 | 114 | .tn-button { 115 | display: table; 116 | font-size: 24px; 117 | width: 100%; 118 | height: 195px; 119 | box-shadow: 0 4px 0 0px #666666; 120 | text-align: center; 121 | color: #ffffff; 122 | border-radius: 10px; 123 | } 124 | 125 | .tn-button-green { 126 | cursor: pointer; 127 | background-color: #3d9970; 128 | } 129 | 130 | .tn-button-green:active, .tn-button-green:hover, .tn-button-image:active, .tn-button-image:hover { 131 | box-shadow: 0 1px 0 0px #666666; 132 | transform: translateY(3px); 133 | } 134 | 135 | .tn-button-yellow1 { 136 | cursor: not-allowed; 137 | color: #dd0000; 138 | background-color: #c1a44a; 139 | } 140 | 141 | .tn-button-yellow2 { 142 | cursor: not-allowed; 143 | color: #dd0000; 144 | background-color: #e3c66c; 145 | } 146 | 147 | .tn-button-image { 148 | width: 100%; 149 | height: 100%; 150 | cursor: pointer; 151 | background-color: #ffffff; 152 | } 153 | 154 | .tn-button-span { 155 | display: table-cell; 156 | vertical-align: middle; 157 | } 158 | -------------------------------------------------------------------------------- /www/elements/curve.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | 21 | class Curve { 22 | constructor (start, end) { 23 | this.start = start; 24 | this.end = end; 25 | }; 26 | 27 | render (temp, snap) { 28 | let {start, end} = this; 29 | let color = 'black'; 30 | let width = temp ? 1 : 2; 31 | 32 | let snapPoints = ( 33 | 34 | 35 | 36 | 37 | ); 38 | 39 | return ( 40 | 41 | 42 | {snap ? snapPoints : null} 43 | 44 | ); 45 | }; 46 | 47 | export () { 48 | let {start, end} = this; 49 | start.z = 0.0; 50 | end.z = 0.0; 51 | return {start, end}; 52 | } 53 | }; 54 | 55 | export default Curve; 56 | -------------------------------------------------------------------------------- /www/elements/element.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | class Element { 20 | render (temp) { 21 | throw new Error('The function render() not implemented.'); 22 | }; 23 | 24 | getType () { 25 | return this.type; 26 | }; 27 | }; 28 | 29 | export default Element; 30 | -------------------------------------------------------------------------------- /www/elements/floor.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import Element from './element'; 21 | import ArrayUtils from '../utils/array_utils'; 22 | 23 | class Floor extends Element { 24 | constructor (curves) { 25 | super(); 26 | this.type = 'floor'; 27 | this.curves = curves; 28 | }; 29 | 30 | render (temp, snap) { 31 | let {curves} = this; 32 | return ( 33 | { 34 | ArrayUtils.range(curves.length).map(idx => ( 35 | 36 | {curves[idx].render(temp, snap || idx 38 | )) 39 | } 40 | ); 41 | }; 42 | 43 | export () { 44 | return this.curves.map(({start}) => { 45 | start.z = 0.0; 46 | return start; 47 | }); 48 | }; 49 | }; 50 | 51 | export default Floor; 52 | -------------------------------------------------------------------------------- /www/elements/wall.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import Element from './element'; 21 | 22 | class Wall extends Element { 23 | constructor (curve) { 24 | super(); 25 | this.type = 'wall'; 26 | this.curve = curve; 27 | }; 28 | 29 | render (temp, snap) { 30 | return ( 31 | 32 | {this.curve.render(temp, snap)} 33 | 34 | ); 35 | }; 36 | 37 | export () { 38 | return this.curve.export(); 39 | }; 40 | }; 41 | 42 | export default Wall; 43 | -------------------------------------------------------------------------------- /www/entry/app.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReactDOM from 'react-dom'; 21 | import {Provider} from 'react-redux'; 22 | import store from '../store/store'; 23 | import SketchIt from '../react/sketch_it'; 24 | import bootstrap from 'bootstrap/dist/css/bootstrap.css'; 25 | import style from '../css/style.css'; 26 | 27 | document.addEventListener("DOMContentLoaded", (event) => { 28 | ReactDOM.render( 29 | 30 | 31 | , 32 | document.getElementById('body-div') 33 | ); 34 | }); 35 | -------------------------------------------------------------------------------- /www/generated/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/generated/.gitkeep -------------------------------------------------------------------------------- /www/generated/sketch_it_bundle.js.tmp-browserify-06042699962653919066: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/generated/sketch_it_bundle.js.tmp-browserify-06042699962653919066 -------------------------------------------------------------------------------- /www/generated/sketch_it_bundle.js.tmp-browserify-35300449065229422274: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/generated/sketch_it_bundle.js.tmp-browserify-35300449065229422274 -------------------------------------------------------------------------------- /www/generated/sketch_it_bundle.js.tmp-browserify-67279445076799904157: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/generated/sketch_it_bundle.js.tmp-browserify-67279445076799904157 -------------------------------------------------------------------------------- /www/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /www/mathutils/angle_converter.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | class AngleConverter { 20 | static toRad(deg) { 21 | return (Math.PI * deg) / 180; 22 | }; 23 | 24 | static toDeg(rad) { 25 | return (180 * rad) / Math.PI; 26 | }; 27 | }; 28 | 29 | export default AngleConverter; -------------------------------------------------------------------------------- /www/mathutils/gl_matrix_wrapper.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import {vec2 as Vec2, vec3 as Vec3, mat2d as Mat2d} from 'gl-matrix'; 20 | import almostEqual from 'almost-equal'; 21 | 22 | class Vector { 23 | constructor (x, y) { 24 | x = x || 0; 25 | y = y || 0; 26 | this.v = Vec2.fromValues(x, y); 27 | }; 28 | 29 | static create (x, y) { 30 | return new Vector(x, y); 31 | }; 32 | 33 | clone () { 34 | let r = Vector.create(); 35 | Vec2.copy(r.v, this.v); 36 | return r; 37 | }; 38 | 39 | add (b) { 40 | let r = Vector.create(); 41 | Vec2.add(r.v, this.v, b.v); 42 | return r; 43 | }; 44 | 45 | subtract (b) { 46 | let r = Vector.create(); 47 | Vec2.subtract(r.v, this.v, b.v); 48 | return r; 49 | }; 50 | 51 | scale (val) { 52 | let r = Vector.create(); 53 | Vec2.scale(r.v, this.v, val); 54 | return r; 55 | }; 56 | 57 | negate () { 58 | let r = Vector.create(); 59 | Vec2.negate(r.v, this.v); 60 | return r; 61 | }; 62 | 63 | normalize () { 64 | let r = Vector.create(); 65 | Vec2.normalize(r.v, this.v); 66 | return r; 67 | }; 68 | 69 | min (b) { 70 | let r = Vector.create(); 71 | Vec2.min(r.v, this.v, b.v); 72 | return r; 73 | }; 74 | 75 | max (b) { 76 | let r = Vector.create(); 77 | Vec2.max(r.v, this.v, b.v); 78 | return r; 79 | }; 80 | 81 | distanceFrom (b) { 82 | return Vec2.distance(this.v, b.v); 83 | }; 84 | 85 | angleTo (b) { 86 | let c = Vec3.fromValues(0, 0, 0); 87 | Vec2.cross(c, this.v, b.v); 88 | let sign = c[2] < 0 ? -1 : 1; 89 | let cos = this.dot(b) / (this.length() * b.length()); 90 | if (almostEqual(cos, 1)) cos = 1 - Number.EPSILON; 91 | if (almostEqual(cos, -1)) cos = -1 + Number.EPSILON; 92 | return sign * Math.acos(cos); 93 | }; 94 | 95 | length () { 96 | return Vec2.length(this.v); 97 | }; 98 | 99 | dot (b) { 100 | return Vec2.dot(this.v, b.v); 101 | }; 102 | 103 | asObj () { 104 | return { 105 | x: this.v[0], 106 | y: this.v[1] 107 | }; 108 | }; 109 | 110 | asArr () { 111 | return [ 112 | this.v[0], 113 | this.v[1] 114 | ]; 115 | }; 116 | }; 117 | 118 | class Matrix { 119 | constructor () { 120 | this.m = Mat2d.create(); 121 | }; 122 | 123 | static create () { 124 | return new Matrix(); 125 | }; 126 | 127 | translate (point) { 128 | let r = Matrix.create(); 129 | Mat2d.translate(r.m, this.m, point.v); 130 | return r; 131 | }; 132 | 133 | rotate (rad) { 134 | let r = Matrix.create(); 135 | Mat2d.rotate(r.m, this.m, rad); 136 | return r; 137 | }; 138 | 139 | scale (val1, val2 = val1) { 140 | let r = Matrix.create(); 141 | Mat2d.scale(r.m, this.m, Vec2.fromValues(val1, val2)); 142 | return r; 143 | }; 144 | 145 | invert () { 146 | let r = Matrix.create(); 147 | Mat2d.invert(r.m, this.m); 148 | return r; 149 | }; 150 | 151 | multiply (b) { 152 | let r = Matrix.create(); 153 | Mat2d.multiply(r.m, this.m, b.m); 154 | return r; 155 | }; 156 | 157 | transformPoint (point) { 158 | let r = Vector.create(); 159 | Vec2.transformMat2d(r.v, point.v, this.m); 160 | return r; 161 | }; 162 | 163 | asArr () { 164 | return this.m; 165 | }; 166 | }; 167 | 168 | class MatrixTransformations { 169 | constructor () { 170 | this.t = []; 171 | }; 172 | 173 | static create () { 174 | return new MatrixTransformations(); 175 | }; 176 | 177 | append (trf) { 178 | this.t.push(trf); 179 | }; 180 | 181 | appendFromOther (mt) { 182 | mt.t.forEach(trf => this.append(trf)); 183 | }; 184 | 185 | getMatrix () { 186 | return this.t.reduceRight((matrix, trf)=>trf(matrix), Matrix.create()); 187 | }; 188 | 189 | getInverseMatrix () { 190 | return this.getMatrix().invert(); 191 | } 192 | }; 193 | 194 | export {Vector, Matrix, MatrixTransformations}; 195 | -------------------------------------------------------------------------------- /www/react/canvas.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReduxUtils from '../utils/redux_utils'; 21 | import ArrayUtils from '../utils/array_utils'; 22 | import TransformUtils from '../utils/transform_utils'; 23 | import CanvasEvents from './canvas_events'; 24 | 25 | class Canvas extends React.Component { 26 | constructor(props) { 27 | super(props); 28 | this.getSvg = this.getSvg.bind(this); 29 | }; 30 | 31 | getSvg () { 32 | return this.refs.svg; 33 | }; 34 | 35 | getModelToScreenAsString () { 36 | let matrix = TransformUtils.getModelToScreen(); 37 | return 'matrix( ' + matrix.asArr().join(',') + ')'; 38 | }; 39 | 40 | setCanvasDimensions () { 41 | let {width, height} = this.getSvg().getBoundingClientRect(); 42 | this.props.actions.setCanvasDimensions(width, height); 43 | }; 44 | 45 | componentDidMount () { 46 | this.setCanvasDimensions(); 47 | this.refs.events.register(); 48 | }; 49 | 50 | componentWillUnmount () { 51 | this.refs.events.unregister(); 52 | }; 53 | 54 | renderElements (temp) { 55 | let elementsToRender = temp ? this.props.temporaryElements : this.props.documentElements; 56 | return ArrayUtils.range(elementsToRender.length).map(idx => { 57 | let prefix = temp ? 'temp' : 'doc'; 58 | return ( 59 | 60 | {elementsToRender[idx].render(temp, !temp || idx 62 | ); 63 | }); 64 | }; 65 | 66 | render () { 67 | return ( 68 |
69 | 70 | 71 | {this.renderElements()} 72 | {this.renderElements(true)} 73 | 74 | 75 | 76 |
77 | ); 78 | }; 79 | }; 80 | 81 | let mapStateToProps = (state, ownProps) => { 82 | return { 83 | zoomFactor: state.transformData.zoomFactor, 84 | upVector: state.transformData.upVector, 85 | origin: state.transformData.origin, 86 | canvasDimensions: state.canvasDimensions, 87 | documentElements: state.elementsData.permanent, 88 | temporaryElements: state.elementsData.temporary 89 | }; 90 | }; 91 | 92 | export default ReduxUtils.connect(mapStateToProps, true)(Canvas); 93 | -------------------------------------------------------------------------------- /www/react/canvas_events.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import debounce from 'debounce'; 21 | import {Vector, Matrix} from '../mathutils/gl_matrix_wrapper'; 22 | import TransformUtils from '../utils/transform_utils'; 23 | import store from '../store/store'; 24 | 25 | class CanvasEvents extends React.Component { 26 | constructor(props) { 27 | super(props); 28 | 29 | this.onMouseMove = this.onMouseMove.bind(this); 30 | this.onMouseUp = this.onMouseUp.bind(this); 31 | this.onMouseDown = this.onMouseDown.bind(this); 32 | this.onMouseLeave = this.onMouseLeave.bind(this); 33 | this.onMouseWheel = this.onMouseWheel.bind(this); 34 | this.onKeydown = this.onKeydown.bind(this); 35 | this.onContextMenu = this.onContextMenu.bind(this); 36 | this.onMouseWheelDoc = this.onMouseWheelDoc.bind(this); 37 | this.onResize = this.onResize.bind(this); 38 | this.resetEventDataDebounce = debounce(this.resetEventDataDebounce.bind(this), 200); 39 | this.onMouseDownDebounce = debounce(this.onMouseDownDebounce.bind(this), 200); 40 | }; 41 | 42 | getSvgRect () { 43 | return this.props.getSvg().getBoundingClientRect(); 44 | }; 45 | 46 | getPositionAtEvent (event, snap) { 47 | let boundingRect = this.getSvgRect(); 48 | let pos = { 49 | x: event.clientX - boundingRect.left, 50 | y: event.clientY - boundingRect.top 51 | }; 52 | 53 | if (!snap) 54 | return pos; 55 | 56 | let svg = this.props.getSvg(); 57 | let hitTestRect = svg.createSVGRect(); 58 | 59 | let snapSize = 5; 60 | hitTestRect.x = pos.x - snapSize; 61 | hitTestRect.y = pos.y - snapSize; 62 | hitTestRect.width = snapSize*2; 63 | hitTestRect.height = snapSize*2; 64 | 65 | let nodes = Array.from(svg.getIntersectionList(hitTestRect, null)) 66 | .filter(elem => elem.tagName === 'circle'); 67 | 68 | if (nodes.length === 0) 69 | return pos; 70 | 71 | let posVec = Vector.create(pos.x, pos.y) 72 | let modelToScreen = TransformUtils.getModelToScreen(); 73 | let points = nodes.map(elem => JSON.parse(elem.getAttribute('data-snap'))) 74 | .map(obj => modelToScreen.transformPoint(Vector.create(obj.x, obj.y))) 75 | .sort((pnt1, pnt2) => pnt1.distanceFrom(posVec) < pnt2.distanceFrom(posVec)); 76 | 77 | return points[0].asObj(); 78 | }; 79 | 80 | register () { 81 | let svg = this.props.getSvg(); 82 | svg.addEventListener('mousemove', this.onMouseMove, false); 83 | svg.addEventListener('mouseup', this.onMouseUp, false); 84 | svg.addEventListener('mousedown', this.onMouseDown, false); 85 | svg.addEventListener('mouseleave', this.onMouseLeave, false); 86 | svg.addEventListener('mousewheel', this.onMouseWheel, false); 87 | window.addEventListener('resize', this.onResize); 88 | document.addEventListener('keydown', this.onKeydown, false); 89 | document.addEventListener('mousewheel', this.onMouseWheelDoc, false); 90 | svg.oncontextmenu = this.onContextMenu; 91 | }; 92 | 93 | unregister () { 94 | let svg = this.props.getSvg(); 95 | svg.removeEventListener('mousemove', this.onMouseMove, false); 96 | svg.removeEventListener('mouseup', this.onMouseUp, false); 97 | svg.removeEventListener('mousedown', this.onMouseDown, false); 98 | svg.removeEventListener('mouseleave', this.onMouseLeave, false); 99 | svg.removeEventListener('mousewheel', this.onMouseWheel, false); 100 | window.removeEventListener('resize', this.onResize); 101 | document.removeEventListener('keydown', this.onKeydown, false); 102 | document.removeEventListener('mousewheel', this.onMouseWheelDoc, false); 103 | svg.oncontextmenu = null; 104 | }; 105 | 106 | onContextMenu (event) { 107 | event.preventDefault(); 108 | return false; 109 | }; 110 | 111 | onMouseWheelDoc (event) { 112 | event.preventDefault(); 113 | return false; 114 | }; 115 | 116 | onMouseDownDebounce (event) { 117 | let dataType = 'none'; 118 | let data = {}; 119 | 120 | if (!event.shiftKey) { 121 | dataType = 'pan'; 122 | data.origin = store.getState().transformData.origin; 123 | } else { 124 | dataType = 'rotate'; 125 | data.upVector = store.getState().transformData.upVector; 126 | } 127 | 128 | this.props.actions.setEventData(dataType, this.getPositionAtEvent(event, false), data); 129 | }; 130 | 131 | onMouseDown (event) { 132 | this.onMouseDownDebounce(event); 133 | }; 134 | 135 | onMouseMove (event) { 136 | let data = store.getState().eventData; 137 | if (data.type === 'pan') { 138 | this.handlePan(event); 139 | } else if (data.type === 'rotate') { 140 | this.handleRotate(event); 141 | } else { 142 | this.handleEditorEvent(event, 'move'); 143 | return; 144 | } 145 | }; 146 | 147 | onMouseUp (event) { 148 | this.onMouseDownDebounce.clear(); 149 | 150 | let data = store.getState().eventData; 151 | if (data.type === 'pan') { 152 | this.handlePan(event); 153 | } else if (data.type === 'rotate') { 154 | this.handleRotate(event); 155 | } else { 156 | this.handleEditorEvent(event, 'click'); 157 | return; 158 | } 159 | 160 | this.props.actions.resetEventData(); 161 | }; 162 | 163 | onMouseLeave () { 164 | this.onMouseDownDebounce.clear(); 165 | this.props.actions.resetEventData(); 166 | }; 167 | 168 | onMouseWheel (event) { 169 | event.preventDefault(); 170 | 171 | let dataType = 'none'; 172 | let data = {}; 173 | let wheelDistance = Math.round(event.wheelDeltaY/30); 174 | let zoomFactor = store.getState().transformData.zoomFactor + wheelDistance; 175 | if (zoomFactor < 25) { 176 | zoomFactor = 25; 177 | } else if (zoomFactor > 400) { 178 | zoomFactor = 400; 179 | } 180 | 181 | if (wheelDistance > 0) { 182 | dataType = 'zoomin'; 183 | data.zoomFactor = store.getState().transformData.zoomFactor; 184 | } else if (wheelDistance < 0) { 185 | dataType = 'zoomout'; 186 | data.zoomFactor = store.getState().transformData.zoomFactor; 187 | } 188 | 189 | if (zoomFactor !== store.getState().transformData.zoomFactor) { 190 | this.props.actions.setEventData(dataType, this.getPositionAtEvent(event, false), data); 191 | this.props.actions.setZoomFactor(zoomFactor); 192 | } 193 | this.resetEventDataDebounce(); 194 | return false; 195 | }; 196 | 197 | resetEventDataDebounce () { 198 | this.props.actions.resetEventData(); 199 | }; 200 | 201 | setCanvasDimensions () { 202 | let {width, height} = this.getSvgRect(); 203 | this.props.actions.setCanvasDimensions(width, height); 204 | } 205 | 206 | onResize (e) { 207 | this.resetEventDataDebounce(); 208 | this.setCanvasDimensions(); 209 | }; 210 | 211 | onKeydown (event) { 212 | if (event.keyCode === 13) { 213 | event.preventDefault(); 214 | return false; 215 | } 216 | if (event.keyCode !== 27) { 217 | return; 218 | } 219 | 220 | let data = store.getState().eventData; 221 | if (data.type === 'pan') { 222 | this.cancelPan(); 223 | } else if (data.type === 'rotate') { 224 | this.cancelRotate(); 225 | } 226 | this.props.actions.resetEventData(); 227 | this.finishEditor(); 228 | }; 229 | 230 | createVectorFromObj (vecObj) { 231 | return Vector.create(vecObj.x, vecObj.y); 232 | }; 233 | 234 | createVectorInModelCoordinates (vecObj) { 235 | let screenToModel = TransformUtils.getScreenToModel(); 236 | return screenToModel.transformPoint(this.createVectorFromObj(vecObj)); 237 | }; 238 | 239 | handleRotate (event) { 240 | let data = store.getState().eventData; 241 | let midPoint = this.createVectorInModelCoordinates({x: this.getSvgRect().width*0.5, y: this.getSvgRect().height*0.5}); 242 | let startVec = this.createVectorInModelCoordinates(data.startData.position).subtract(midPoint); 243 | let currentVec = this.createVectorInModelCoordinates(this.getPositionAtEvent(event, false)).subtract(midPoint); 244 | 245 | let matrix = Matrix.create().rotate(-1 * startVec.angleTo(currentVec)); 246 | let upVector = matrix.transformPoint(this.createVectorFromObj(data.startData.upVector)); 247 | this.props.actions.setUpVector(upVector.asObj()); 248 | }; 249 | 250 | cancelRotate () { 251 | let data = store.getState().eventData; 252 | this.props.actions.setUpVector(data.startData.upVector); 253 | }; 254 | 255 | handlePan (event) { 256 | let data = store.getState().eventData; 257 | let startPnt = this.createVectorInModelCoordinates(data.startData.position); 258 | let currentPnt = this.createVectorInModelCoordinates(this.getPositionAtEvent(event, false)); 259 | let moveVec = currentPnt.subtract(startPnt); 260 | 261 | let org = this.createVectorFromObj(data.startData.origin).subtract(moveVec); 262 | this.props.actions.setOrigin(org.asObj()); 263 | }; 264 | 265 | handleEditorEvent (event, type) { 266 | let {element} = store.getState().editorData; 267 | if (element==='none') return; 268 | let point = this.createVectorInModelCoordinates(this.getPositionAtEvent(event, true)).asObj(); 269 | let screenToModel = TransformUtils.getScreenToModel(); 270 | this.props.actions.setEditorEvent({type, point, screenToModel}); 271 | }; 272 | 273 | finishEditor () { 274 | let {element} = store.getState().editorData; 275 | if (element==='none') return; 276 | this.props.actions.setEditorEvent({type: 'done'}); 277 | this.props.actions.resetEditorElem(); 278 | this.props.actions.resetEditorCurve(); 279 | }; 280 | 281 | cancelPan () { 282 | let data = store.getState().eventData; 283 | this.props.actions.setOrigin(data.startData.origin); 284 | }; 285 | 286 | render() { 287 | return null; 288 | }; 289 | }; 290 | 291 | export default CanvasEvents; 292 | -------------------------------------------------------------------------------- /www/react/editor.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReduxUtils from '../utils/redux_utils'; 21 | import ArrayUtils from '../utils/array_utils'; 22 | 23 | class Editor extends React.Component { 24 | componentDidMount () { 25 | this.editorReset(); 26 | }; 27 | 28 | componentDidUpdate () { 29 | if (this.handleEvent()) return; 30 | this.props.actions.setTemporaryElements(this.generateElements(true)); 31 | }; 32 | 33 | componentWillUnmount () { 34 | this.editorReset(); 35 | this.props.actions.resetTemporaryElements(); 36 | }; 37 | 38 | editorReset () { 39 | this.props.actions.resetEditorPoints(); 40 | this.props.actions.resetEditorEvent(); 41 | }; 42 | 43 | handleEvent () { 44 | let {event} = this.props; 45 | if (!event) return false; 46 | 47 | if ((event.type === 'chain') && (!this.props.needsLoop)) { 48 | this.props.actions.addPermanentElements(this.generateElements(false)); 49 | let points = this.props.points.slice(); 50 | this.editorReset(); 51 | this.props.actions.addEditorPoints([points[points.length-1]]); 52 | return true; 53 | } 54 | 55 | if (event.type === 'done') { 56 | this.props.actions.addPermanentElements(this.generateElements(false)); 57 | this.editorReset(); 58 | return true; 59 | } 60 | 61 | if (event.type === 'click') { 62 | this.props.actions.addEditorPoints([event.point]); 63 | if (this.props.points.length === 1) { 64 | this.props.actions.setEditorEvent({type: 'chain'}); 65 | } else { 66 | this.props.actions.resetEditorEvent(); 67 | } 68 | 69 | return true; 70 | } 71 | 72 | return false; 73 | }; 74 | 75 | getPoints (temp) { 76 | let points = this.props.points.slice(); 77 | if (!temp) return points; 78 | 79 | let {event} = this.props; 80 | if (!event) return points; 81 | if (event.type !== 'move') return points; 82 | return points.concat([event.point]); 83 | }; 84 | 85 | generateElements (temp) { 86 | let points = this.getPoints(temp); 87 | return this.props.generateElems(points, temp); 88 | }; 89 | 90 | render () { 91 | return null; 92 | }; 93 | }; 94 | 95 | 96 | let mapStateToProps = (state, ownProps) => { 97 | return { 98 | points: state.editorData.points, 99 | length: state.editorData.points.length, 100 | event: state.editorData.event 101 | }; 102 | }; 103 | 104 | export default ReduxUtils.connect(mapStateToProps, true)(Editor); 105 | -------------------------------------------------------------------------------- /www/react/editor_button.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReduxUtils from '../utils/redux_utils'; 21 | import classNames from 'classnames'; 22 | 23 | class EditorButton extends React.Component { 24 | constructor (props) { 25 | super(props); 26 | this.onClick = this.onClick.bind(this); 27 | }; 28 | 29 | onClick () { 30 | let {type, active} = this.props; 31 | if (active) { 32 | this.props.actions.setEditorEvent({type: 'cancel'}); 33 | this.props.actions.resetEditorElem(); 34 | this.props.actions.resetEditorCurve(); 35 | } 36 | else { 37 | this.props.actions.setEditorElem(type); 38 | } 39 | }; 40 | 41 | render () { 42 | let cls = classNames('editor-button', {'editor-button-active': this.props.active}); 43 | return ( 44 | 45 | ); 46 | }; 47 | }; 48 | 49 | let mapStateToProps = (state, ownProps) => { 50 | return { 51 | active: state.editorData.element === ownProps.type, 52 | }; 53 | }; 54 | 55 | export default ReduxUtils.connect(mapStateToProps, true)(EditorButton); 56 | -------------------------------------------------------------------------------- /www/react/side_bar.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReduxUtils from '../utils/redux_utils'; 21 | import EditorButton from './editor_button'; 22 | import Thumbnail from './thumbnail'; 23 | import Editor from './editor'; 24 | import ElementUtils from '../utils/element_utils'; 25 | 26 | 27 | class SideBar extends React.Component { 28 | 29 | getEditorData () { 30 | return [ 31 | { type: 'wall', needsLoop: false, generateElems: ElementUtils.generateWallsFromPoints }, 32 | { type: 'floor', needsLoop: true, generateElems: ElementUtils.generateFloorsFromPoints }, 33 | { type: 'door', needsLoop: false, generateElems: null }, 34 | { type: 'window', needsLoop: false, generateElems: null }, 35 | { type: 'ceiling', needsLoop: false, generateElems: null }, 36 | { type: 'roof', needsLoop: false, generateElems: null }, 37 | { type: 'component', needsLoop: false, generateElems: null }, 38 | { type: 'column', needsLoop: false, generateElems: null } 39 | ]; 40 | }; 41 | 42 | getActiveEditorComponent () { 43 | let editorData = this.getEditorData().filter(data => data.type === this.props.editorElem); 44 | 45 | if (editorData.length<1) return null; 46 | if (!editorData[0].generateElems) return null; 47 | 48 | let {type, ...propsToPass} = editorData[0]; 49 | return (); 50 | }; 51 | 52 | render () { 53 | return ( 54 | 61 | ); 62 | }; 63 | }; 64 | 65 | let mapStateToProps = (state, ownProps) => { 66 | return { 67 | editorElem: state.editorData.element, 68 | }; 69 | }; 70 | 71 | export default ReduxUtils.connect(mapStateToProps, true)(SideBar); 72 | -------------------------------------------------------------------------------- /www/react/sketch_it.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReduxUtils from '../utils/redux_utils'; 21 | import Canvas from './canvas'; 22 | import Viewer from './viewer'; 23 | import SideBar from './side_bar'; 24 | 25 | let HeaderView = () => ( 26 | 29 | ); 30 | 31 | let FooterView = () => ( 32 | 35 | ); 36 | 37 | class SketchIt extends React.Component { 38 | render () { 39 | return ( 40 |
41 | 42 | {!this.props.showModel ? () : ()} 43 | 44 | 45 |
46 | ); 47 | }; 48 | }; 49 | 50 | let mapStateToProps = (state, ownProps) => { 51 | return { 52 | showModel: state.modelData.showViewer, 53 | }; 54 | }; 55 | 56 | export default ReduxUtils.connect(mapStateToProps)(SketchIt); 57 | -------------------------------------------------------------------------------- /www/react/thumbnail.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReduxUtils from '../utils/redux_utils'; 21 | import RequestUtils from '../utils/request_utils'; 22 | import io from 'socket.io-client'; 23 | import base64 from 'base-64'; 24 | import classNames from 'classnames'; 25 | 26 | class Thumbnail extends React.Component { 27 | constructor (props) { 28 | super(props); 29 | this.onTranslateModel = this.onTranslateModel.bind(this); 30 | this.onShowModel = this.onShowModel.bind(this); 31 | }; 32 | 33 | getThumbnail () { 34 | let qs = {fileId: this.props.modelName}; 35 | return RequestUtils.getRequest('/thumbnail', qs); 36 | }; 37 | 38 | updateThumbnail () { 39 | this.props.actions.resetModelThumbnail(); 40 | this.getThumbnail().then(({thumbnail}) => { 41 | this.props.actions.setModelThumbnail(thumbnail); 42 | }).then(_ => { 43 | let qs = {fileId: this.props.modelName}; 44 | return RequestUtils.getRequest('/download', qs); 45 | }).then(data => { 46 | if (!data.found) return; 47 | this.props.actions.setModelDownloadUrl(data.signedUrl); 48 | }); 49 | }; 50 | 51 | onEmit (socket, msg) { 52 | if (msg === 'workitem') { 53 | this.props.actions.setModelWorkitemDone(true); 54 | } else if (msg === 'thumbnail') { 55 | socket.disconnect(); 56 | this.updateThumbnail(); 57 | } 58 | }; 59 | 60 | onTranslateModel () { 61 | let walls = this.props.documentElements 62 | .filter(elem => elem.type === 'wall') 63 | .map(elem => elem.export()); 64 | let floors = this.props.documentElements 65 | .filter(elem => elem.type === 'floor') 66 | .map(elem => elem.export()); 67 | let elements = {walls, floors}; 68 | 69 | RequestUtils.postRequest('/create', {elements}) 70 | .then(({fileId}) => { 71 | this.props.actions.setModelName(fileId); 72 | this.props.actions.resetModelThumbnail(); 73 | let socket = io.connect('/').on(fileId, msg => this.onEmit(socket, msg)); 74 | }); 75 | }; 76 | 77 | onShowModel () { 78 | this.props.actions.setShowViewer(true); 79 | }; 80 | 81 | getComponent () { 82 | if (!this.props.modelName) { 83 | return (
84 | 85 | Generate Revit model 86 | 87 |
); 88 | } else if (!this.props.modelWorkitemDone) { 89 | return (
90 | 91 | Creating {this.props.modelName} 92 | 93 |
); 94 | } else if (!this.props.modelThumbnail) { 95 | return (
96 | 97 | Publishing {this.props.modelName} 98 | 99 |
); 100 | } else if (!this.props.showModel) { 101 | return (
102 | 103 |
); 104 | } else { 105 | return (
106 | 107 | 108 | 109 |
); 110 | } 111 | 112 | }; 113 | 114 | render () { 115 | return ( 116 |
117 | {this.getComponent()} 118 |
119 | ); 120 | }; 121 | }; 122 | 123 | let mapStateToProps = (state, ownProps) => { 124 | return { 125 | documentElements: state.elementsData.permanent, 126 | modelName: state.modelData.name, 127 | modelWorkitemDone: state.modelData.workitemDone, 128 | modelThumbnail: state.modelData.thumbnail, 129 | modelDownloadUrl: state.modelData.downloadUrl, 130 | showModel: state.modelData.showViewer 131 | }; 132 | }; 133 | 134 | export default ReduxUtils.connect(mapStateToProps, true)(Thumbnail); 135 | -------------------------------------------------------------------------------- /www/react/viewer.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import React from 'react'; 20 | import ReduxUtils from '../utils/redux_utils'; 21 | import RequestUtils from '../utils/request_utils'; 22 | import base64 from 'base-64'; 23 | 24 | class Viewer extends React.Component { 25 | componentDidMount () { 26 | RequestUtils.getRequest('/bucket').then(bucket => { 27 | this.myBucket = bucket; 28 | }), 29 | 30 | RequestUtils.getRequest('/token').then(token => { 31 | let options = { 32 | env: 'AutodeskProduction', 33 | getAccessToken: (onGetAccessToken) => { 34 | var accessToken = token.access_token; 35 | var expireTimeSeconds = 60 * 30; 36 | onGetAccessToken(accessToken, expireTimeSeconds); 37 | } 38 | }; 39 | let documentId = 'urn:' + base64.encode('urn:adsk.objects:os.object:' + this.myBucket + '/' + this.props.modelName); 40 | Autodesk.Viewing.Initializer(options, () => { 41 | let viewerApp = new Autodesk.Viewing.ViewingApplication('forge-viewer'); 42 | viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D); 43 | viewerApp.loadDocument(documentId, (doc) => { 44 | let viewables = viewerApp.bubble.search({'type':'geometry'}); 45 | if (viewables.length === 0) { 46 | console.error('Document contains no viewables.'); 47 | return; 48 | } 49 | viewerApp.selectItem(viewables[0], null, console.error); 50 | }, console.error); 51 | }); 52 | }); 53 | }; 54 | 55 | render () { 56 | return ( 57 |
58 |
59 | 62 |
63 | ); 64 | }; 65 | }; 66 | 67 | let mapStateToProps = (state, ownProps) => { 68 | return { 69 | modelName: state.modelData.name 70 | }; 71 | }; 72 | 73 | export default ReduxUtils.connect(mapStateToProps)(Viewer); 74 | -------------------------------------------------------------------------------- /www/res/ceiling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/ceiling.png -------------------------------------------------------------------------------- /www/res/column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/column.png -------------------------------------------------------------------------------- /www/res/component.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/component.png -------------------------------------------------------------------------------- /www/res/door.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/door.png -------------------------------------------------------------------------------- /www/res/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/favicon.png -------------------------------------------------------------------------------- /www/res/floor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/floor.png -------------------------------------------------------------------------------- /www/res/forge-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/forge-logo.png -------------------------------------------------------------------------------- /www/res/roof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/roof.png -------------------------------------------------------------------------------- /www/res/wall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/wall.png -------------------------------------------------------------------------------- /www/res/window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Autodesk-Forge/forge-sketchit-revit/8f5394dabbe05dc2c1561b435b7c4fb11622ddf5/www/res/window.png -------------------------------------------------------------------------------- /www/store/action_creators.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import { createAction } from 'redux-actions'; 20 | import * as ActionTypes from './action_types'; 21 | 22 | export let addPermanentElements = createAction(ActionTypes.ADD_PERMANENT_ELEMENTS); 23 | export let resetPermanentElements = createAction(ActionTypes.RESET_PERMANENT_ELEMENTS); 24 | 25 | export let setTemporaryElements = createAction(ActionTypes.SET_TEMPORARY_ELEMENTS); 26 | export let resetTemporaryElements = createAction(ActionTypes.RESET_TEMPORARY_ELEMENTS); 27 | 28 | export let setEditorElem = createAction(ActionTypes.SET_EDITOR_ELEM); 29 | export let resetEditorElem = createAction(ActionTypes.RESET_EDITOR_ELEM); 30 | 31 | export let setEditorCurve = createAction(ActionTypes.SET_EDITOR_CURVE); 32 | export let resetEditorCurve = createAction(ActionTypes.RESET_EDITOR_CURVE); 33 | 34 | export let addEditorPoints = createAction(ActionTypes.ADD_EDITOR_POINTS); 35 | export let resetEditorPoints = createAction(ActionTypes.RESET_EDITOR_POINTS); 36 | 37 | export let setEditorEvent = createAction(ActionTypes.SET_EDITOR_EVENT); 38 | export let resetEditorEvent = createAction(ActionTypes.RESET_EDITOR_EVENT); 39 | 40 | 41 | let eventDataMap = (type, position, otherData = {}) => { 42 | let startData = Object.assign(otherData, {position}); 43 | return { type, startData }; 44 | }; 45 | export let setEventData = createAction(ActionTypes.SET_EVENT_DATA, eventDataMap); 46 | export let resetEventData = createAction(ActionTypes.RESET_EVENT_DATA); 47 | 48 | export let setZoomFactor = createAction(ActionTypes.SET_ZOOM_FACTOR); 49 | export let resetZoomFactor = createAction(ActionTypes.RESET_ZOOM_FACTOR); 50 | 51 | export let setUpVector = createAction(ActionTypes.SET_UP_VECTOR); 52 | export let resetUpVector = createAction(ActionTypes.RESET_UP_VECTOR); 53 | 54 | export let setOrigin = createAction(ActionTypes.SET_ORIGIN); 55 | export let resetOrigin = createAction(ActionTypes.RESET_ORIGIN); 56 | 57 | let canvasDimensionsMap = (width, height) => { 58 | return {width, height}; 59 | }; 60 | export let setCanvasDimensions = createAction(ActionTypes.SET_CANVAS_DIMENSIONS, canvasDimensionsMap); 61 | 62 | 63 | export let setShowViewer = createAction(ActionTypes.SET_SHOW_VIEWER); 64 | export let resetShowViewer = createAction(ActionTypes.RESET_SHOW_VIEWER); 65 | 66 | export let setModelName = createAction(ActionTypes.SET_MODEL_NAME); 67 | export let resetModelName = createAction(ActionTypes.RESET_MODEL_NAME); 68 | 69 | export let setModelWorkitemDone = createAction(ActionTypes.SET_MODEL_WORKITEM_DONE); 70 | export let resetModelWorkitemDone = createAction(ActionTypes.RESET_MODEL_WORKITEM_DONE); 71 | 72 | export let setModelThumbnail = createAction(ActionTypes.SET_MODEL_THUMBNAIL); 73 | export let resetModelThumbnail = createAction(ActionTypes.RESET_MODEL_THUMBNAIL); 74 | 75 | export let setModelDownloadUrl = createAction(ActionTypes.SET_MODEL_DOWNLOADURL); 76 | export let resetModelDownloadUrl = createAction(ActionTypes.RESET_MODEL_DOWNLOADURL); 77 | -------------------------------------------------------------------------------- /www/store/action_types.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | export const ADD_PERMANENT_ELEMENTS = 'ADD_PERMANENT_ELEMENTS'; 20 | export const RESET_PERMANENT_ELEMENTS = 'RESET_PERMANENT_ELEMENTS'; 21 | export const SET_TEMPORARY_ELEMENTS = 'SET_TEMPORARY_ELEMENTS'; 22 | export const RESET_TEMPORARY_ELEMENTS = 'RESET_TEMPORARY_ELEMENTS'; 23 | export const SET_EDITOR_ELEM = 'SET_EDITOR_ELEM'; 24 | export const RESET_EDITOR_ELEM = 'RESET_EDITOR_ELEM'; 25 | export const SET_EDITOR_CURVE = 'SET_EDITOR_CURVE'; 26 | export const RESET_EDITOR_CURVE = 'RESET_EDITOR_CURVE'; 27 | export const ADD_EDITOR_POINTS = 'ADD_EDITOR_POINTS'; 28 | export const RESET_EDITOR_POINTS = 'RESET_EDITOR_POINTS'; 29 | export const SET_EDITOR_EVENT = 'SET_EDITOR_EVENT'; 30 | export const RESET_EDITOR_EVENT = 'RESET_EDITOR_EVENT'; 31 | export const SET_EVENT_DATA = 'SET_EVENT_DATA'; 32 | export const RESET_EVENT_DATA = 'RESET_EVENT_DATA'; 33 | export const SET_ZOOM_FACTOR = 'SET_ZOOM_FACTOR'; 34 | export const RESET_ZOOM_FACTOR = 'RESET_ZOOM_FACTOR'; 35 | export const SET_UP_VECTOR = 'SET_UP_VECTOR'; 36 | export const RESET_UP_VECTOR = 'RESET_UP_VECTOR'; 37 | export const SET_ORIGIN = 'SET_ORIGIN'; 38 | export const RESET_ORIGIN = 'RESET_ORIGIN'; 39 | export const SET_CANVAS_DIMENSIONS = 'SET_CANVAS_DIMENSIONS'; 40 | export const SET_SHOW_VIEWER = 'SET_SHOW_VIEWER'; 41 | export const RESET_SHOW_VIEWER = 'RESET_SHOW_VIEWER'; 42 | export const SET_MODEL_NAME = 'SET_MODEL_NAME'; 43 | export const RESET_MODEL_NAME = 'RESET_MODEL_NAME'; 44 | export const SET_MODEL_WORKITEM_DONE = 'SET_MODEL_WORKITEM_DONE'; 45 | export const RESET_MODEL_WORKITEM_DONE = 'RESET_MODEL_WORKITEM_DONE'; 46 | export const SET_MODEL_THUMBNAIL = 'SET_MODEL_THUMBNAIL'; 47 | export const RESET_MODEL_THUMBNAIL = 'RESET_MODEL_THUMBNAIL'; 48 | export const SET_MODEL_DOWNLOADURL = 'SET_MODEL_DOWNLOADURL'; 49 | export const RESET_MODEL_DOWNLOADURL = 'RESET_MODEL_DOWNLOADURL'; 50 | -------------------------------------------------------------------------------- /www/store/reducers.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import {combineReducers} from 'redux'; 20 | import {handleActions} from 'redux-actions'; 21 | import * as ActionTypes from './action_types'; 22 | 23 | let createReducer = (actionsMap, defaultState) => { 24 | let actionsMapLocal = {}; 25 | Object.keys(actionsMap).map((key) => { 26 | let val = actionsMap[key]; 27 | if (val === 'default') 28 | actionsMapLocal[key] = (state, action) => defaultState; 29 | else if (val === 'payload') 30 | actionsMapLocal[key] = (state, action) => action.payload; 31 | else 32 | actionsMapLocal[key] = val; 33 | }); 34 | return handleActions(actionsMapLocal, defaultState); 35 | }; 36 | 37 | let permanentElementsReducer = createReducer({ 38 | [ActionTypes.ADD_PERMANENT_ELEMENTS]: (state, action) => state.concat(action.payload), 39 | [ActionTypes.RESET_PERMANENT_ELEMENTS]: 'default' 40 | }, []); 41 | 42 | let temporaryElementsReducer = createReducer({ 43 | [ActionTypes.SET_TEMPORARY_ELEMENTS]: 'payload', 44 | [ActionTypes.RESET_TEMPORARY_ELEMENTS]: 'default' 45 | }, []); 46 | 47 | let editorElemReducer = createReducer({ 48 | [ActionTypes.SET_EDITOR_ELEM]: 'payload', 49 | [ActionTypes.RESET_EDITOR_ELEM]: 'default' 50 | }, 'none'); 51 | 52 | let editorCurveReducer = createReducer({ 53 | [ActionTypes.SET_EDITOR_CURVE]: 'payload', 54 | [ActionTypes.RESET_EDITOR_CURVE]: 'default' 55 | }, 'none'); 56 | 57 | let editorPointsReducer = createReducer({ 58 | [ActionTypes.ADD_EDITOR_POINTS]: (state, action) => state.concat(action.payload), 59 | [ActionTypes.RESET_EDITOR_POINTS]: 'default' 60 | }, []); 61 | 62 | let editorEventReducer = createReducer({ 63 | [ActionTypes.SET_EDITOR_EVENT]: 'payload', 64 | [ActionTypes.RESET_EDITOR_EVENT]: 'default' 65 | }, null); 66 | 67 | let eventDataReducer = createReducer({ 68 | [ActionTypes.SET_EVENT_DATA]: 'payload', 69 | [ActionTypes.RESET_EVENT_DATA]: 'default' 70 | }, {type: 'none', startData: null}); 71 | 72 | let zoomFactorReducer = createReducer({ 73 | [ActionTypes.SET_ZOOM_FACTOR]: 'payload', 74 | [ActionTypes.RESET_ZOOM_FACTOR]: 'default' 75 | }, 100); 76 | 77 | let upVectorReducer = createReducer({ 78 | [ActionTypes.SET_UP_VECTOR]: 'payload', 79 | [ActionTypes.RESET_UP_VECTOR]: 'default' 80 | }, {x:0, y:1}); 81 | 82 | let originReducer = createReducer({ 83 | [ActionTypes.SET_ORIGIN]: 'payload', 84 | [ActionTypes.RESET_ORIGIN]: 'default' 85 | }, {x:0, y:0}); 86 | 87 | let canvasDimensionsReducer = createReducer({ 88 | [ActionTypes.SET_CANVAS_DIMENSIONS]: 'payload' 89 | }, {width:-1, height:-1}); 90 | 91 | let showViewerReducer = createReducer({ 92 | [ActionTypes.SET_SHOW_VIEWER]: 'payload', 93 | [ActionTypes.RESET_SHOW_VIEWER]: 'default' 94 | }, false); 95 | 96 | let modelNameReducer = createReducer({ 97 | [ActionTypes.SET_MODEL_NAME]: 'payload', 98 | [ActionTypes.RESET_MODEL_NAME]: 'default' 99 | }, ''); 100 | 101 | let workitemDoneReducer = createReducer({ 102 | [ActionTypes.SET_MODEL_WORKITEM_DONE]: 'payload', 103 | [ActionTypes.RESET_MODEL_WORKITEM_DONE]: 'default' 104 | }, false); 105 | 106 | let modelThumbnailReducer = createReducer({ 107 | [ActionTypes.SET_MODEL_THUMBNAIL]: 'payload', 108 | [ActionTypes.RESET_MODEL_THUMBNAIL]: 'default' 109 | }, ''); 110 | 111 | let modelDownloadUrlReducer = createReducer({ 112 | [ActionTypes.SET_MODEL_DOWNLOADURL]: 'payload', 113 | [ActionTypes.RESET_MODEL_DOWNLOADURL]: 'default' 114 | }, ''); 115 | 116 | let reducers = combineReducers({ 117 | elementsData: combineReducers({ 118 | permanent: permanentElementsReducer, 119 | temporary: temporaryElementsReducer 120 | }), 121 | 122 | eventData: eventDataReducer, 123 | 124 | editorData: combineReducers({ 125 | element: editorElemReducer, 126 | curve: editorCurveReducer, 127 | points: editorPointsReducer, 128 | event: editorEventReducer 129 | }), 130 | 131 | transformData: combineReducers({ 132 | zoomFactor: zoomFactorReducer, 133 | upVector: upVectorReducer, 134 | origin: originReducer, 135 | }), 136 | 137 | canvasDimensions: canvasDimensionsReducer, 138 | 139 | modelData: combineReducers({ 140 | showViewer: showViewerReducer, 141 | name: modelNameReducer, 142 | workitemDone: workitemDoneReducer, 143 | thumbnail: modelThumbnailReducer, 144 | downloadUrl: modelDownloadUrlReducer 145 | }) 146 | }); 147 | 148 | export default reducers; 149 | -------------------------------------------------------------------------------- /www/store/store.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////// 2 | // Copyright (c) Autodesk, Inc. All rights reserved 3 | // Written by Forge Partner Development 4 | // 5 | // Permission to use, copy, modify, and distribute this software in 6 | // object code form for any purpose and without fee is hereby granted, 7 | // provided that the above copyright notice appears in all copies and 8 | // that both that copyright notice and the limited warranty and 9 | // restricted rights notice below appear in all supporting 10 | // documentation. 11 | // 12 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 13 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 14 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. 15 | // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 16 | // UNINTERRUPTED OR ERROR FREE. 17 | ///////////////////////////////////////////////////////////////////// 18 | 19 | import {createStore} from 'redux'; 20 | import reducers from './reducers'; 21 | 22 | let store = createStore(reducers); 23 | 24 | export default store; 25 | -------------------------------------------------------------------------------- /www/utils/array_utils.js: -------------------------------------------------------------------------------- 1 | class ArrayUtils { 2 | static range (num) { 3 | return Array.from(Array(num).keys()); 4 | }; 5 | 6 | static orderedRange (num, last) { 7 | let arr = this.range(num); 8 | if (last < 0) return arr; 9 | if (last >= num) return arr; 10 | return arr.concat(arr.splice(last, 1)); 11 | } 12 | }; 13 | 14 | export default ArrayUtils; -------------------------------------------------------------------------------- /www/utils/element_utils.js: -------------------------------------------------------------------------------- 1 | import Curve from '../elements/curve'; 2 | import Wall from '../elements/wall'; 3 | import Floor from '../elements/floor'; 4 | import ArrayUtils from './array_utils'; 5 | 6 | class ElementUtils { 7 | static getCurvesFromPoints (points) { 8 | let length = points.length; 9 | if (length < 2) return []; 10 | return ArrayUtils.range(length-1).map(idx => new Curve(points[idx], points[idx+1])); 11 | }; 12 | 13 | static generateWallsFromPoints (points, temp) { 14 | let length = points.length; 15 | if (length < 2) return []; 16 | return ElementUtils.getCurvesFromPoints(points).map(curve => new Wall(curve)); 17 | }; 18 | 19 | static generateFloorsFromPoints (points, temp) { 20 | let length = points.length; 21 | if (length < 2) return []; 22 | 23 | if (length < 3) 24 | { 25 | if (temp) 26 | return ElementUtils.generateWallsFromPoints(points, temp); 27 | else 28 | return []; 29 | } 30 | 31 | let first = points[0]; 32 | return [new Floor(ElementUtils.getCurvesFromPoints(points.concat([first])))]; 33 | }; 34 | }; 35 | 36 | export default ElementUtils; 37 | -------------------------------------------------------------------------------- /www/utils/redux_utils.js: -------------------------------------------------------------------------------- 1 | import {connect} from 'react-redux'; 2 | import {bindActionCreators} from 'redux'; 3 | import * as ActionCreators from '../store/action_creators'; 4 | 5 | class ReduxUtils { 6 | static connect (mapStateToProps, shouldMapDispatchToProps=false) { 7 | return connect(mapStateToProps, shouldMapDispatchToProps ? this.mapDispatchToProps : null); 8 | }; 9 | 10 | static mapDispatchToProps = (dispatch) => { 11 | return { actions: bindActionCreators(ActionCreators, dispatch) }; 12 | }; 13 | 14 | static dispatchFunc (observerFunc) { 15 | return (dispatch, currentState, previousState) => { 16 | let {actions} = this.mapDispatchToProps(dispatch); 17 | observerFunc(actions, currentState, previousState); 18 | }; 19 | }; 20 | }; 21 | 22 | export default ReduxUtils; 23 | -------------------------------------------------------------------------------- /www/utils/request_utils.js: -------------------------------------------------------------------------------- 1 | import request from 'request'; 2 | import isUrl from 'is-url'; 3 | import {promisify} from 'es6-promisify'; 4 | 5 | 6 | class RequestUtils { 7 | static getUrl (route) { 8 | return isUrl(route) ? route : window.location.origin + route; 9 | }; 10 | 11 | static getRequest (route, payload) { 12 | let url = this.getUrl(route); 13 | return promisify(request)({url, qs: payload}).then((httpResponse) => { 14 | return JSON.parse(httpResponse.body); 15 | }); 16 | }; 17 | 18 | static postRequest (route, payload) { 19 | let url = this.getUrl(route); 20 | return promisify(request.post)({url, json: payload}).then((httpResponse) => { 21 | return httpResponse.body; 22 | }); 23 | }; 24 | }; 25 | 26 | export default RequestUtils; -------------------------------------------------------------------------------- /www/utils/transform_utils.js: -------------------------------------------------------------------------------- 1 | import {Vector, MatrixTransformations} from '../mathutils/gl_matrix_wrapper'; 2 | import store from '../store/store'; 3 | 4 | class TransformUtils { 5 | static getModelToScreen () { 6 | let matrixTransforms = MatrixTransformations.create(); 7 | let {transformData, canvasDimensions} = store.getState(); 8 | let {origin, zoomFactor, upVector} = transformData; 9 | 10 | let negOrg = Vector.create(origin.x, origin.y).negate(); 11 | matrixTransforms.append(m => m.translate(negOrg)); 12 | matrixTransforms.append(m => m.scale(zoomFactor*0.01)); 13 | matrixTransforms.append(m => m.scale(10)); // Pixel to units. 14 | 15 | let upVec = Vector.create(upVector.x, upVector.y); 16 | matrixTransforms.append(m => m.rotate(upVec.angleTo(Vector.create(0, 1)))); 17 | 18 | matrixTransforms.append(m => m.scale(1, -1)); 19 | let midRect = Vector.create(canvasDimensions.width, canvasDimensions.height).scale(0.5); 20 | matrixTransforms.append(m => m.translate(midRect)); 21 | 22 | return matrixTransforms.getMatrix(); 23 | }; 24 | 25 | static getScreenToModel () { 26 | return TransformUtils.getModelToScreen().invert(); 27 | }; 28 | }; 29 | 30 | export default TransformUtils; --------------------------------------------------------------------------------