for the boyz
11
.gh-sync.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"debug": false,
|
||||||
|
"matching": [
|
||||||
|
"*.json",
|
||||||
|
"*.md",
|
||||||
|
"*.yaml",
|
||||||
|
"*.csv",
|
||||||
|
"*.xls",
|
||||||
|
"*.html"
|
||||||
|
]
|
||||||
|
}
|
||||||
47
.gitignore
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
*.pdb
|
||||||
|
*.cache
|
||||||
|
|
||||||
|
npm-debug.log*
|
||||||
|
yarn.lock
|
||||||
|
yarn-error.log
|
||||||
|
credentials.json
|
||||||
|
gcreds.json
|
||||||
|
token.json
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules
|
||||||
|
jspm_packages
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
5
.npmignore
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
tests
|
||||||
|
src
|
||||||
|
ref
|
||||||
|
web
|
||||||
|
scripts
|
||||||
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org>
|
||||||
138
README.md
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# OSR CAD Tools
|
||||||
|
|
||||||
|
This is a CLI(CommandLineInterface) toolset to convert 3D files, using Solidworks and other software.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
1. [Node-JS](https://nodejs.org/en/download/)
|
||||||
|
2. Optional: install [Git](https://git-scm.com/downloads) (Make sure you enable Linux tools on Windows console)
|
||||||
|
3. Solidworks 2020. In case you are using another version, please find on your disc 'SolidWorks.Interop.sldworks.dll' and replace the one in [./sw](https://gitlab.com/plastichub/osr/osr-convert-cad/tree/main/sw)
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
|
||||||
|
git clone https://gitlab.com/plastichub/osr/osr-convert-cad.git
|
||||||
|
cd osr-convert-cad
|
||||||
|
npm i
|
||||||
|
|
||||||
|
# or globally (recommended)
|
||||||
|
|
||||||
|
npm i @plastichub/osr-cad -g
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Open a terminal and run this:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad --help
|
||||||
|
```
|
||||||
|
|
||||||
|
See more in [./docs/Examples.md](./docs/Examples.md) and [./docs/Integration.md](./docs/Integration.md)
|
||||||
|
|
||||||
|
### References - Development
|
||||||
|
|
||||||
|
- [site:Solidworks API basics - examples](https://www.codestack.net/labs/solidworks/)
|
||||||
|
- [site:Rhino-API](https://developer.rhino3d.com/api/RhinoCommon/html/R_Project_RhinoCommon.htm)
|
||||||
|
- [site:Solidworks Reverse Decoder](http://heybryan.org/solidworks_file_format.html)
|
||||||
|
- [sw interop - component - API ](https://help.solidworks.com/2019/English/api/swdocmgrapi/Get_Current_Name_of_Configuration_of_Suppressed_Component_Example_CSharp.htm)
|
||||||
|
|
||||||
|
|
||||||
|
## Todos
|
||||||
|
|
||||||
|
- [x] Select default views via CLI Argument
|
||||||
|
- [ - Arg: Skip suppressed | hidden (difficult since it's out of part file scope, check explorer api ) | dry mode
|
||||||
|
- [x] Arg: Overwrite files
|
||||||
|
- [-] Arg: skip non OSR parts
|
||||||
|
- [-] Arg: displaymode : wireframe, shaded, ... (see [SW Docs](http://help.solidworks.com/2017/english/api/sldworksapi/solidworks.interop.sldworks~solidworks.interop.sldworks.iview~setdisplaymode3.html))
|
||||||
|
- [-] report
|
||||||
|
- [x] export as lib
|
||||||
|
- [-] Multi view (trainings data for @plastichub/part-detector)
|
||||||
|
- [-] Speed: use same instance for multiple exports
|
||||||
|
- [ ] Context Menu Shell Extension (@osr-tools)
|
||||||
|
- [-] Local/Global config (=>osrl)
|
||||||
|
- [ ] emit/merge authors from components in target artefact
|
||||||
|
- [.] Add CLI Arg Path variables
|
||||||
|
- [-] json-path for glob patterns
|
||||||
|
- [-] bracket expansion
|
||||||
|
- [ ] Report templates (=> @osrl)
|
||||||
|
- [ ] xls
|
||||||
|
- [ ] md
|
||||||
|
- [ ] txt
|
||||||
|
- [-] Plugin interface for custom format (chained) => osrl
|
||||||
|
- [x] Conversions
|
||||||
|
- [x] STEP -> SLDPRT (via xcad->fc->fw)
|
||||||
|
- [x] any -> 3dxml (osrl!)
|
||||||
|
- [x] any -> html (via edrawings)
|
||||||
|
|
||||||
|
- [ ] Structural
|
||||||
|
- [ ] support pipes, eg: intermediate formats
|
||||||
|
- [-] add pre, post and content filters, as pipes
|
||||||
|
- [-] plugins
|
||||||
|
- [-] integrate osrl
|
||||||
|
- [ ] omit format options in --help
|
||||||
|
- [ ] omit possible conversions in ```info``
|
||||||
|
- [ ] per in and out args
|
||||||
|
- [ ] global
|
||||||
|
- [ ] Cache hash fuckery : integrate options in integrity
|
||||||
|
- [ ] external cache directory
|
||||||
|
|
||||||
|
### Commands - Todos
|
||||||
|
|
||||||
|
- [x] Solidworks
|
||||||
|
- [-] Set system wide options for JPG output
|
||||||
|
- [-] Set system wide options for PDF output
|
||||||
|
- [ ] Directory index (=>osrl)
|
||||||
|
- [ ] arg: local HTML path/dir offset
|
||||||
|
- [ ] arg: generate UNC paths
|
||||||
|
- [ ] format: PDF
|
||||||
|
- [-] arg: sw drawing/BOMs to CSV/xls
|
||||||
|
- [ ] Part/Sub-Assembly web(&local) compilation/index (=>osrl)
|
||||||
|
- [-] Web directory ([xeokit](https://gitlab.com/plastichub/osr/xeokit-sdk))
|
||||||
|
- [-] Git hook, check components & references
|
||||||
|
|
||||||
|
### Lib - Todos
|
||||||
|
|
||||||
|
- [ ] SW: 4 view single image
|
||||||
|
- [ ] Incorrect JPG output with sw2020
|
||||||
|
|
||||||
|
### Utils
|
||||||
|
|
||||||
|
- [Batch Export to HTML via EDrawings OCX](ref/edrawings-api/BatchExportHTML)
|
||||||
|
|
||||||
|
- For SOLIDWORKS Document Manager API, please check the intro [here](https://www.codestack.net/solidworks-document-manager-api/) which leads to [https://xcad.xarial.com/]. Their actual API code is now at [./ref/xcad](./ref/xcad). Please check also [xcad basics on YouTube](https://www.youtube.com/watch?v=dLjlTYYeMpo)
|
||||||
|
|
||||||
|
### Resources
|
||||||
|
|
||||||
|
- [SOLIDWORKS](https://www.linkedin.com/company/solidworks?trk=public_post_share-update_update-text)
|
||||||
|
- [SW Model Error Ref](https://help.solidworks.com/2019/english/api/swconst/SO_Messages.htm)
|
||||||
|
- API Help Files [https://lnkd.in/d9QX6wvS](https://lnkd.in/d9QX6wvS?trk=public_post_share-update_update-text)
|
||||||
|
- Free API Books, Macros and Utilities by [Luke Malpass](https://uk.linkedin.com/in/angelsix?trk=public_post_share-update_update-text) - [https://lnkd.in/d8EbSDiB](https://lnkd.in/d8EbSDiB?trk=public_post_share-update_update-text)
|
||||||
|
- Video Tutorials (first few lessons are free and rest are paid) by [SolidProfessor](https://www.linkedin.com/company/solidprofessor?trk=public_post_share-update_update-text)
|
||||||
|
- [https://lnkd.in/d6bJew-z](https://lnkd.in/d6bJew-z?trk=public_post_share-update_update-text)
|
||||||
|
- [https://lnkd.in/dAv2366P](https://lnkd.in/dAv2366P?trk=public_post_share-update_update-text)
|
||||||
|
- [Artem Taturevych](https://au.linkedin.com/in/artem-taturevych?trk=public_post_share-update_update-text)’s free SOLIDWORKS Goodies
|
||||||
|
- [http://www.codestack.net](http://www.codestack.net/?trk=public_post_share-update_update-text)/
|
||||||
|
- [Lenny Kikstra](https://www.linkedin.com/in/lennyworks?trk=public_post_share-update_update-text)
|
||||||
|
- free SOLIDWORKS Goodies [https://lnkd.in/d6RJfCuZ](https://lnkd.in/d6RJfCuZ?trk=public_post_share-update_update-text)
|
||||||
|
- [Roland Schwarz](https://www.linkedin.com/in/rolandschwarz?trk=public_post_share-update_update-text)
|
||||||
|
- free SOLIDWORKS Goodies [https://lnkd.in/dSiq6r6h](https://lnkd.in/dSiq6r6h?trk=public_post_share-update_update-text)
|
||||||
|
- Video Tutorials (free and paid with macros library) by [Keith Rice](https://www.linkedin.com/in/keitharice?trk=public_post_share-update_update-text)
|
||||||
|
- [https://www.cadsharp.com](https://www.cadsharp.com/?trk=public_post_share-update_update-text)
|
||||||
|
- MySolidWorks Video Training (paid) [https://lnkd.in/dpXnNBsy](https://lnkd.in/dpXnNBsy?trk=public_post_share-update_update-text)
|
||||||
|
- SOLIDWORKS Free Macros at Cadforum: [https://lnkd.in/d4W63jBX](https://lnkd.in/d4W63jBX?trk=public_post_share-update_update-text)
|
||||||
|
- SOLIDWORKS Free Macros at 3D Content Central: [https://lnkd.in/d4zVEfhh](https://lnkd.in/d4zVEfhh?trk=public_post_share-update_update-text) • SOLIDWORKS Customization eBook using VB.Net (paid) by [Tushar Suradkar](https://in.linkedin.com/in/tusharsuradkar?trk=public_post_share-update_update-text)
|
||||||
|
- [https://lnkd.in/dD_sn3ai](https://lnkd.in/dD_sn3ai?trk=public_post_share-update_update-text)
|
||||||
|
- [Mike Spens](https://www.linkedin.com/in/mikespens?trk=public_post_share-update_update-text)
|
||||||
|
- API resources [http://www.solidapi.com](http://www.solidapi.com/?trk=public_post_share-update_update-text)/ and book (paid) by him "Automating SOLIDWORKS Using Macros" ([https://amzn.to/3nWOmYn](https://amzn.to/3nWOmYn?trk=public_post_share-update_update-text))
|
||||||
|
- Stefan Berlitz's free SOLIDWORKS Goodies [https://lnkd.in/dMCmnX6h](https://lnkd.in/dMCmnX6h?trk=public_post_share-update_update-text)
|
||||||
|
- SOLIDWORKS users on active subscription also have access to two API SolidPractices available from [https://lnkd.in/d9VD3f5A](https://lnkd.in/d9VD3f5A?trk=public_post_share-update_update-text)
|
||||||
|
- Free SOLIDWORKS API [VBA + C#] Tutorials from [Prashant Baher](https://in.linkedin.com/in/prashantbaher?trk=public_post_share-update_update-text) [https://thecadcoder.com](https://thecadcoder.com/?trk=public_post_share-update_update-text)/
|
||||||
|
- Video Tutorials by [GoEngineer](https://www.linkedin.com/company/goengineer?trk=public_post_share-update_update-text) [https://lnkd.in/gfBKmeU4](https://lnkd.in/gfBKmeU4?trk=public_post_share-update_update-text)
|
||||||
|
- SOLIDWORKS forums to ask/find great solutions/macros 3DSwym SOLIDWORKS User Forum: [https://lnkd.in/dFG_isCJ](https://lnkd.in/dFG_isCJ?trk=public_post_share-update_update-text)
|
||||||
|
- Eng-Tips: [https://lnkd.in/dgspDQ-H](https://lnkd.in/dgspDQ-H?trk=public_post_share-update_update-text)
|
||||||
|
- CadOverFlow: [https://lnkd.in/d3bFWXUb](https://lnkd.in/d3bFWXUb?trk=public_post_share-update_update-text)
|
||||||
|
|
||||||
16
_cli.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.defaults = void 0;
|
||||||
|
// tweaks and handlers
|
||||||
|
exports.defaults = () => {
|
||||||
|
// default command
|
||||||
|
const DefaultCommand = 'summary';
|
||||||
|
if (process.argv.length === 2) {
|
||||||
|
process.argv.push(DefaultCommand);
|
||||||
|
}
|
||||||
|
// currently no default handler, display only :
|
||||||
|
process.on('unhandledRejection', (reason) => {
|
||||||
|
console.error('Unhandled rejection, reason: ', reason);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=_cli.js.map
|
||||||
1
_cli.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"_cli.js","sourceRoot":"","sources":["src/_cli.ts"],"names":[],"mappings":";;;AAAA,sBAAsB;AACT,QAAA,QAAQ,GAAG,GAAG,EAAE;IACzB,kBAAkB;IAClB,MAAM,cAAc,GAAG,SAAS,CAAC;IACjC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;QAC3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;KACrC;IAED,+CAA+C;IAC/C,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAc,EAAE,EAAE;QAChD,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACP,CAAC,CAAC"}
|
||||||
206
argv.js
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.sanitize = exports.sanitizeSingle = exports.defaultOptions = void 0;
|
||||||
|
const path = require("path");
|
||||||
|
const _1 = require("./");
|
||||||
|
const primitives_1 = require("./lib/common/primitives");
|
||||||
|
const core_1 = require("@plastichub/core");
|
||||||
|
const osr_cli_commons_1 = require("@plastichub/osr-cli-commons");
|
||||||
|
const read_1 = require("@plastichub/fs/read");
|
||||||
|
// default options for all commands
|
||||||
|
exports.defaultOptions = (yargs) => {
|
||||||
|
return yargs.option('src', {
|
||||||
|
default: './',
|
||||||
|
describe: 'The source directory or source file. Glob patters are supported!',
|
||||||
|
demandOption: true
|
||||||
|
}).option('format', {
|
||||||
|
describe: 'The target format. Multiple formats are allowed as well, use --format=pdf --format=jpg'
|
||||||
|
}).option('dst', {
|
||||||
|
describe: 'Destination folder or file'
|
||||||
|
}).option('view', {
|
||||||
|
default: 'Isometric',
|
||||||
|
describe: 'Sets the target view'
|
||||||
|
}).option('Report', {
|
||||||
|
describe: 'Optional conversion report. Can be JSON, HTML, CSV or Markdown'
|
||||||
|
}).option('debug', {
|
||||||
|
default: false,
|
||||||
|
describe: 'Enable internal debug messages',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('alt', {
|
||||||
|
default: false,
|
||||||
|
describe: 'Use alternate tokenizer, & instead of $',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('skip', {
|
||||||
|
default: true,
|
||||||
|
describe: 'Skip existing files',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('dry', {
|
||||||
|
default: false,
|
||||||
|
describe: 'Run without conversion',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('verbose', {
|
||||||
|
default: true,
|
||||||
|
describe: 'Show internal messages',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('sw', {
|
||||||
|
describe: 'Set explicit the path to the Solidworks binaries & scripts.\
|
||||||
|
"It assumes SolidWorks.Interop.sldworks.dll and export.cmd at this location!'
|
||||||
|
}).option('script', {
|
||||||
|
describe: 'Set explicit the path to the Solidworks script'
|
||||||
|
}).option('hash', {
|
||||||
|
describe: 'To skip already converted files, this option will create a hash file with the extension .hash \
|
||||||
|
using --skip==true will disable it again',
|
||||||
|
default: true,
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('bom-config', {
|
||||||
|
describe: 'Set the Model Configuration to be used',
|
||||||
|
default: 'Default'
|
||||||
|
}).option('bom-template', {
|
||||||
|
describe: 'Path to the BOM template. Default is osr-cad/sw/bom-all.sldbomtbt'
|
||||||
|
}).option('bom-type', {
|
||||||
|
describe: 'Bom Type : default = 2 - PartsOnly = 1 | TopLevelOnly = 2 | Indented = 3',
|
||||||
|
type: "number",
|
||||||
|
default: 2
|
||||||
|
}).option('bom-detail', {
|
||||||
|
describe: 'Bom Numbering : default = 1 - Type_None = 0 | Type_Detailed = 1 | Type_Flat = 2 | BOMNotSet = 3',
|
||||||
|
type: "number",
|
||||||
|
default: 1
|
||||||
|
}).option('bom-images', {
|
||||||
|
describe: 'Add an image in the first colum',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// Sanitizes faulty user argv options for all commands.
|
||||||
|
exports.sanitizeSingle = (argv) => {
|
||||||
|
const src = path.resolve('' + argv.src);
|
||||||
|
const config = argv.config ? read_1.sync(path.resolve('' + argv.config), 'json') : {};
|
||||||
|
const extraVariables = {};
|
||||||
|
for (const key in config) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(config, key)) {
|
||||||
|
const element = config[key];
|
||||||
|
if (typeof element === 'string') {
|
||||||
|
extraVariables[key] = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const args = {
|
||||||
|
src: src,
|
||||||
|
dst: '' + argv.dst,
|
||||||
|
report: argv.report ? path.resolve(argv.report) : null,
|
||||||
|
debug: argv.debug,
|
||||||
|
verbose: argv.verbose,
|
||||||
|
dry: argv.dry,
|
||||||
|
skip: argv.skip,
|
||||||
|
alt: argv.alt,
|
||||||
|
glob: argv.glob,
|
||||||
|
// sw: argv.sw ? path.resolve(argv.sw as string) : path.resolve(__dirname + '/../sw'),
|
||||||
|
script: argv.script || 'pack.exe',
|
||||||
|
variables: Object.assign({}, extraVariables),
|
||||||
|
args: argv.args || '',
|
||||||
|
hash: argv.hash
|
||||||
|
};
|
||||||
|
if (!args.src) {
|
||||||
|
_1.logger.error('Invalid source, abort');
|
||||||
|
return process.exit();
|
||||||
|
}
|
||||||
|
args.srcInfo = osr_cli_commons_1.pathInfo(argv.src);
|
||||||
|
if (!args.srcInfo.FILES) {
|
||||||
|
_1.logger.error(`Invalid source files, abort`);
|
||||||
|
return process.exit();
|
||||||
|
}
|
||||||
|
for (const key in args.srcInfo) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(args.srcInfo, key)) {
|
||||||
|
args.variables['SRC_' + key] = args.srcInfo[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argv.dst) {
|
||||||
|
args.dst = path.resolve(args.dst);
|
||||||
|
args.dstInfo = osr_cli_commons_1.pathInfo(args.dst);
|
||||||
|
args.dstInfo.PATH = path.resolve(argv.dst);
|
||||||
|
for (const key in args.dstInfo) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(args.dstInfo, key)) {
|
||||||
|
args.variables['DST_' + key] = args.dstInfo[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for single file direct conversion
|
||||||
|
if (!args.dstInfo.IS_GLOB && !args.format && args.dstInfo.IS_GLOB) {
|
||||||
|
// args.format = [dstParts.ext.replace('*', '')]
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
};
|
||||||
|
// Sanitizes faulty user argv options for all commands.
|
||||||
|
exports.sanitize = (argv) => {
|
||||||
|
const src = path.resolve('' + argv.src);
|
||||||
|
const config = argv.config ? read_1.sync(path.resolve('' + argv.config), 'json') : {};
|
||||||
|
const extraVariables = {};
|
||||||
|
for (const key in config) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(config, key)) {
|
||||||
|
const element = config[key];
|
||||||
|
if (typeof element === 'string') {
|
||||||
|
extraVariables[key] = element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const args = {
|
||||||
|
src: src,
|
||||||
|
dst: '' + argv.dst,
|
||||||
|
report: argv.report ? path.resolve(argv.report) : null,
|
||||||
|
debug: argv.debug,
|
||||||
|
verbose: argv.verbose,
|
||||||
|
dry: argv.dry,
|
||||||
|
skip: argv.skip,
|
||||||
|
alt: argv.alt,
|
||||||
|
glob: argv.glob,
|
||||||
|
// sw: argv.sw ? path.resolve(argv.sw as string) : path.resolve(__dirname + '/../sw'),
|
||||||
|
script: argv.script || 'export.cmd',
|
||||||
|
variables: Object.assign({}, extraVariables),
|
||||||
|
args: argv.args || '',
|
||||||
|
hash: argv.hash,
|
||||||
|
"bom-config": argv['bom-config'],
|
||||||
|
"bom-detail": argv['bom-detail'],
|
||||||
|
"bom-template": argv['bom-template'],
|
||||||
|
"bom-type": argv['bom-type'],
|
||||||
|
"bom-images": argv['bom-images'],
|
||||||
|
};
|
||||||
|
if (!args.src) {
|
||||||
|
_1.logger.error('Invalid source, abort');
|
||||||
|
return process.exit();
|
||||||
|
}
|
||||||
|
if (argv.format) {
|
||||||
|
if (typeof argv.format === 'string') {
|
||||||
|
args.format = [argv.format];
|
||||||
|
}
|
||||||
|
else if (argv.source && primitives_1.isArray(argv.format)) {
|
||||||
|
args.format = argv.format;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args.srcInfo = osr_cli_commons_1.pathInfo(argv.src);
|
||||||
|
if (!args.srcInfo.FILES) {
|
||||||
|
_1.logger.error(`Invalid source files, abort`, args.srcInfo);
|
||||||
|
return process.exit();
|
||||||
|
}
|
||||||
|
for (const key in args.srcInfo) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(args.srcInfo, key)) {
|
||||||
|
args.variables['SRC_' + key] = args.srcInfo[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argv.dst) {
|
||||||
|
args.dst = path.resolve(core_1.substitute(args.dst, args.variables));
|
||||||
|
args.dstInfo = osr_cli_commons_1.pathInfo(args.dst);
|
||||||
|
args.dstInfo.PATH = argv.dst;
|
||||||
|
for (const key in args.dstInfo) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(args.dstInfo, key)) {
|
||||||
|
args.variables['DST_' + key] = args.dstInfo[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args.view = argv.view || "Isometric";
|
||||||
|
// check for single file direct conversion
|
||||||
|
if (!args.dstInfo.IS_GLOB && !args.format && args.dstInfo.IS_GLOB) {
|
||||||
|
// args.format = [dstParts.ext.replace('*', '')]
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=argv.js.map
|
||||||
1
argv.js.map
Normal file
6
cad/index.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
var sw_lib_1 = require("./sw-lib");
|
||||||
|
Object.defineProperty(exports, "convert", { enumerable: true, get: function () { return sw_lib_1.convert; } });
|
||||||
|
Object.defineProperty(exports, "pack", { enumerable: true, get: function () { return sw_lib_1.pack; } });
|
||||||
|
//# sourceMappingURL=index.js.map
|
||||||
1
cad/index.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/cad/index.ts"],"names":[],"mappings":";;AAAA,mCAAyC;AAAhC,iGAAA,OAAO,OAAA;AAAE,8FAAA,IAAI,OAAA"}
|
||||||
300
cad/sw-lib.js
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.pack = exports.convert = exports.targets = exports.report = exports.packFile = exports.convertFiles = void 0;
|
||||||
|
const path = require("path");
|
||||||
|
const bluebird = require("bluebird");
|
||||||
|
const bluebird_1 = require("bluebird");
|
||||||
|
const exists_1 = require("@plastichub/fs/exists");
|
||||||
|
const read_1 = require("@plastichub/fs/read");
|
||||||
|
const write_1 = require("@plastichub/fs/write");
|
||||||
|
const dir_1 = require("@plastichub/fs/dir");
|
||||||
|
const remove_1 = require("@plastichub/fs/remove");
|
||||||
|
const __1 = require("..");
|
||||||
|
const lib_1 = require("../lib/");
|
||||||
|
const index_1 = require("../lib/process/index");
|
||||||
|
const which_1 = require("which");
|
||||||
|
const report_1 = require("../report");
|
||||||
|
const clone = (obj) => {
|
||||||
|
if (null == obj || "object" != typeof obj)
|
||||||
|
return obj;
|
||||||
|
var copy = obj.constructor();
|
||||||
|
for (var attr in obj) {
|
||||||
|
if (obj.hasOwnProperty(attr))
|
||||||
|
copy[attr] = obj[attr];
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
};
|
||||||
|
const hash_path = (file) => {
|
||||||
|
const srcParts = path.parse(file);
|
||||||
|
let targetPath = path.join(srcParts.dir, srcParts.name + '.hash');
|
||||||
|
return targetPath;
|
||||||
|
};
|
||||||
|
const createHashFile = (file, dst) => {
|
||||||
|
dst = hash_path(file);
|
||||||
|
const hashed = lib_1.hash(file);
|
||||||
|
write_1.sync(dst, hashed);
|
||||||
|
};
|
||||||
|
function convertFiles(file, targets, view, onNode = () => { }, options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (options.dry) {
|
||||||
|
return bluebird.resolve();
|
||||||
|
}
|
||||||
|
return bluebird_1.Promise.resolve(targets).map((target) => {
|
||||||
|
if (options.hash) {
|
||||||
|
const srcHash = lib_1.hash(file);
|
||||||
|
const targetHashPath = hash_path(target);
|
||||||
|
if (exists_1.sync(targetHashPath) && exists_1.sync(target) && options.skip !== false) {
|
||||||
|
const targetHash = read_1.sync(targetHashPath);
|
||||||
|
if (srcHash === targetHash) {
|
||||||
|
options.verbose && __1.logger.info('Already converted ' + file);
|
||||||
|
onNode({
|
||||||
|
src: file,
|
||||||
|
target
|
||||||
|
});
|
||||||
|
return bluebird.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.skip && exists_1.sync(target)) {
|
||||||
|
onNode({
|
||||||
|
src: file,
|
||||||
|
target
|
||||||
|
});
|
||||||
|
return bluebird.resolve();
|
||||||
|
}
|
||||||
|
// customs
|
||||||
|
const parts = path.parse(target);
|
||||||
|
if (parts.ext === '.3DHTML') {
|
||||||
|
on3DHTML(file, target.replace('.3DHTML', '_3D.html'), options);
|
||||||
|
return bluebird.resolve();
|
||||||
|
}
|
||||||
|
const soure_parts = path.parse(file);
|
||||||
|
let exe = '' + options.script;
|
||||||
|
let cwd = path.resolve(options.sw || (__dirname + '/../sw'));
|
||||||
|
let args = [
|
||||||
|
`"${file}"`,
|
||||||
|
`"${target}"`,
|
||||||
|
`"*${view}"`,
|
||||||
|
];
|
||||||
|
if (parts.ext === '.json' && soure_parts.ext === '.SLDASM' || soure_parts.ext === '.sldasm') {
|
||||||
|
exe = 'model-reader.exe';
|
||||||
|
args = [
|
||||||
|
`"${file}"`,
|
||||||
|
`"${target.replace('.SLDASM', '.json').replace('.sldasm', '.json')}"`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (parts.ext === '.html') {
|
||||||
|
exe = 'ExportHTML.exe';
|
||||||
|
args = [
|
||||||
|
`"${file}"`,
|
||||||
|
`"${target.replace('.SLDASM', '.html').replace('.sldasm', '.html')}"`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (parts.ext === '.xlsx') {
|
||||||
|
exe = 'bom.exe';
|
||||||
|
args = [
|
||||||
|
`"${file}"`,
|
||||||
|
`"${target}"`,
|
||||||
|
`--configuration ${options['bom-config']}`,
|
||||||
|
`--type ${options['bom-type']}`,
|
||||||
|
`--detail ${options['bom-detail']}`
|
||||||
|
];
|
||||||
|
options['bom-images'] && args.push('--images');
|
||||||
|
options['bom-template'] && args.push(`--template ${options['bom-template']}`);
|
||||||
|
if (!options.skip && exists_1.sync(target)) {
|
||||||
|
remove_1.sync(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (soure_parts.ext === '.drawio') {
|
||||||
|
exe = 'draw.io.exe';
|
||||||
|
try {
|
||||||
|
cwd = path.parse(which_1.sync(exe)).dir;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
__1.logger.error(`Cant find ${exe}`);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
args = [
|
||||||
|
`"${file}"`,
|
||||||
|
'-x',
|
||||||
|
`-f ${parts.ext.replace('.', '')}`,
|
||||||
|
`${options.args}`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (soure_parts.ext === '.pack') {
|
||||||
|
exe = 'pack.exe';
|
||||||
|
"sw --skip=true --src='C:\Users\mc007\Desktop\ph3\products\products\extrusion\lydia-v4.5\cad\GlobalAssembly.SLDASM' --dst='C:\Users\mc007\Desktop\ph3\products\products\extrusion\lydia-v4.5\cad_public.pack'";
|
||||||
|
args = [
|
||||||
|
`"${file}"`,
|
||||||
|
`"${target}"`
|
||||||
|
];
|
||||||
|
}
|
||||||
|
const bin = path.resolve(`${cwd}/${exe}`);
|
||||||
|
if (!exists_1.sync(bin)) {
|
||||||
|
__1.logger.error(`${bin} doesnt exists in ${cwd}`);
|
||||||
|
__1.logger.error('__dirname:' + __dirname);
|
||||||
|
__1.logger.error('options.sw ' + options.sw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//options.debug && logger.info(`CWD ${cwd} | Exce : ${exe} `, args);
|
||||||
|
//logger.info('cwd ', path.resolve(__dirname +'/../sw' ));
|
||||||
|
const promise = index_1.Helper.run(cwd, exe, args, options.debug);
|
||||||
|
promise.then((d) => {
|
||||||
|
if (options.hash) {
|
||||||
|
createHashFile(file, hash_path(target));
|
||||||
|
}
|
||||||
|
onNode(Object.assign(Object.assign({}, d), { src: file, target }));
|
||||||
|
});
|
||||||
|
return promise;
|
||||||
|
}, { concurrency: 1 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.convertFiles = convertFiles;
|
||||||
|
;
|
||||||
|
function packFile(file, onNode = () => { }, options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (options.dry) {
|
||||||
|
return bluebird.resolve();
|
||||||
|
}
|
||||||
|
const target = options.dst;
|
||||||
|
if (options.hash) {
|
||||||
|
const srcHash = lib_1.hash(file);
|
||||||
|
const targetHashPath = hash_path(target);
|
||||||
|
if (exists_1.sync(targetHashPath) && exists_1.sync(target) && options.skip !== false) {
|
||||||
|
const targetHash = read_1.sync(targetHashPath);
|
||||||
|
if (srcHash === targetHash) {
|
||||||
|
options.verbose && __1.logger.info('Already converted ' + file);
|
||||||
|
onNode({
|
||||||
|
src: file,
|
||||||
|
target
|
||||||
|
});
|
||||||
|
return bluebird.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.skip && exists_1.sync(target)) {
|
||||||
|
onNode({
|
||||||
|
src: file,
|
||||||
|
target
|
||||||
|
});
|
||||||
|
return bluebird.resolve();
|
||||||
|
}
|
||||||
|
let exe = '' + options.script;
|
||||||
|
let args = [
|
||||||
|
`"${file}"`,
|
||||||
|
`"${target}"`
|
||||||
|
];
|
||||||
|
const cwd = path.resolve(options.sw || (__dirname + '/../sw'));
|
||||||
|
const bin = path.resolve(`${cwd}/${exe}`);
|
||||||
|
if (!exists_1.sync(bin)) {
|
||||||
|
__1.logger.error(`${bin} doesnt exists in ${cwd}`);
|
||||||
|
__1.logger.error('__dirname:' + __dirname);
|
||||||
|
__1.logger.error('options.sw ' + options.sw);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
options.debug && __1.logger.debug(`Run ${exe} in ${cwd} with `, args);
|
||||||
|
const promise = index_1.Helper.run(cwd, exe, args, options.debug);
|
||||||
|
promise.then((d) => {
|
||||||
|
if (options.hash) {
|
||||||
|
createHashFile(file, hash_path(target));
|
||||||
|
}
|
||||||
|
onNode(Object.assign(Object.assign({}, d), { src: file, target }));
|
||||||
|
});
|
||||||
|
return promise;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.packFile = packFile;
|
||||||
|
;
|
||||||
|
exports.report = (data, dst) => {
|
||||||
|
let report = null;
|
||||||
|
if (dst.endsWith('.md')) {
|
||||||
|
report = report_1.reportMarkdown(data);
|
||||||
|
}
|
||||||
|
if (dst.endsWith('.csv')) {
|
||||||
|
report = report_1.reportCSV(data);
|
||||||
|
}
|
||||||
|
if (report) {
|
||||||
|
__1.info(`Write report to ${dst}`);
|
||||||
|
write_1.sync(dst, report);
|
||||||
|
}
|
||||||
|
return report;
|
||||||
|
};
|
||||||
|
const on3DHTML = (src, dst, options) => {
|
||||||
|
const web_root = path.resolve(__dirname + '/../../web/xeo');
|
||||||
|
const config = JSON.parse(read_1.sync(path.resolve(__dirname + '/../../config.json')));
|
||||||
|
const templatePath = path.resolve(`${web_root}/template.html`);
|
||||||
|
const template = read_1.sync(templatePath, 'string');
|
||||||
|
const srcParts = path.parse(src);
|
||||||
|
const variables = Object.assign(Object.assign({}, config.variables), { SRC_PATH_WEB: './' + srcParts.name + '_3D.html', MODEL_SRC: './' + srcParts.name + '.3dxml' });
|
||||||
|
const content = __1.substitute(false, template, variables);
|
||||||
|
write_1.sync(dst, content);
|
||||||
|
};
|
||||||
|
exports.targets = (f, options) => {
|
||||||
|
const srcParts = path.parse(f);
|
||||||
|
const variables = clone(options.variables);
|
||||||
|
const targets = [];
|
||||||
|
if (options.dstInfo.IS_GLOB) {
|
||||||
|
options.dstInfo.GLOB_EXTENSIONS.forEach((e) => {
|
||||||
|
variables.SRC_NAME = srcParts.name;
|
||||||
|
variables.SRC_DIR = srcParts.dir;
|
||||||
|
let targetPath = __1.substitute(options.alt, options.variables.DST_PATH, variables);
|
||||||
|
targetPath = path.resolve(targetPath.replace(options.variables.DST_FILE_EXT, '') + e);
|
||||||
|
const parts = path.parse(targetPath);
|
||||||
|
if (!exists_1.sync(parts.dir)) {
|
||||||
|
try {
|
||||||
|
dir_1.sync(parts.dir);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (options.debug) {
|
||||||
|
__1.logger.error(`Error creating target path ${parts.dir} for ${targetPath}`);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
targets.push(targetPath);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return targets;
|
||||||
|
};
|
||||||
|
function convert(options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let reports = [];
|
||||||
|
const onNode = (data) => { reports.push(data); };
|
||||||
|
options.verbose && __1.logger.info(`Convert ${options.srcInfo.FILES.length} files `);
|
||||||
|
yield bluebird_1.Promise.resolve(options.srcInfo.FILES).map((f) => {
|
||||||
|
const outputs = exports.targets(f, options);
|
||||||
|
options.verbose && __1.logger.info(`Convert ${f} to `, outputs);
|
||||||
|
return convertFiles(f, outputs, options.view, onNode, options);
|
||||||
|
}, { concurrency: 1 });
|
||||||
|
if (options.report) {
|
||||||
|
const reportOutFile = __1.substitute(false, options.report, {
|
||||||
|
dst: options.srcInfo.DIR
|
||||||
|
});
|
||||||
|
options.verbose && __1.logger.info(`Write report to ${reportOutFile}`);
|
||||||
|
exports.report(reports, reportOutFile);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.convert = convert;
|
||||||
|
function pack(options) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let reports = [];
|
||||||
|
const onNode = (data) => { reports.push(data); };
|
||||||
|
options.verbose && __1.logger.info(`Pack ${options.srcInfo.FILES.length} files `);
|
||||||
|
yield bluebird_1.Promise.resolve(options.srcInfo.FILES).map((f) => {
|
||||||
|
options.verbose && __1.logger.info(`Convert ${f} to `, options.dst);
|
||||||
|
return packFile(f, onNode, options);
|
||||||
|
}, { concurrency: 1 });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.pack = pack;
|
||||||
|
//# sourceMappingURL=sw-lib.js.map
|
||||||
1
cad/sw-lib.js.map
Normal file
7
clear_history.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
git checkout --orphan latest_branch
|
||||||
|
git add -A
|
||||||
|
git commit -am "for the boyz"
|
||||||
|
git branch -D master
|
||||||
|
git branch -m master
|
||||||
|
git push -f origin master
|
||||||
|
git gc --aggressive --prune=all
|
||||||
69
commands/common/sanitize-filename.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.register = void 0;
|
||||||
|
const path = require("path");
|
||||||
|
const fs_1 = require("fs");
|
||||||
|
const lib_1 = require("../../lib");
|
||||||
|
const debug = require("../../log");
|
||||||
|
const sanitize = require("sanitize-filename");
|
||||||
|
const filenamify = require('filenamify');
|
||||||
|
const slugify = require('slugify');
|
||||||
|
const fg = require('fast-glob');
|
||||||
|
const defaultOptions = (yargs) => {
|
||||||
|
return yargs.option('input', {
|
||||||
|
default: './',
|
||||||
|
describe: 'The sources'
|
||||||
|
}).option('slugify', {
|
||||||
|
default: 'false',
|
||||||
|
describe: 'convert whitespaces to dashes, remove special ASCIs'
|
||||||
|
}).option('debug', {
|
||||||
|
default: 'false',
|
||||||
|
describe: 'debug messages'
|
||||||
|
}).option('dry', {
|
||||||
|
default: 'false',
|
||||||
|
describe: 'dry run, dont modify'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let options = (yargs) => defaultOptions(yargs);
|
||||||
|
const prep = (file) => {
|
||||||
|
const parts = path.parse(file);
|
||||||
|
const stats = fs_1.lstatSync(file);
|
||||||
|
if (stats.isFile()) {
|
||||||
|
console.log('p', parts);
|
||||||
|
// return parts.name.trim() + parts.ext.trim().split('.')[1].trim();
|
||||||
|
return filenamify(parts.name + parts.ext);
|
||||||
|
}
|
||||||
|
return prep;
|
||||||
|
};
|
||||||
|
// npm run build ; node ./build/main.js sanitize-filenames --input=.
|
||||||
|
exports.register = (cli) => {
|
||||||
|
return cli.command('sanitize-filename', 'Removes invalid chars in filenames', options, (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (argv.help) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const _debug = argv.debug === 'true';
|
||||||
|
const _dry = argv.dry === 'true';
|
||||||
|
const src = path.resolve('' + argv.input);
|
||||||
|
_debug && debug.info(`sanitize ${src}`);
|
||||||
|
if (fs_1.existsSync(src)) {
|
||||||
|
!_dry && sanitize(src);
|
||||||
|
if (argv.slugify === 'true') {
|
||||||
|
let _files = lib_1.files(src, '**/**').map(prep).map(slugify);
|
||||||
|
debug.info('files', _files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_debug && debug.error(`doesnt exists : ${src} `);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=sanitize-filename.js.map
|
||||||
1
commands/common/sanitize-filename.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"sanitize-filename.js","sourceRoot":"","sources":["../../src/commands/common/sanitize-filename.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,6BAA6B;AAC7B,2BAA2C;AAC3C,mCAAkC;AAClC,mCAAmC;AAEnC,MAAM,QAAQ,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AACzC,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;AACnC,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAEhC,MAAM,cAAc,GAAG,CAAC,KAAe,EAAE,EAAE;IACvC,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE;QACzB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,aAAa;KAC1B,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE;QACjB,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,qDAAqD;KAClE,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE;QACf,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,gBAAgB;KAC7B,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;QACb,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,sBAAsB;KACnC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,IAAI,OAAO,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AAEzD,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE;IAE1B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,cAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE;QAChB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAC,KAAK,CAAC,CAAC;QAC/B,2EAA2E;QACnE,OAAO,UAAU,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;KAC7C;IACD,OAAO,IAAI,CAAC;AAChB,CAAC,CAAA;AAED,oEAAoE;AACvD,QAAA,QAAQ,GAAG,CAAC,GAAa,EAAE,EAAE;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,oCAAoC,EAAE,OAAO,EAAE,CAAO,IAAmB,EAAE,EAAE;QACjH,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;SAAE;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,KAAK,MAAM,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,KAAM,MAAM,CAAC;QAClC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;QACxC,IAAI,eAAU,CAAC,GAAG,CAAC,EAAE;YAEjB,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE;gBACzB,IAAI,MAAM,GAAG,WAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACxD,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;aAC/B;SACJ;aAAM;YACH,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,mBAAmB,GAAG,GAAG,CAAC,CAAC;SACpD;IACL,CAAC,CAAA,CAAC,CAAC;AACP,CAAC,CAAC"}
|
||||||
77
commands/markdown.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.register = exports.convertFiles = exports.convert = void 0;
|
||||||
|
const __1 = require("..");
|
||||||
|
const utils = require("../lib/common/strings");
|
||||||
|
const path = require("path");
|
||||||
|
const read_1 = require("@plastichub/fs/read");
|
||||||
|
const exists_1 = require("@plastichub/fs/exists");
|
||||||
|
const dir_1 = require("@plastichub/fs/dir");
|
||||||
|
const write_1 = require("@plastichub/fs/write");
|
||||||
|
const showdown_1 = require("showdown");
|
||||||
|
const fg = require('fast-glob');
|
||||||
|
const defaultData = (override) => {
|
||||||
|
return Object.assign({ PART_PARENT: 'my parent 2', PART_INVENTORY: 'inventory', PART_NAME: 'Front Shield', PART_VERSION: 1, PART_VERSIONS: '1 2', PART_ID: 'Z_4_FRONT_SHIELD', PART_DRAWING: 'https://a360.co/37pDdVD', PART_PREVIEW: '', PART_COMPAT: '', PART_CAPS: '', PART_ASSEMBLY: '', PART_TOOLS: '<div>tools - data </div>', PART_TEMPLATES: '', PART_STOCK: '', PART_MACHINES: '', PART_STEPS: '', PART_EDIT: '', PART_EDIT_ARGS: '' }, override);
|
||||||
|
};
|
||||||
|
const defaultOptions = (yargs) => {
|
||||||
|
return yargs.option('input', {
|
||||||
|
default: './',
|
||||||
|
describe: 'The sources'
|
||||||
|
}).option('output', {
|
||||||
|
default: './',
|
||||||
|
describe: 'The output'
|
||||||
|
}).option('debug', {
|
||||||
|
default: 'false',
|
||||||
|
describe: 'Enable internal debug message'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let options = (yargs) => defaultOptions(yargs);
|
||||||
|
exports.convert = (input, data) => {
|
||||||
|
input = utils.replace(input, null, defaultData(data), {
|
||||||
|
begin: '<%',
|
||||||
|
end: '%>'
|
||||||
|
});
|
||||||
|
let converter = new showdown_1.Converter();
|
||||||
|
converter.setOption('literalMidWordUnderscores', 'true');
|
||||||
|
return converter.makeHtml(input);
|
||||||
|
};
|
||||||
|
exports.convertFiles = (files, dst) => {
|
||||||
|
files.forEach((f) => {
|
||||||
|
const content = read_1.sync(f, 'string');
|
||||||
|
const html = exports.convert(content, {});
|
||||||
|
if (!dst) {
|
||||||
|
dst = path.parse(f).dir;
|
||||||
|
}
|
||||||
|
const target = dst + path.sep + path.parse(f).name + '.html';
|
||||||
|
__1.debug(`\t Convert ${f} to ${target}`);
|
||||||
|
write_1.sync(target, html);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// npm run build ; node ./build/main.js markdown --input=../pages --output=../out
|
||||||
|
exports.register = (cli) => {
|
||||||
|
return cli.command('markdown', 'Converts md files to html using showdown', options, (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (argv.help) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const src = path.resolve('' + argv.input);
|
||||||
|
const dst = path.resolve('' + argv.output);
|
||||||
|
if (!exists_1.sync(dst)) {
|
||||||
|
dir_1.sync(dst);
|
||||||
|
}
|
||||||
|
const files = fg.sync('*.md', { dot: true, cwd: src, absolute: true });
|
||||||
|
exports.convertFiles(files, dst);
|
||||||
|
if (argv.debug) {
|
||||||
|
__1.debug(`Converted ${files.length} files`);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=markdown.js.map
|
||||||
1
commands/markdown.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/commands/markdown.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,0BAA2B;AAC3B,+CAA+C;AAC/C,6BAA6B;AAC7B,8CAAmD;AACnD,kDAAuD;AACvD,4CAAiD;AACjD,gDAAqD;AACrD,uCAAqC;AAErC,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAEhC,MAAM,WAAW,GAAG,CAAC,QAAa,EAAE,EAAE;IAClC,uBACI,WAAW,EAAE,aAAa,EAC1B,cAAc,EAAE,WAAW,EAC3B,SAAS,EAAE,cAAc,EACzB,YAAY,EAAE,CAAC,EACf,aAAa,EAAE,KAAK,EACpB,OAAO,EAAE,kBAAkB,EAC3B,YAAY,EAAE,yBAAyB,EACvC,YAAY,EAAE,EAAE,EAChB,WAAW,EAAE,EAAE,EACf,SAAS,EAAE,EAAE,EACb,aAAa,EAAE,EAAE,EACjB,UAAU,EAAE,0BAA0B,EACtC,cAAc,EAAE,EAAE,EAClB,UAAU,EAAE,EAAE,EACd,aAAa,EAAE,EAAE,EACjB,UAAU,EAAE,EAAE,EACd,SAAS,EAAE,EAAE,EACb,cAAc,EAAE,EAAE,IACf,QAAQ,EACd;AACL,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,KAAe,EAAE,EAAE;IACvC,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE;QACzB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,aAAa;KAC1B,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;QAChB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,YAAY;KACzB,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE;QACf,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,+BAA+B;KAC5C,CAAC,CAAA;AACN,CAAC,CAAC;AAEF,IAAI,OAAO,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AAE5C,QAAA,OAAO,GAAG,CAAC,KAAa,EAAE,IAAS,EAAE,EAAE;IAChD,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE;QAClD,KAAK,EAAE,IAAI;QACX,GAAG,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,IAAI,SAAS,GAAG,IAAI,oBAAS,EAAE,CAAC;IAChC,SAAS,CAAC,SAAS,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;IACzD,OAAO,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC,CAAA;AAEY,QAAA,YAAY,GAAG,CAAC,KAAe,EAAE,GAAW,EAAE,EAAE;IACzD,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE;QAChB,MAAM,OAAO,GAAG,WAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAClC,MAAM,IAAI,GAAG,eAAO,CAAC,OAAiB,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAG,CAAC,GAAG,EAAC;YACJ,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;SAC3B;QACD,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,OAAO,CAAC;QAC7D,SAAK,CAAC,cAAc,CAAC,OAAO,MAAM,EAAE,CAAC,CAAC;QACtC,YAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC,CAAC,CAAA;AACN,CAAC,CAAA;AACD,iFAAiF;AACpE,QAAA,QAAQ,GAAG,CAAC,GAAa,EAAE,EAAE;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,0CAA0C,EAAE,OAAO,EAAE,CAAO,IAAmB,EAAE,EAAE;QAC9G,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;SAAE;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,aAAM,CAAC,GAAG,CAAC,EAAE;YACd,UAAG,CAAC,GAAG,CAAC,CAAC;SACZ;QACD,MAAM,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACvE,oBAAY,CAAC,KAAK,EAAC,GAAG,CAAC,CAAC;QACxB,IAAI,IAAI,CAAC,KAAK,EAAE;YACZ,SAAK,CAAC,aAAa,KAAK,CAAC,MAAM,QAAQ,CAAC,CAAC;SAC5C;IACL,CAAC,CAAA,CAAC,CAAC;AACP,CAAC,CAAC"}
|
||||||
67
commands/pack.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.register = exports.defaultOptions = void 0;
|
||||||
|
const __1 = require("../");
|
||||||
|
const argv_1 = require("../argv");
|
||||||
|
const index_1 = require("../cad/index");
|
||||||
|
const OSR_REGEX = /^[0-9].+$/;
|
||||||
|
exports.defaultOptions = (yargs) => {
|
||||||
|
return yargs.option('src', {
|
||||||
|
default: './',
|
||||||
|
describe: 'The source directory or source file. Glob patters are supported!',
|
||||||
|
demandOption: true
|
||||||
|
}).option('dst', {
|
||||||
|
describe: 'Destination folder or file'
|
||||||
|
}).option('view', {
|
||||||
|
default: 'Isometric',
|
||||||
|
describe: 'Sets the target view'
|
||||||
|
}).option('Report', {
|
||||||
|
describe: 'Optional conversion report. Can be JSON, HTML, CSV or Markdown'
|
||||||
|
}).option('debug', {
|
||||||
|
default: false,
|
||||||
|
describe: 'Enable internal debug messages',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('skip', {
|
||||||
|
default: true,
|
||||||
|
describe: 'Skip existing files',
|
||||||
|
type: 'boolean',
|
||||||
|
}).option('dry', {
|
||||||
|
default: false,
|
||||||
|
describe: 'Run without conversion but create reports',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('alt', {
|
||||||
|
default: false,
|
||||||
|
describe: 'Alternate tokenizer'
|
||||||
|
}).option('verbose', {
|
||||||
|
default: true,
|
||||||
|
describe: 'Show internal messages',
|
||||||
|
type: 'boolean'
|
||||||
|
}).option('sw', {
|
||||||
|
describe: 'Set explicit the path to the Solidworks binaries & scripts.\
|
||||||
|
"It assumes SolidWorks.Interop.sldworks.dll and export.cmd at this location!'
|
||||||
|
}).option('script', {
|
||||||
|
describe: 'Set explicit the path to the Solidworks script'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
let options = (yargs) => exports.defaultOptions(yargs);
|
||||||
|
// node ./build/main.js pack --src=../../ph3/products/products/injection/elena/cad/Global*.SLDASM --dst="../test" --verbose=true
|
||||||
|
exports.register = (cli) => {
|
||||||
|
return cli.command('pack', '', options, (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (argv.help) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options = argv_1.sanitizeSingle(argv);
|
||||||
|
options.verbose && __1.logger.debug("options " + argv.dst, options);
|
||||||
|
return index_1.pack(options);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=pack.js.map
|
||||||
1
commands/pack.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../src/commands/pack.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,2BAA6B;AAE7B,kCAAyC;AAEzC,wCAAoC;AAEpC,MAAM,SAAS,GAAG,WAAW,CAAC;AAEjB,QAAA,cAAc,GAAG,CAAC,KAAe,EAAE,EAAE;IAC9C,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE;QACvB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,kEAAkE;QAC5E,YAAY,EAAE,IAAI;KACrB,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;QACb,QAAQ,EAAE,4BAA4B;KACzC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE;QACd,OAAO,EAAE,WAAW;QACpB,QAAQ,EAAE,sBAAsB;KACnC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;QAChB,QAAQ,EAAE,gEAAgE;KAC7E,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE;QACf,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,gCAAgC;QAC1C,IAAI,EAAE,SAAS;KAClB,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE;QACd,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,qBAAqB;QAC/B,IAAI,EAAE,SAAS;KAClB,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;QACb,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,2CAA2C;QACrD,IAAI,EAAE,SAAS;KAClB,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;QACb,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,qBAAqB;KAClC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE;QACjB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,wBAAwB;QAClC,IAAI,EAAE,SAAS;KAClB,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE;QACZ,QAAQ,EAAE;qFACmE;KAChF,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;QAChB,QAAQ,EAAE,gDAAgD;KAC7D,CAAC,CAAA;AACN,CAAC,CAAC;AAEF,IAAI,OAAO,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,sBAAc,CAAC,KAAK,CAAC,CAAC;AAEzD,gIAAgI;AACnH,QAAA,QAAQ,GAAG,CAAC,GAAa,EAAE,EAAE;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,CAAO,IAAmB,EAAE,EAAE;QAClE,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;SAAE;QAC1B,MAAM,OAAO,GAAG,qBAAc,CAAC,IAAI,CAAqB,CAAC;QACzD,OAAO,CAAC,OAAO,IAAI,UAAM,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAChE,OAAO,YAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,CAAA,CAAC,CAAC;AACP,CAAC,CAAC"}
|
||||||
31
commands/sw.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.register = void 0;
|
||||||
|
const debug = require("../log");
|
||||||
|
const argv_1 = require("../argv");
|
||||||
|
const index_1 = require("../cad/index");
|
||||||
|
const OSR_REGEX = /^[0-9].+$/;
|
||||||
|
const isOSR = (filename) => filename.match(OSR_REGEX) != null;
|
||||||
|
// SolidWorks base converter, using powershell & interop interface (pkgdir/sw)
|
||||||
|
let options = (yargs) => argv_1.defaultOptions(yargs);
|
||||||
|
// node ./build/main.js sw --src=../plastichub/products/elena/cad --glob="*.SLDASM" --format="step" --dst="../test"
|
||||||
|
exports.register = (cli) => {
|
||||||
|
return cli.command('sw', '', options, (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (argv.help) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options = argv_1.sanitize(argv);
|
||||||
|
options.debug && debug.inspect("options " + argv.dst, options);
|
||||||
|
return index_1.convert(options);
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=sw.js.map
|
||||||
1
commands/sw.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"sw.js","sourceRoot":"","sources":["../src/commands/sw.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,gCAAgC;AAKhC,kCAAmD;AAEnD,wCAAuC;AAEvC,MAAM,SAAS,GAAG,WAAW,CAAC;AAC9B,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AAE9D,8EAA8E;AAE9E,IAAI,OAAO,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,qBAAc,CAAC,KAAK,CAAC,CAAC;AAEzD,mHAAmH;AAEtG,QAAA,QAAQ,GAAG,CAAC,GAAa,EAAE,EAAE;IAEtC,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,CAAO,IAAmB,EAAE,EAAE;QAChE,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;SAAE;QAC1B,MAAM,OAAO,GAAG,eAAQ,CAAC,IAAI,CAAqB,CAAC;QAEnD,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC/D,OAAO,eAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC,CAAA,CAAC,CAAC;AACP,CAAC,CAAC"}
|
||||||
83
commands/watch.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
"use strict";
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.register = exports.updateTSX = void 0;
|
||||||
|
const chokidar = require("chokidar");
|
||||||
|
const path = require("path");
|
||||||
|
const __1 = require("..");
|
||||||
|
const markdown_1 = require("./markdown");
|
||||||
|
const utils = require("../lib/common/strings");
|
||||||
|
const read_1 = require("@plastichub/fs/read");
|
||||||
|
const write_1 = require("@plastichub/fs/write");
|
||||||
|
// import * as cheerio from 'cheerio';
|
||||||
|
const pretty = require('pretty');
|
||||||
|
const defaultOptions = (yargs) => {
|
||||||
|
return yargs.option('input', {
|
||||||
|
default: './',
|
||||||
|
describe: 'The sources'
|
||||||
|
}).option('debug', {
|
||||||
|
default: 'false',
|
||||||
|
describe: 'Enable internal debug message'
|
||||||
|
}).option('tsx', {
|
||||||
|
default: 'true',
|
||||||
|
describe: 'Update tsx file'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
export const parseHTML = (input: string) => {
|
||||||
|
const $ = cheerio.load(input as string, {
|
||||||
|
xmlMode: true
|
||||||
|
});
|
||||||
|
|
||||||
|
$('meta').remove();
|
||||||
|
$('templates').remove();
|
||||||
|
|
||||||
|
input = $.html();
|
||||||
|
input = pretty(input,{ocd: true});
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
exports.updateTSX = (mdPath) => {
|
||||||
|
const parts = path.parse(mdPath);
|
||||||
|
let html = read_1.sync(`${parts.dir}/${parts.name}.html`, 'string');
|
||||||
|
const tsxin = read_1.sync(`${parts.dir}/${parts.name}.tsxin`, 'string');
|
||||||
|
// html = parseHTML(html as string);
|
||||||
|
const output = utils.replace(tsxin, null, {
|
||||||
|
CONTENT: html
|
||||||
|
}, {
|
||||||
|
begin: '<%',
|
||||||
|
end: '%>'
|
||||||
|
});
|
||||||
|
write_1.sync(`${parts.dir}/${parts.name}.tsx`, output);
|
||||||
|
};
|
||||||
|
let options = (yargs) => defaultOptions(yargs);
|
||||||
|
// npm run build ; node ./build/main.js watch --input=../pages
|
||||||
|
exports.register = (cli) => {
|
||||||
|
return cli.command('watch', '', options, (argv) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
if (argv.help) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const src = path.resolve('' + argv.input);
|
||||||
|
const watcher = chokidar.watch(`${src}/**/*.md`, {
|
||||||
|
ignored: /(^|[\/\\])\../,
|
||||||
|
persistent: true
|
||||||
|
});
|
||||||
|
if (argv.debug) {
|
||||||
|
__1.debug(`Watching ${src}`);
|
||||||
|
}
|
||||||
|
watcher
|
||||||
|
.on('change', path => {
|
||||||
|
markdown_1.convertFiles([path]);
|
||||||
|
exports.updateTSX(path);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=watch.js.map
|
||||||
1
commands/watch.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/commands/watch.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,qCAAqC;AACrC,6BAA6B;AAC7B,0BAA2B;AAC3B,yCAA0C;AAC1C,+CAA+C;AAC/C,8CAAmD;AACnD,gDAAqD;AACrD,sCAAsC;AACtC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEjC,MAAM,cAAc,GAAG,CAAC,KAAe,EAAE,EAAE;IACvC,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE;QACzB,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,aAAa;KAC1B,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE;QACf,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,+BAA+B;KAC5C,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE;QACb,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,iBAAiB;KAC9B,CAAC,CAAA;AACN,CAAC,CAAC;AAEF;;;;;;;;;;;;;EAaE;AAGW,QAAA,SAAS,GAAG,CAAC,MAAc,EAAE,EAAE;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEjC,IAAI,IAAI,GAAG,WAAI,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,WAAI,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjE,oCAAoC;IAEpC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,KAAe,EAAE,IAAI,EAAE;QAChD,OAAO,EAAE,IAAI;KAChB,EAAE;QACC,KAAK,EAAE,IAAI;QACX,GAAG,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,YAAK,CAAC,GAAG,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,MAAM,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC,CAAA;AAED,IAAI,OAAO,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AACzD,8DAA8D;AACjD,QAAA,QAAQ,GAAG,CAAC,GAAa,EAAE,EAAE;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAO,IAAmB,EAAE,EAAE;QACnE,IAAI,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO;SAAE;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,GAAG,UAAU,EAAE;YAC7C,OAAO,EAAE,eAAe;YACxB,UAAU,EAAE,IAAI;SACnB,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,KAAK,EAAE;YACZ,SAAK,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;SAC5B;QACD,OAAO;aACF,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE;YACjB,uBAAY,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACrB,iBAAS,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,CAAC,CAAA;IACV,CAAC,CAAA,CAAC,CAAC;AACP,CAAC,CAAC"}
|
||||||
5
config.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"variables":{
|
||||||
|
"OSR_CAD_WEB":"https://osr-plastic.org/cad"
|
||||||
|
}
|
||||||
|
}
|
||||||
8
constants.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.PACKAGE_NAME = exports.MODULE_NAME = exports.GIT_REPO = exports.GIT_CHANGELOG_MESSAGE_PREFIX = void 0;
|
||||||
|
exports.GIT_CHANGELOG_MESSAGE_PREFIX = 'ChangeLog:';
|
||||||
|
exports.GIT_REPO = 'https://git.osr-plastic.org/osr-plastic/';
|
||||||
|
exports.MODULE_NAME = `OSR-CAD`;
|
||||||
|
exports.PACKAGE_NAME = 'osr-cad';
|
||||||
|
//# sourceMappingURL=constants.js.map
|
||||||
1
constants.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"constants.js","sourceRoot":"","sources":["src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,4BAA4B,GAAG,YAAY,CAAC;AAC5C,QAAA,QAAQ,GAAG,0CAA0C,CAAA;AACrD,QAAA,WAAW,GAAG,SAAS,CAAC;AACxB,QAAA,YAAY,GAAG,SAAS,CAAC"}
|
||||||
154
docs/Examples.md
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
### General usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src=(FOLDER||FILE)/GLOB --dst=EXPRESSION||FILE||FOLDER/GLOB
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
|
||||||
|
**src** : The source directory or file. This can be a glob pattern.
|
||||||
|
|
||||||
|
**dst** : The source directory or file. This can be a glob pattern with expressions.
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
|
||||||
|
|
||||||
|
**SRC_DIR** : The directory of the current file being converted
|
||||||
|
|
||||||
|
**SRC_NAME** : The file name of the current file being converted
|
||||||
|
|
||||||
|
**SRC_FILE_EXT** : The file extension of the current file being converted
|
||||||
|
|
||||||
|
|
||||||
|
## Basics
|
||||||
|
|
||||||
|
### Convert all assembly files to PDF files in the current directory
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='../plastichub/products/elena/cad/*.SLDASM' --dst='${SRC_NAME}.pdf'
|
||||||
|
```
|
||||||
|
### Convert all assembly files to PDF files in the source directory
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='../plastichub/products/elena/cad/*.SLDASM' --dst='${SRC_DIR}/${SRC_NAME}.pdf'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convert all assembly files to PDF files in the source directory, recursively
|
||||||
|
|
||||||
|
**Note** : Recursion can be added by using `**/`.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='../plastichub/products/elena/cad/**/*.SLDASM' --dst='${SRC_DIR}/${SRC_NAME}.pdf'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convert all assembly and part files to PDF files in the source directory, recursively
|
||||||
|
|
||||||
|
**Note** : Recursion can be added by using `**/`.
|
||||||
|
|
||||||
|
**Note** : To select or use multiple file extensions, write ```*.+(SLDASM|SLDPRT)``` instead of ```*.SLDASM```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='../plastichub/products/elena/cad/**/*.+(SLDASM|SLDPRT)' --dst='${SRC_DIR}/${SRC_NAME}.pdf'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convert all assembly and part files to PDF and JPG files in the source directory, recursively
|
||||||
|
|
||||||
|
**Note** : Recursion can be added by using `**/`.
|
||||||
|
|
||||||
|
**Note** : To select or use multiple file extensions, write ```*.+(SLDASM|SLDPRT)``` instead of ```*.SLDASM```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='../plastichub/products/elena/cad/**/*.+(SLDASM|SLDPRT)' --dst='${SRC_DIR}/${SRC_NAME}.+(pdf|jpg)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convert all assembly files to STEP and PDF files in the source directory
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='./products/asterix-pp/cad/*.+(SLDASM)' --dst='${SRC_DIR}/${SRC_NAME}.+(step|pdf)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extra all custom properties and depending parts from assembly files to JSON files in the source directory
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='./products/asterix-pp/cad/*.+(SLDASM)' --dst='${SRC_DIR}/${SRC_NAME}.+(json)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convert parts or assemblies to HTML files (all incl. view and data) - using eDrawings interop API
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='./products/asterix-pp/cad/*.+(SLDASM)' --dst='${SRC_DIR}/${SRC_NAME}.+(html)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Export drawio files to png, pdf or jpg
|
||||||
|
|
||||||
|
**Remarks**
|
||||||
|
|
||||||
|
- make sure that draw.io.exe is being found globally (add the path to Draw.io to your Environment path variable! )
|
||||||
|
- Draw.io can be downloaded here [https://github.com/jgraph/drawio-desktop/releases/tag/v14.6.13](https://github.com/jgraph/drawio-desktop/releases/tag/v14.6.13)
|
||||||
|
- to see more options, please run ```draw.io.exe --help```: (forward the arguments using ```--args='-t'```)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Usage: draw.io [options] [input file/folder]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-V, --version output the version number
|
||||||
|
-c, --create creates a new empty file if no file is
|
||||||
|
passed
|
||||||
|
-k, --check does not overwrite existing files
|
||||||
|
-x, --export export the input file/folder based on the
|
||||||
|
given options
|
||||||
|
-r, --recursive for a folder input, recursively convert
|
||||||
|
all files in sub-folders also
|
||||||
|
-o, --output <output file/folder> specify the output file/folder. If
|
||||||
|
omitted, the input file name is used for
|
||||||
|
output with the specified format as
|
||||||
|
extension
|
||||||
|
-f, --format <format> if output file name extension is
|
||||||
|
specified, this option is ignored (file
|
||||||
|
type is determined from output extension,
|
||||||
|
possible export formats are pdf, png, jpg,
|
||||||
|
svg, vsdx, and xml) (default: "pdf")
|
||||||
|
-q, --quality <quality> output image quality for JPEG (default:
|
||||||
|
90)
|
||||||
|
-t, --transparent set transparent background for PNG
|
||||||
|
-e, --embed-diagram includes a copy of the diagram (for PNG
|
||||||
|
format only)
|
||||||
|
-b, --border <border> sets the border width around the diagram
|
||||||
|
(default: 0)
|
||||||
|
-s, --scale <scale> scales the diagram size
|
||||||
|
--width <width> fits the generated image/pdf into the
|
||||||
|
specified width, preserves aspect ratio.
|
||||||
|
--height <height> fits the generated image/pdf into the
|
||||||
|
specified height, preserves aspect ratio.
|
||||||
|
--crop crops PDF to diagram size
|
||||||
|
-a, --all-pages export all pages (for PDF format only)
|
||||||
|
-p, --page-index <pageIndex> selects a specific page, if not specified
|
||||||
|
and the format is an image, the first page
|
||||||
|
is selected
|
||||||
|
-g, --page-range <from>..<to> selects a page range (for PDF format only)
|
||||||
|
-u, --uncompressed Uncompressed XML output (for XML format
|
||||||
|
only)
|
||||||
|
-h, --help display help for command
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='./products/extrusion/**/*.+(drawio)' --dst='${SRC_DIR}/${SRC_NAME}.+(png)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create & export BOMs from assembly files
|
||||||
|
|
||||||
|
**Remarks**
|
||||||
|
|
||||||
|
- it's using by default osr-cad/sw/bom-all.sldbomtbt as table template
|
||||||
|
- run osr-cad --help to see the BOM options
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad sw --src='./products/extrusion/**/*.+(SLDASM)' --dst='${SRC_DIR}/${SRC_NAME}.+(xlsx)'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pack Assembly (aka 'pack and go')
|
||||||
|
|
||||||
|
```sh
|
||||||
|
osr-cad pack --src=../../ph3/products/products/injection/elena/cad/Global*.SLDASM --dst="../test"
|
||||||
|
```
|
||||||
33
docs/Integration.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Integration
|
||||||
|
|
||||||
|
## [Alt-Tap Salamand](https://www.altap.cz/) - Custom Menus
|
||||||
|
|
||||||
|
To use OSR-CAD in custom menus, as follows
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
1. install osr-cad via ```npm i -g @plastichub/osr-cad```
|
||||||
|
2. Register a new custom menu (press F9 on any file)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**command** : ```osr-cad```
|
||||||
|
|
||||||
|
**Arguments** : ```sw --alt=true --verbose=true --hash=false --debug=true --skip=false --src="$(FullName)" --dst="&{SRC_DIR}/&{SRC_NAME}.+(step)"```
|
||||||
|
|
||||||
|
Here explained,
|
||||||
|
|
||||||
|
```sh
|
||||||
|
|
||||||
|
sw # osr-cad command
|
||||||
|
--alt=true # use alternate tokenizer, '&' instead of '$' to prevent collisions with Alt-Tab's own variable designator
|
||||||
|
--verbose=true # be verbose
|
||||||
|
--hash=false # don't create hash files (for caching)
|
||||||
|
--debug=true # be even more verbose
|
||||||
|
--skip=false # skip already created files
|
||||||
|
--src="$(FullName)" # use Alt-Tab's variable for the current selected file
|
||||||
|
--dst="&{SRC_DIR}/&{SRC_NAME}.+(step)" # the output destination path
|
||||||
|
```
|
||||||
|
|
||||||
|
This will convert any Solidwork supported file format to ```step```. For drawings, assemblies and parts, ```jpg```, ```pdf``` and other 2D formats are supported. Conversions will use the options set in your Solidworks settings.
|
||||||
|
|
||||||
BIN
docs/assets/integration-as-custom-menu-register.PNG
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
docs/assets/integration-as-custom-menu.PNG
Normal file
|
After Width: | Height: | Size: 29 KiB |
20
format.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
/*
|
||||||
|
export const render = (result: any, options: Options) => {
|
||||||
|
switch (options.format) {
|
||||||
|
case OutputFormat.text: {
|
||||||
|
//@TODO: human readable format
|
||||||
|
return JSON.stringify(result, null, 2);
|
||||||
|
}
|
||||||
|
case OutputFormat.json: {
|
||||||
|
return JSON.stringify(result, null, 2);
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
//private, should never happen since options had to be sanitized
|
||||||
|
error('format::render Invalid value in options.format');
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
//# sourceMappingURL=format.js.map
|
||||||
1
format.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"format.js","sourceRoot":"","sources":["src/format.ts"],"names":[],"mappings":";;AAGA;;;;;;;;;;;;;;;;GAgBG"}
|
||||||
22
formatter.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.sizeToString = void 0;
|
||||||
|
exports.sizeToString = (bytes, si = true) => {
|
||||||
|
var units;
|
||||||
|
var u;
|
||||||
|
var b = bytes;
|
||||||
|
var thresh = si ? 1000 : 1024;
|
||||||
|
if (Math.abs(b) < thresh) {
|
||||||
|
return b + ' B';
|
||||||
|
}
|
||||||
|
units = si
|
||||||
|
? ['kB', 'MB', 'GB', 'TB']
|
||||||
|
: ['KiB', 'MiB', 'GiB', 'TiB'];
|
||||||
|
u = -1;
|
||||||
|
do {
|
||||||
|
b /= thresh;
|
||||||
|
++u;
|
||||||
|
} while (Math.abs(b) >= thresh && u < units.length - 1);
|
||||||
|
return b.toFixed(1) + ' ' + units[u];
|
||||||
|
};
|
||||||
|
//# sourceMappingURL=formatter.js.map
|
||||||
1
formatter.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["src/formatter.ts"],"names":[],"mappings":";;;AAAa,QAAA,YAAY,GAAG,CAAC,KAAa,EAAE,KAAc,IAAI,EAAE,EAAE;IAC9D,IAAI,KAAK,CAAC;IACV,IAAI,CAAC,CAAC;IACN,IAAI,CAAC,GAAG,KAAK,CAAC;IACd,IAAI,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9B,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE;QACtB,OAAO,CAAC,GAAG,IAAI,CAAC;KACnB;IACD,KAAK,GAAG,EAAE;QACN,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;QAC1B,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC,GAAG,CAAC,CAAC,CAAC;IACP,GAAG;QACC,CAAC,IAAI,MAAM,CAAC;QACZ,EAAE,CAAC,CAAC;KACP,QAAQ,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,MAAM,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE;IACxD,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC,CAAC"}
|
||||||
159
fusion360/.incoming/setup-sheets.cpp
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
#include <Core/CoreAll.h>
|
||||||
|
#include <CAM/CAMAll.h>
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#else
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace adsk::core;
|
||||||
|
using namespace adsk::cam;
|
||||||
|
|
||||||
|
Ptr<UserInterface> ui;
|
||||||
|
|
||||||
|
extern "C" XI_EXPORT bool run(const char* context)
|
||||||
|
{
|
||||||
|
Ptr<Application> app = Application::get();
|
||||||
|
if (!app)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ui = app->userInterface();
|
||||||
|
if (!ui)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Ptr<Document> doc = app->activeDocument();
|
||||||
|
if (!doc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Ptr<Products> products = doc->products();
|
||||||
|
if(!products)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Ptr<CAM> camProduct = products->itemByProductType("CAMProductType");
|
||||||
|
if (!camProduct)
|
||||||
|
{
|
||||||
|
ui->messageBox("There are no CAM operations in the active document. This script requires the active document to contain at least one CAM operation.",
|
||||||
|
"No CAM Operations Exist", MessageBoxButtonTypes::OKButtonType, MessageBoxIconTypes::CriticalIconType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string outputFolder = camProduct->temporaryFolder();
|
||||||
|
SetupSheetFormats sheetFormat = SetupSheetFormats::HTMLFormat;
|
||||||
|
DialogResults dlgResults = ui->messageBox("View setup sheets when done?", "Generate Setup Sheets",
|
||||||
|
MessageBoxButtonTypes::YesNoButtonType,
|
||||||
|
MessageBoxIconTypes::QuestionIconType);
|
||||||
|
bool viewResults = dlgResults == DialogResults::DialogNo ? false : true;
|
||||||
|
|
||||||
|
int scenario = 3;
|
||||||
|
switch (scenario)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
ui->messageBox("Setup sheets for all operations will be generated.");
|
||||||
|
camProduct->generateAllSetupSheets(sheetFormat, outputFolder, viewResults);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
ui->messageBox("Setup sheets for operations in the first setup will be generated.");
|
||||||
|
Ptr<Setups> setups = camProduct->setups();
|
||||||
|
if (!setups)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Ptr<Setup> setup = setups->item(0);
|
||||||
|
if (!setup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
camProduct->generateSetupSheet(setup, sheetFormat, outputFolder, viewResults);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
ui->messageBox("A setup sheet for the first operation in the first setup will be generated.");
|
||||||
|
Ptr<Setups> setups = camProduct->setups();
|
||||||
|
if (!setups)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Ptr<Setup> setup = setups->item(0);
|
||||||
|
if (!setup)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// It is a set of Operations, Folders and Patterns.
|
||||||
|
Ptr<ObjectCollection> objects = setup->allOperations();
|
||||||
|
if (!objects)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (objects->count() == 0)
|
||||||
|
{
|
||||||
|
ui->messageBox("There is not any operation in the first setup!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ptr<Base> baseObject = objects->item(0);
|
||||||
|
if (!baseObject)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Operation* pOperation = baseObject->query<Operation>();
|
||||||
|
if (!pOperation)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Ptr<Operation> operation(pOperation, false);
|
||||||
|
if (operation->hasToolpath())
|
||||||
|
{
|
||||||
|
camProduct->generateSetupSheet(operation, sheetFormat, outputFolder, viewResults);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->messageBox("This operation has no toolpath. A valid toolpath must exist in order for a setup sheet to be generated.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show output folder.
|
||||||
|
ui->messageBox("Setup Sheets have been generated in '" + outputFolder + "'.");
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
ShellExecuteA(nullptr, "open", outputFolder.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
|
#else
|
||||||
|
std::string command = "open " + outputFolder;
|
||||||
|
system(command.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Active CAM workspace if it is not the active one.
|
||||||
|
if (ui->activeWorkspace()->name() != "CAM")
|
||||||
|
{
|
||||||
|
DialogResults result = ui->messageBox("Activate the CAM Workspace?", "CAM Workspace Activate",
|
||||||
|
MessageBoxButtonTypes::YesNoButtonType, MessageBoxIconTypes::QuestionIconType);
|
||||||
|
bool activeCAMWorkspace = result == DialogResults::DialogYes ? true : false;
|
||||||
|
if (activeCAMWorkspace)
|
||||||
|
{
|
||||||
|
Ptr<Workspace> camWorkspace = ui->workspaces()->itemById("CAMEnvironment");
|
||||||
|
camWorkspace->activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef XI_WIN
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain(HMODULE hmodule, DWORD reason, LPVOID reserved)
|
||||||
|
{
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // XI_WIN
|
||||||
0
fusion360/Readme.md
Normal file
17
fusion360/python/AddInSamples/AddInSample/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Python: Attach",
|
||||||
|
"type": "python",
|
||||||
|
"request": "attach",
|
||||||
|
"pathMappings": [ {
|
||||||
|
"localRoot": "${workspaceRoot}",
|
||||||
|
"remoteRoot": "${workspaceRoot}"}],
|
||||||
|
"osx": {"filePath":"${file}"},
|
||||||
|
"windows": {"filePath":"${file}"},
|
||||||
|
"port": 9000,
|
||||||
|
"host": "localhost"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"autodeskProduct":"Fusion360",
|
||||||
|
"type":"addin",
|
||||||
|
"id":"319679C5-AF6D-4A46-862D-93414F1AE117",
|
||||||
|
"author":"Autodesk Inc.",
|
||||||
|
"description":{
|
||||||
|
"": "This is sample addin.",
|
||||||
|
"1033": "This is sample addin.",
|
||||||
|
"2052": "这是一个附加模块的例子。"
|
||||||
|
},
|
||||||
|
"version":"0.0.1",
|
||||||
|
"runOnStartup":false,
|
||||||
|
"supportedOS":"windows|mac"
|
||||||
|
}
|
||||||
314
fusion360/python/AddInSamples/AddInSample/AddInSample.py
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
#Author-Autodesk Inc.
|
||||||
|
#Description-This is sample addin.
|
||||||
|
|
||||||
|
import adsk.core, adsk.fusion, traceback, os, gettext
|
||||||
|
|
||||||
|
btnCmdIdOnQAT = 'demoButtonCommandOnQAT'
|
||||||
|
listCmdIdOnQAT = 'demoListCommandOnQAT'
|
||||||
|
commandIdOnPanel = 'demoCommandOnPanel'
|
||||||
|
selectionInputId = 'selectionInput'
|
||||||
|
distanceInputId = 'distanceValueCommandInput'
|
||||||
|
panelId = 'SolidCreatePanel'
|
||||||
|
|
||||||
|
# global set of event handlers to keep them referenced for the duration of the command
|
||||||
|
handlers = []
|
||||||
|
|
||||||
|
# Support localization
|
||||||
|
_ = None
|
||||||
|
def getUserLanguage():
|
||||||
|
app = adsk.core.Application.get()
|
||||||
|
|
||||||
|
return {
|
||||||
|
adsk.core.UserLanguages.ChinesePRCLanguage: "zh-CN",
|
||||||
|
adsk.core.UserLanguages.ChineseTaiwanLanguage: "zh-TW",
|
||||||
|
adsk.core.UserLanguages.CzechLanguage: "cs-CZ",
|
||||||
|
adsk.core.UserLanguages.EnglishLanguage: "en-US",
|
||||||
|
adsk.core.UserLanguages.FrenchLanguage: "fr-FR",
|
||||||
|
adsk.core.UserLanguages.GermanLanguage: "de-DE",
|
||||||
|
adsk.core.UserLanguages.HungarianLanguage: "hu-HU",
|
||||||
|
adsk.core.UserLanguages.ItalianLanguage: "it-IT",
|
||||||
|
adsk.core.UserLanguages.JapaneseLanguage: "ja-JP",
|
||||||
|
adsk.core.UserLanguages.KoreanLanguage: "ko-KR",
|
||||||
|
adsk.core.UserLanguages.PolishLanguage: "pl-PL",
|
||||||
|
adsk.core.UserLanguages.PortugueseBrazilianLanguage: "pt-BR",
|
||||||
|
adsk.core.UserLanguages.RussianLanguage: "ru-RU",
|
||||||
|
adsk.core.UserLanguages.SpanishLanguage: "es-ES"
|
||||||
|
}[app.preferences.generalPreferences.userLanguage]
|
||||||
|
|
||||||
|
# Get loc string by language
|
||||||
|
def getLocStrings():
|
||||||
|
currentDir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
return gettext.translation('resource', currentDir, [getUserLanguage(), "en-US"]).gettext
|
||||||
|
|
||||||
|
def commandDefinitionById(id):
|
||||||
|
app = adsk.core.Application.get()
|
||||||
|
ui = app.userInterface
|
||||||
|
if not id:
|
||||||
|
ui.messageBox(_('commandDefinition id is not specified'))
|
||||||
|
return None
|
||||||
|
commandDefinitions_ = ui.commandDefinitions
|
||||||
|
commandDefinition_ = commandDefinitions_.itemById(id)
|
||||||
|
return commandDefinition_
|
||||||
|
|
||||||
|
def commandControlByIdForQAT(id):
|
||||||
|
app = adsk.core.Application.get()
|
||||||
|
ui = app.userInterface
|
||||||
|
if not id:
|
||||||
|
ui.messageBox(_('commandControl id is not specified'))
|
||||||
|
return None
|
||||||
|
toolbars_ = ui.toolbars
|
||||||
|
toolbarQAT_ = toolbars_.itemById('QAT')
|
||||||
|
toolbarControls_ = toolbarQAT_.controls
|
||||||
|
toolbarControl_ = toolbarControls_.itemById(id)
|
||||||
|
return toolbarControl_
|
||||||
|
|
||||||
|
def commandControlByIdForPanel(id):
|
||||||
|
app = adsk.core.Application.get()
|
||||||
|
ui = app.userInterface
|
||||||
|
if not id:
|
||||||
|
ui.messageBox(_('commandControl id is not specified'))
|
||||||
|
return None
|
||||||
|
workspaces_ = ui.workspaces
|
||||||
|
modelingWorkspace_ = workspaces_.itemById('FusionSolidEnvironment')
|
||||||
|
toolbarPanels_ = modelingWorkspace_.toolbarPanels
|
||||||
|
toolbarPanel_ = toolbarPanels_.itemById(panelId)
|
||||||
|
toolbarControls_ = toolbarPanel_.controls
|
||||||
|
toolbarControl_ = toolbarControls_.itemById(id)
|
||||||
|
return toolbarControl_
|
||||||
|
|
||||||
|
def destroyObject(uiObj, tobeDeleteObj):
|
||||||
|
if uiObj and tobeDeleteObj:
|
||||||
|
if tobeDeleteObj.isValid:
|
||||||
|
tobeDeleteObj.deleteMe()
|
||||||
|
else:
|
||||||
|
uiObj.messageBox(_('tobeDeleteObj is not a valid object'))
|
||||||
|
|
||||||
|
def run(context):
|
||||||
|
ui = None
|
||||||
|
try:
|
||||||
|
app = adsk.core.Application.get()
|
||||||
|
ui = app.userInterface
|
||||||
|
|
||||||
|
global _
|
||||||
|
_ = getLocStrings()
|
||||||
|
|
||||||
|
commandName = _('Demo')
|
||||||
|
commandDescription = _('Demo Command')
|
||||||
|
commandResources = './resources'
|
||||||
|
iconResources = './resources'
|
||||||
|
|
||||||
|
class InputChangedHandler(adsk.core.InputChangedEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
command = args.firingEvent.sender
|
||||||
|
cmdInput = args.input
|
||||||
|
if cmdInput.id != distanceInputId:
|
||||||
|
ui.messageBox(_('Input: {} changed event triggered').format(command.parentCommandDefinition.id))
|
||||||
|
|
||||||
|
if cmdInput.id == selectionInputId:
|
||||||
|
inputs = cmdInput.commandInputs
|
||||||
|
distanceInput = inputs.itemById(distanceInputId)
|
||||||
|
|
||||||
|
if cmdInput.selectionCount > 0:
|
||||||
|
sel = cmdInput.selection(0)
|
||||||
|
selPt = sel.point
|
||||||
|
ent = sel.entity
|
||||||
|
plane = ent.geometry
|
||||||
|
|
||||||
|
distanceInput.setManipulator(selPt, plane.normal)
|
||||||
|
distanceInput.expression = "10mm * 2"
|
||||||
|
distanceInput.isEnabled = True
|
||||||
|
distanceInput.isVisible = True
|
||||||
|
else:
|
||||||
|
distanceInput.isEnabled = False
|
||||||
|
distanceInput.isVisible = False
|
||||||
|
except:
|
||||||
|
if ui:
|
||||||
|
ui.messageBox(_('Input changed event failed: {}').format(traceback.format_exc()))
|
||||||
|
|
||||||
|
class CommandExecuteHandler(adsk.core.CommandEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
command = args.firingEvent.sender
|
||||||
|
ui.messageBox(_('command: {} executed successfully').format(command.parentCommandDefinition.id))
|
||||||
|
except:
|
||||||
|
if ui:
|
||||||
|
ui.messageBox(_('command executed failed: {}').format(traceback.format_exc()))
|
||||||
|
|
||||||
|
class CommandCreatedEventHandlerPanel(adsk.core.CommandCreatedEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
cmd = args.command
|
||||||
|
cmd.helpFile = 'help.html'
|
||||||
|
|
||||||
|
onExecute = CommandExecuteHandler()
|
||||||
|
cmd.execute.add(onExecute)
|
||||||
|
|
||||||
|
onInputChanged = InputChangedHandler()
|
||||||
|
cmd.inputChanged.add(onInputChanged)
|
||||||
|
# keep the handler referenced beyond this function
|
||||||
|
handlers.append(onExecute)
|
||||||
|
handlers.append(onInputChanged)
|
||||||
|
|
||||||
|
commandInputs_ = cmd.commandInputs
|
||||||
|
commandInputs_.addValueInput('valueInput_', _('Value'), 'cm', adsk.core.ValueInput.createByString('0.0 cm'))
|
||||||
|
commandInputs_.addBoolValueInput('boolvalueInput_', _('Bool'), True)
|
||||||
|
commandInputs_.addStringValueInput('stringValueInput_', _('String Value'), _('Default value'))
|
||||||
|
selInput = commandInputs_.addSelectionInput(selectionInputId, _('Selection'), _('Select one'))
|
||||||
|
selInput.addSelectionFilter('PlanarFaces')
|
||||||
|
selInput.addSelectionFilter('ConstructionPlanes')
|
||||||
|
dropDownCommandInput_ = commandInputs_.addDropDownCommandInput('dropdownCommandInput', _('Drop Down'), adsk.core.DropDownStyles.LabeledIconDropDownStyle)
|
||||||
|
dropDownItems_ = dropDownCommandInput_.listItems
|
||||||
|
dropDownItems_.add(_('ListItem 1'), True)
|
||||||
|
dropDownItems_.add(_('ListItem 2'), False)
|
||||||
|
dropDownItems_.add(_('ListItem 3'), False)
|
||||||
|
dropDownCommandInput2_ = commandInputs_.addDropDownCommandInput('dropDownCommandInput2', _('Drop Down2'), adsk.core.DropDownStyles.CheckBoxDropDownStyle)
|
||||||
|
dropDownCommandInputListItems_ = dropDownCommandInput2_.listItems
|
||||||
|
dropDownCommandInputListItems_.add(_('ListItem 1'), True)
|
||||||
|
dropDownCommandInputListItems_.add(_('ListItem 2'), True)
|
||||||
|
dropDownCommandInputListItems_.add(_('ListItem 3'), False)
|
||||||
|
commandInputs_.addFloatSliderCommandInput('floatSliderCommandInput', _('Slider'), 'cm', 0.0, 10.0, True)
|
||||||
|
buttonRowCommandInput_ = commandInputs_.addButtonRowCommandInput('buttonRowCommandInput', _('Button Row'), False)
|
||||||
|
buttonRowCommandInputListItems_ = buttonRowCommandInput_.listItems
|
||||||
|
buttonRowCommandInputListItems_.add(_('ListItem 1'), False, iconResources)
|
||||||
|
buttonRowCommandInputListItems_.add(_('ListItem 2'), True, iconResources)
|
||||||
|
buttonRowCommandInputListItems_.add(_('ListItem 3'), False, iconResources)
|
||||||
|
|
||||||
|
distanceInput = commandInputs_.addDistanceValueCommandInput(distanceInputId, _('Distance'), adsk.core.ValueInput.createByReal(0.0))
|
||||||
|
distanceInput.isEnabled = False
|
||||||
|
distanceInput.isVisible = False
|
||||||
|
distanceInput.minimumValue = 1.0
|
||||||
|
distanceInput.maximumValue = 10.0
|
||||||
|
|
||||||
|
directionInput = commandInputs_.addDirectionCommandInput('directionInput', _('Direction'))
|
||||||
|
directionInput.setManipulator(adsk.core.Point3D.create(0,0,0), adsk.core.Vector3D.create(1,0,0))
|
||||||
|
directionInput2 = commandInputs_.addDirectionCommandInput('directionInput2', _('Direction2'), iconResources)
|
||||||
|
directionInput2.setManipulator(adsk.core.Point3D.create(0,0,0), adsk.core.Vector3D.create(0,1,0))
|
||||||
|
|
||||||
|
ui.messageBox(_('Panel command created successfully'))
|
||||||
|
except:
|
||||||
|
if ui:
|
||||||
|
ui.messageBox(_('Panel command created failed: {}').format(traceback.format_exc()))
|
||||||
|
|
||||||
|
class CommandCreatedEventHandlerQAT(adsk.core.CommandCreatedEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
command = args.command
|
||||||
|
onExecute = CommandExecuteHandler()
|
||||||
|
command.execute.add(onExecute)
|
||||||
|
# keep the handler referenced beyond this function
|
||||||
|
handlers.append(onExecute)
|
||||||
|
ui.messageBox(_('QAT command created successfully'))
|
||||||
|
except:
|
||||||
|
ui.messageBox(_('QAT command created failed: {}').format(traceback.format_exc()))
|
||||||
|
|
||||||
|
commandDefinitions_ = ui.commandDefinitions
|
||||||
|
|
||||||
|
# add a button command on Quick Access Toolbar
|
||||||
|
toolbars_ = ui.toolbars
|
||||||
|
toolbarQAT_ = toolbars_.itemById('QAT')
|
||||||
|
toolbarControlsQAT_ = toolbarQAT_.controls
|
||||||
|
btnCmdToolbarCtlQAT_ = toolbarControlsQAT_.itemById(btnCmdIdOnQAT)
|
||||||
|
if not btnCmdToolbarCtlQAT_:
|
||||||
|
btnCmdDefinitionQAT_ = commandDefinitions_.itemById(btnCmdIdOnQAT)
|
||||||
|
if not btnCmdDefinitionQAT_:
|
||||||
|
btnCmdDefinitionQAT_ = commandDefinitions_.addButtonDefinition(btnCmdIdOnQAT, commandName, commandDescription, commandResources)
|
||||||
|
onButtonCommandCreated = CommandCreatedEventHandlerQAT()
|
||||||
|
btnCmdDefinitionQAT_.commandCreated.add(onButtonCommandCreated)
|
||||||
|
# keep the handler referenced beyond this function
|
||||||
|
handlers.append(onButtonCommandCreated)
|
||||||
|
btnCmdToolbarCtlQAT_ = toolbarControlsQAT_.addCommand(btnCmdDefinitionQAT_)
|
||||||
|
btnCmdToolbarCtlQAT_.isVisible = True
|
||||||
|
ui.messageBox(_('A demo button command is successfully added to the Quick Access Toolbar'))
|
||||||
|
|
||||||
|
# add a list command on Quick Access Toolbar
|
||||||
|
listCmdToolbarCtlQAT_ = toolbarControlsQAT_.itemById(listCmdIdOnQAT)
|
||||||
|
if not listCmdToolbarCtlQAT_:
|
||||||
|
listCmdDefinitionQAT_ = commandDefinitions_.itemById(listCmdIdOnQAT)
|
||||||
|
if not listCmdDefinitionQAT_:
|
||||||
|
listCmdDefinitionQAT_ = commandDefinitions_.addListDefinition(listCmdIdOnQAT, commandName, adsk.core.ListControlDisplayTypes.CheckBoxListType, commandResources)
|
||||||
|
listItems_ = adsk.core.ListControlDefinition.cast(listCmdDefinitionQAT_.controlDefinition).listItems
|
||||||
|
listItems_.add('Demo item 1', True)
|
||||||
|
listItems_.add('Demo item 2', False)
|
||||||
|
listItems_.add('Demo item 3', False)
|
||||||
|
|
||||||
|
onListCommandCreated = CommandCreatedEventHandlerQAT()
|
||||||
|
listCmdDefinitionQAT_.commandCreated.add(onListCommandCreated)
|
||||||
|
# keep the handler referenced beyond this function
|
||||||
|
handlers.append(onListCommandCreated)
|
||||||
|
listCmdToolbarCtlQAT_ = toolbarControlsQAT_.addCommand(listCmdDefinitionQAT_)
|
||||||
|
listCmdToolbarCtlQAT_.isVisible = True
|
||||||
|
ui.messageBox(_('A demo list command is successfully added to the Quick Access Toolbar'))
|
||||||
|
|
||||||
|
# add a command on create panel in modeling workspace
|
||||||
|
workspaces_ = ui.workspaces
|
||||||
|
modelingWorkspace_ = workspaces_.itemById('FusionSolidEnvironment')
|
||||||
|
toolbarPanels_ = modelingWorkspace_.toolbarPanels
|
||||||
|
toolbarPanel_ = toolbarPanels_.itemById(panelId) # add the new command under the CREATE panel
|
||||||
|
toolbarControlsPanel_ = toolbarPanel_.controls
|
||||||
|
toolbarControlPanel_ = toolbarControlsPanel_.itemById(commandIdOnPanel)
|
||||||
|
if not toolbarControlPanel_:
|
||||||
|
commandDefinitionPanel_ = commandDefinitions_.itemById(commandIdOnPanel)
|
||||||
|
if not commandDefinitionPanel_:
|
||||||
|
commandDefinitionPanel_ = commandDefinitions_.addButtonDefinition(commandIdOnPanel, commandName, commandDescription, commandResources)
|
||||||
|
onCommandCreated = CommandCreatedEventHandlerPanel()
|
||||||
|
commandDefinitionPanel_.commandCreated.add(onCommandCreated)
|
||||||
|
# keep the handler referenced beyond this function
|
||||||
|
handlers.append(onCommandCreated)
|
||||||
|
toolbarControlPanel_ = toolbarControlsPanel_.addCommand(commandDefinitionPanel_)
|
||||||
|
toolbarControlPanel_.isVisible = True
|
||||||
|
ui.messageBox(_('A demo command is successfully added to the create panel in modeling workspace'))
|
||||||
|
|
||||||
|
except:
|
||||||
|
if ui:
|
||||||
|
ui.messageBox(_('AddIn Start Failed: {}').format(traceback.format_exc()))
|
||||||
|
|
||||||
|
def stop(context):
|
||||||
|
ui = None
|
||||||
|
try:
|
||||||
|
app = adsk.core.Application.get()
|
||||||
|
ui = app.userInterface
|
||||||
|
objArrayQAT = []
|
||||||
|
objArrayPanel = []
|
||||||
|
|
||||||
|
btnCmdToolbarCtlQAT_ = commandControlByIdForQAT(btnCmdIdOnQAT)
|
||||||
|
if btnCmdToolbarCtlQAT_:
|
||||||
|
objArrayQAT.append(btnCmdToolbarCtlQAT_)
|
||||||
|
|
||||||
|
btnCmdDefinitionQAT_ = commandDefinitionById(btnCmdIdOnQAT)
|
||||||
|
if btnCmdDefinitionQAT_:
|
||||||
|
objArrayQAT.append(btnCmdDefinitionQAT_)
|
||||||
|
|
||||||
|
listCmdToolbarCtlQAT_ = commandControlByIdForQAT(listCmdIdOnQAT)
|
||||||
|
if listCmdToolbarCtlQAT_:
|
||||||
|
objArrayQAT.append(listCmdToolbarCtlQAT_)
|
||||||
|
|
||||||
|
listCmdDefinitionQAT_ = commandDefinitionById(listCmdIdOnQAT)
|
||||||
|
if listCmdDefinitionQAT_:
|
||||||
|
objArrayQAT.append(listCmdDefinitionQAT_)
|
||||||
|
|
||||||
|
commandControlPanel_ = commandControlByIdForPanel(commandIdOnPanel)
|
||||||
|
if commandControlPanel_:
|
||||||
|
objArrayPanel.append(commandControlPanel_)
|
||||||
|
|
||||||
|
commandDefinitionPanel_ = commandDefinitionById(commandIdOnPanel)
|
||||||
|
if commandDefinitionPanel_:
|
||||||
|
objArrayPanel.append(commandDefinitionPanel_)
|
||||||
|
|
||||||
|
for obj in objArrayQAT:
|
||||||
|
destroyObject(ui, obj)
|
||||||
|
|
||||||
|
for obj in objArrayPanel:
|
||||||
|
destroyObject(ui, obj)
|
||||||
|
|
||||||
|
except:
|
||||||
|
if ui:
|
||||||
|
ui.messageBox(_('AddIn Stop Failed: {}').format(traceback.format_exc()))
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR ORGANIZATION
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"POT-Creation-Date: 2015-08-03 15:59+China Standard Time\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "commandDefinition id is not specified"
|
||||||
|
msgstr "commandDefinition id is not specified"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "commandControl id is not specified"
|
||||||
|
msgstr "commandControl id is not specified"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "tobeDeleteObj is not a valid object"
|
||||||
|
msgstr "tobeDeleteObj is not a valid object"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Demo"
|
||||||
|
msgstr "Demo"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Demo Command"
|
||||||
|
msgstr "Demo Command"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Input: {} changed event triggered"
|
||||||
|
msgstr "Input: {} changed event triggered"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Input changed event failed: {}"
|
||||||
|
msgstr "Input changed event failed: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "command: {} executed successfully"
|
||||||
|
msgstr "command: {} executed successfully"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "command executed failed: {}"
|
||||||
|
msgstr "command executed failed: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Value"
|
||||||
|
msgstr "Value"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Checked"
|
||||||
|
msgstr "Checked"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Default value"
|
||||||
|
msgstr "Default value"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "String Value"
|
||||||
|
msgstr "String Value"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Select one"
|
||||||
|
msgstr "Select one"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Selection"
|
||||||
|
msgstr "Selection"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Drop Down"
|
||||||
|
msgstr "Drop Down"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Drop Down2"
|
||||||
|
msgstr "Drop Down2"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "ListItem 1"
|
||||||
|
msgstr "ListItem 1"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "ListItem 2"
|
||||||
|
msgstr "ListItem 2"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "ListItem 3"
|
||||||
|
msgstr "ListItem 3"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Slider"
|
||||||
|
msgstr "Slider"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Button Row"
|
||||||
|
msgstr "Button Row"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Panel command created successfully"
|
||||||
|
msgstr "Panel command created successfully"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Panel command created failed: {}"
|
||||||
|
msgstr "Panel command created failed: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "QAT command created successfully"
|
||||||
|
msgstr "QAT command created successfully"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "QAT command created failed: {}"
|
||||||
|
msgstr "QAT command created failed: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "A demo command button is successfully added to the Quick Access Toolbar"
|
||||||
|
msgstr "A demo command button is successfully added to the Quick Access Toolbar"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "A demo command is successfully added to the create panel in modeling workspace"
|
||||||
|
msgstr "A demo command is successfully added to the create panel in modeling workspace"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "AddIn Start Failed: {}"
|
||||||
|
msgstr "AddIn Start Failed: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "AddIn Stop Failed: {}"
|
||||||
|
msgstr "AddIn Stop Failed: {}"
|
||||||
6
fusion360/python/AddInSamples/AddInSample/help.html
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
This is help file of this addin.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 726 B |
|
After Width: | Height: | Size: 726 B |
BIN
fusion360/python/AddInSamples/AddInSample/resources/16x16.png
Normal file
|
After Width: | Height: | Size: 708 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
BIN
fusion360/python/AddInSamples/AddInSample/resources/32x32.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,136 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR ORGANIZATION
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"POT-Creation-Date: 2015-08-04 12:47+China Standard Time\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
|
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "commandDefinition id is not specified"
|
||||||
|
msgstr "没有指定commandDefinition id"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "commandControl id is not specified"
|
||||||
|
msgstr "没有指定commandControl id"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "tobeDeleteObj is not a valid object"
|
||||||
|
msgstr "tobeDeleteObj不是一个有效的对象"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Demo"
|
||||||
|
msgstr "演示"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Demo Command"
|
||||||
|
msgstr "演示命令"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Input: {} changed event triggered"
|
||||||
|
msgstr "触发事件Input: {} changed"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Input changed event failed: {}"
|
||||||
|
msgstr "输入变化事件失败: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "command: {} executed successfully"
|
||||||
|
msgstr "命令: {} 执行成功"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "命令执行失败: {}"
|
||||||
|
msgstr "命令执行失败: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Value"
|
||||||
|
msgstr "值"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Checked"
|
||||||
|
msgstr "选中"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Default value"
|
||||||
|
msgstr "默认值"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "String Value"
|
||||||
|
msgstr "字符串"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Select one"
|
||||||
|
msgstr "选一个"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Selection"
|
||||||
|
msgstr "选择"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Drop Down"
|
||||||
|
msgstr "下拉框"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Drop Down2"
|
||||||
|
msgstr "下拉框2"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "ListItem 1"
|
||||||
|
msgstr "列表项 1"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "ListItem 2"
|
||||||
|
msgstr "列表项 2"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "ListItem 3"
|
||||||
|
msgstr "列表项 3"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Slider"
|
||||||
|
msgstr "滚动条"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Button Row"
|
||||||
|
msgstr "按钮行"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Panel command created successfully"
|
||||||
|
msgstr "面板命令创建成功"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "Panel command created failed: {}"
|
||||||
|
msgstr "面板命令创建失败: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "QAT command created successfully"
|
||||||
|
msgstr "QAT命令创建成功"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "QAT command created failed: {}"
|
||||||
|
msgstr "QAT命令创建失败: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "A demo command button is successfully added to the Quick Access Toolbar"
|
||||||
|
msgstr "一个演示命令被成功的添加到QAT"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "A demo command is successfully added to the create panel in modeling workspace"
|
||||||
|
msgstr "一个演示命令被成功的添加到创建面板"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "AddIn Start Failed: {}"
|
||||||
|
msgstr "附加模块启动失败: {}"
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "AddIn Stop Failed: {}"
|
||||||
|
msgstr "附加模块启动成功: {}"
|
||||||
17
fusion360/python/AddInSamples/CustomWorkspaceSample/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Python: Attach",
|
||||||
|
"type": "python",
|
||||||
|
"request": "attach",
|
||||||
|
"pathMappings": [ {
|
||||||
|
"localRoot": "${workspaceRoot}",
|
||||||
|
"remoteRoot": "${workspaceRoot}"}],
|
||||||
|
"osx": {"filePath":"${file}"},
|
||||||
|
"windows": {"filePath":"${file}"},
|
||||||
|
"port": 9000,
|
||||||
|
"host": "localhost"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
fusion360/python/AddInSamples/SpurGear/Resources/GearEnglish.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
fusion360/python/AddInSamples/SpurGear/Resources/GearMetric.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 965 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
13
fusion360/python/AddInSamples/SpurGear/SpurGear.manifest
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"autodeskProduct": "Fusion360",
|
||||||
|
"type": "addin",
|
||||||
|
"id": "6b509eec-34ca-4044-875d-cfb30563b658",
|
||||||
|
"author": "",
|
||||||
|
"description": {
|
||||||
|
"": "Creates a spur gear component."
|
||||||
|
},
|
||||||
|
"version": "",
|
||||||
|
"runOnStartup": false,
|
||||||
|
"supportedOS": "windows|mac",
|
||||||
|
"editEnabled": true
|
||||||
|
}
|
||||||
772
fusion360/python/AddInSamples/SpurGear/SpurGear.py
Normal file
@ -0,0 +1,772 @@
|
|||||||
|
#Author-Brian Ekins
|
||||||
|
#Description-Creates a spur gear component.
|
||||||
|
|
||||||
|
# AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. AUTODESK SPECIFICALLY
|
||||||
|
# DISCLAIMS ANY IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.
|
||||||
|
# AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
|
||||||
|
# UNINTERRUPTED OR ERROR FREE.
|
||||||
|
|
||||||
|
|
||||||
|
import adsk.core, adsk.fusion, adsk.cam, traceback
|
||||||
|
import math
|
||||||
|
|
||||||
|
# Globals
|
||||||
|
_app = adsk.core.Application.cast(None)
|
||||||
|
_ui = adsk.core.UserInterface.cast(None)
|
||||||
|
_units = ''
|
||||||
|
|
||||||
|
# Command inputs
|
||||||
|
_imgInputEnglish = adsk.core.ImageCommandInput.cast(None)
|
||||||
|
_imgInputMetric = adsk.core.ImageCommandInput.cast(None)
|
||||||
|
_standard = adsk.core.DropDownCommandInput.cast(None)
|
||||||
|
_pressureAngle = adsk.core.DropDownCommandInput.cast(None)
|
||||||
|
_pressureAngleCustom = adsk.core.ValueCommandInput.cast(None)
|
||||||
|
_backlash = adsk.core.ValueCommandInput.cast(None)
|
||||||
|
_diaPitch = adsk.core.ValueCommandInput.cast(None)
|
||||||
|
_module = adsk.core.ValueCommandInput.cast(None)
|
||||||
|
_numTeeth = adsk.core.StringValueCommandInput.cast(None)
|
||||||
|
_rootFilletRad = adsk.core.ValueCommandInput.cast(None)
|
||||||
|
_thickness = adsk.core.ValueCommandInput.cast(None)
|
||||||
|
_holeDiam = adsk.core.ValueCommandInput.cast(None)
|
||||||
|
_pitchDiam = adsk.core.TextBoxCommandInput.cast(None)
|
||||||
|
_errMessage = adsk.core.TextBoxCommandInput.cast(None)
|
||||||
|
|
||||||
|
_handlers = []
|
||||||
|
|
||||||
|
def run(context):
|
||||||
|
try:
|
||||||
|
global _app, _ui
|
||||||
|
_app = adsk.core.Application.get()
|
||||||
|
_ui = _app.userInterface
|
||||||
|
|
||||||
|
# Create a command definition and add a button to the CREATE panel.
|
||||||
|
cmdDef = _ui.commandDefinitions.addButtonDefinition('adskSpurGearPythonAddIn', 'Spur Gear', 'Creates a spur gear component', 'Resources/SpurGear')
|
||||||
|
createPanel = _ui.allToolbarPanels.itemById('SolidCreatePanel')
|
||||||
|
gearButton = createPanel.controls.addCommand(cmdDef)
|
||||||
|
|
||||||
|
# Connect to the command created event.
|
||||||
|
onCommandCreated = GearCommandCreatedHandler()
|
||||||
|
cmdDef.commandCreated.add(onCommandCreated)
|
||||||
|
_handlers.append(onCommandCreated)
|
||||||
|
|
||||||
|
if context['IsApplicationStartup'] == False:
|
||||||
|
_ui.messageBox('The "Spur Gear" command has been added\nto the CREATE panel of the MODEL workspace.')
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
def stop(context):
|
||||||
|
try:
|
||||||
|
createPanel = _ui.allToolbarPanels.itemById('SolidCreatePanel')
|
||||||
|
gearButton = createPanel.controls.itemById('adskSpurGearPythonAddIn')
|
||||||
|
if gearButton:
|
||||||
|
gearButton.deleteMe()
|
||||||
|
|
||||||
|
cmdDef = _ui.commandDefinitions.itemById('adskSpurGearPythonAddIn')
|
||||||
|
if cmdDef:
|
||||||
|
cmdDef.deleteMe()
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
# Verfies that a value command input has a valid expression and returns the
|
||||||
|
# value if it does. Otherwise it returns False. This works around a
|
||||||
|
# problem where when you get the value from a ValueCommandInput it causes the
|
||||||
|
# current expression to be evaluated and updates the display. Some new functionality
|
||||||
|
# is being added in the future to the ValueCommandInput object that will make
|
||||||
|
# this easier and should make this function obsolete.
|
||||||
|
def getCommandInputValue(commandInput, unitType):
|
||||||
|
try:
|
||||||
|
valCommandInput = adsk.core.ValueCommandInput.cast(commandInput)
|
||||||
|
if not valCommandInput:
|
||||||
|
return (False, 0)
|
||||||
|
|
||||||
|
# Verify that the expression is valid.
|
||||||
|
des = adsk.fusion.Design.cast(_app.activeProduct)
|
||||||
|
unitsMgr = des.unitsManager
|
||||||
|
|
||||||
|
if unitsMgr.isValidExpression(valCommandInput.expression, unitType):
|
||||||
|
value = unitsMgr.evaluateExpression(valCommandInput.expression, unitType)
|
||||||
|
return (True, value)
|
||||||
|
else:
|
||||||
|
return (False, 0)
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
# Event handler for the commandCreated event.
|
||||||
|
class GearCommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
eventArgs = adsk.core.CommandCreatedEventArgs.cast(args)
|
||||||
|
|
||||||
|
# Verify that a Fusion design is active.
|
||||||
|
des = adsk.fusion.Design.cast(_app.activeProduct)
|
||||||
|
if not des:
|
||||||
|
_ui.messageBox('A Fusion design must be active when invoking this command.')
|
||||||
|
return()
|
||||||
|
|
||||||
|
defaultUnits = des.unitsManager.defaultLengthUnits
|
||||||
|
|
||||||
|
# Determine whether to use inches or millimeters as the intial default.
|
||||||
|
global _units
|
||||||
|
if defaultUnits == 'in' or defaultUnits == 'ft':
|
||||||
|
_units = 'in'
|
||||||
|
else:
|
||||||
|
_units = 'mm'
|
||||||
|
|
||||||
|
# Define the default values and get the previous values from the attributes.
|
||||||
|
if _units == 'in':
|
||||||
|
standard = 'English'
|
||||||
|
else:
|
||||||
|
standard = 'Metric'
|
||||||
|
standardAttrib = des.attributes.itemByName('SpurGear', 'standard')
|
||||||
|
if standardAttrib:
|
||||||
|
standard = standardAttrib.value
|
||||||
|
|
||||||
|
if standard == 'English':
|
||||||
|
_units = 'in'
|
||||||
|
else:
|
||||||
|
_units = 'mm'
|
||||||
|
|
||||||
|
pressureAngle = '20 deg'
|
||||||
|
pressureAngleAttrib = des.attributes.itemByName('SpurGear', 'pressureAngle')
|
||||||
|
if pressureAngleAttrib:
|
||||||
|
pressureAngle = pressureAngleAttrib.value
|
||||||
|
|
||||||
|
pressureAngleCustom = 20 * (math.pi/180.0)
|
||||||
|
pressureAngleCustomAttrib = des.attributes.itemByName('SpurGear', 'pressureAngleCustom')
|
||||||
|
if pressureAngleCustomAttrib:
|
||||||
|
pressureAngleCustom = float(pressureAngleCustomAttrib.value)
|
||||||
|
|
||||||
|
diaPitch = '2'
|
||||||
|
diaPitchAttrib = des.attributes.itemByName('SpurGear', 'diaPitch')
|
||||||
|
if diaPitchAttrib:
|
||||||
|
diaPitch = diaPitchAttrib.value
|
||||||
|
metricModule = 25.4 / float(diaPitch)
|
||||||
|
|
||||||
|
backlash = '0'
|
||||||
|
backlashAttrib = des.attributes.itemByName('SpurGear', 'backlash')
|
||||||
|
if backlashAttrib:
|
||||||
|
backlash = backlashAttrib.value
|
||||||
|
|
||||||
|
numTeeth = '24'
|
||||||
|
numTeethAttrib = des.attributes.itemByName('SpurGear', 'numTeeth')
|
||||||
|
if numTeethAttrib:
|
||||||
|
numTeeth = numTeethAttrib.value
|
||||||
|
|
||||||
|
rootFilletRad = str(.0625 * 2.54)
|
||||||
|
rootFilletRadAttrib = des.attributes.itemByName('SpurGear', 'rootFilletRad')
|
||||||
|
if rootFilletRadAttrib:
|
||||||
|
rootFilletRad = rootFilletRadAttrib.value
|
||||||
|
|
||||||
|
thickness = str(0.5 * 2.54)
|
||||||
|
thicknessAttrib = des.attributes.itemByName('SpurGear', 'thickness')
|
||||||
|
if thicknessAttrib:
|
||||||
|
thickness = thicknessAttrib.value
|
||||||
|
|
||||||
|
holeDiam = str(0.5 * 2.54)
|
||||||
|
holeDiamAttrib = des.attributes.itemByName('SpurGear', 'holeDiam')
|
||||||
|
if holeDiamAttrib:
|
||||||
|
holeDiam = holeDiamAttrib.value
|
||||||
|
|
||||||
|
cmd = eventArgs.command
|
||||||
|
cmd.isExecutedWhenPreEmpted = False
|
||||||
|
inputs = cmd.commandInputs
|
||||||
|
|
||||||
|
global _standard, _pressureAngle, _pressureAngleCustom, _diaPitch, _pitch, _module, _numTeeth, _rootFilletRad, _thickness, _holeDiam, _pitchDiam, _backlash, _imgInputEnglish, _imgInputMetric, _errMessage
|
||||||
|
|
||||||
|
# Define the command dialog.
|
||||||
|
_imgInputEnglish = inputs.addImageCommandInput('gearImageEnglish', '', 'Resources/GearEnglish.png')
|
||||||
|
_imgInputEnglish.isFullWidth = True
|
||||||
|
|
||||||
|
_imgInputMetric = inputs.addImageCommandInput('gearImageMetric', '', 'Resources/GearMetric.png')
|
||||||
|
_imgInputMetric.isFullWidth = True
|
||||||
|
|
||||||
|
_standard = inputs.addDropDownCommandInput('standard', 'Standard', adsk.core.DropDownStyles.TextListDropDownStyle)
|
||||||
|
if standard == "English":
|
||||||
|
_standard.listItems.add('English', True)
|
||||||
|
_standard.listItems.add('Metric', False)
|
||||||
|
_imgInputMetric.isVisible = False
|
||||||
|
else:
|
||||||
|
_standard.listItems.add('English', False)
|
||||||
|
_standard.listItems.add('Metric', True)
|
||||||
|
_imgInputEnglish.isVisible = False
|
||||||
|
|
||||||
|
_pressureAngle = inputs.addDropDownCommandInput('pressureAngle', 'Pressure Angle', adsk.core.DropDownStyles.TextListDropDownStyle)
|
||||||
|
if pressureAngle == '14.5 deg':
|
||||||
|
_pressureAngle.listItems.add('14.5 deg', True)
|
||||||
|
else:
|
||||||
|
_pressureAngle.listItems.add('14.5 deg', False)
|
||||||
|
|
||||||
|
if pressureAngle == '20 deg':
|
||||||
|
_pressureAngle.listItems.add('20 deg', True)
|
||||||
|
else:
|
||||||
|
_pressureAngle.listItems.add('20 deg', False)
|
||||||
|
|
||||||
|
if pressureAngle == '25 deg':
|
||||||
|
_pressureAngle.listItems.add('25 deg', True)
|
||||||
|
else:
|
||||||
|
_pressureAngle.listItems.add('25 deg', False)
|
||||||
|
|
||||||
|
if pressureAngle == 'Custom':
|
||||||
|
_pressureAngle.listItems.add('Custom', True)
|
||||||
|
else:
|
||||||
|
_pressureAngle.listItems.add('Custom', False)
|
||||||
|
|
||||||
|
_pressureAngleCustom = inputs.addValueInput('pressureAngleCustom', 'Custom Angle', 'deg', adsk.core.ValueInput.createByReal(pressureAngleCustom))
|
||||||
|
if pressureAngle != 'Custom':
|
||||||
|
_pressureAngleCustom.isVisible = False
|
||||||
|
|
||||||
|
_diaPitch = inputs.addValueInput('diaPitch', 'Diametral Pitch', '', adsk.core.ValueInput.createByString(diaPitch))
|
||||||
|
|
||||||
|
_module = inputs.addValueInput('module', 'Module', '', adsk.core.ValueInput.createByReal(metricModule))
|
||||||
|
|
||||||
|
if standard == 'English':
|
||||||
|
_module.isVisible = False
|
||||||
|
elif standard == 'Metric':
|
||||||
|
_diaPitch.isVisible = False
|
||||||
|
|
||||||
|
_numTeeth = inputs.addStringValueInput('numTeeth', 'Number of Teeth', numTeeth)
|
||||||
|
|
||||||
|
_backlash = inputs.addValueInput('backlash', 'Backlash', _units, adsk.core.ValueInput.createByReal(float(backlash)))
|
||||||
|
|
||||||
|
_rootFilletRad = inputs.addValueInput('rootFilletRad', 'Root Fillet Radius', _units, adsk.core.ValueInput.createByReal(float(rootFilletRad)))
|
||||||
|
|
||||||
|
_thickness = inputs.addValueInput('thickness', 'Gear Thickness', _units, adsk.core.ValueInput.createByReal(float(thickness)))
|
||||||
|
|
||||||
|
_holeDiam = inputs.addValueInput('holeDiam', 'Hole Diameter', _units, adsk.core.ValueInput.createByReal(float(holeDiam)))
|
||||||
|
|
||||||
|
_pitchDiam = inputs.addTextBoxCommandInput('pitchDiam', 'Pitch Diameter', '', 1, True)
|
||||||
|
|
||||||
|
_errMessage = inputs.addTextBoxCommandInput('errMessage', '', '', 2, True)
|
||||||
|
_errMessage.isFullWidth = True
|
||||||
|
|
||||||
|
# Connect to the command related events.
|
||||||
|
onExecute = GearCommandExecuteHandler()
|
||||||
|
cmd.execute.add(onExecute)
|
||||||
|
_handlers.append(onExecute)
|
||||||
|
|
||||||
|
onInputChanged = GearCommandInputChangedHandler()
|
||||||
|
cmd.inputChanged.add(onInputChanged)
|
||||||
|
_handlers.append(onInputChanged)
|
||||||
|
|
||||||
|
onValidateInputs = GearCommandValidateInputsHandler()
|
||||||
|
cmd.validateInputs.add(onValidateInputs)
|
||||||
|
_handlers.append(onValidateInputs)
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
# Event handler for the execute event.
|
||||||
|
class GearCommandExecuteHandler(adsk.core.CommandEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
eventArgs = adsk.core.CommandEventArgs.cast(args)
|
||||||
|
|
||||||
|
if _standard.selectedItem.name == 'English':
|
||||||
|
diaPitch = _diaPitch.value
|
||||||
|
elif _standard.selectedItem.name == 'Metric':
|
||||||
|
diaPitch = 25.4 / _module.value
|
||||||
|
|
||||||
|
# Save the current values as attributes.
|
||||||
|
des = adsk.fusion.Design.cast(_app.activeProduct)
|
||||||
|
attribs = des.attributes
|
||||||
|
attribs.add('SpurGear', 'standard', _standard.selectedItem.name)
|
||||||
|
attribs.add('SpurGear', 'pressureAngle', _pressureAngle.selectedItem.name)
|
||||||
|
attribs.add('SpurGear', 'pressureAngleCustom', str(_pressureAngleCustom.value))
|
||||||
|
attribs.add('SpurGear', 'diaPitch', str(diaPitch))
|
||||||
|
attribs.add('SpurGear', 'numTeeth', str(_numTeeth.value))
|
||||||
|
attribs.add('SpurGear', 'rootFilletRad', str(_rootFilletRad.value))
|
||||||
|
attribs.add('SpurGear', 'thickness', str(_thickness.value))
|
||||||
|
attribs.add('SpurGear', 'holeDiam', str(_holeDiam.value))
|
||||||
|
attribs.add('SpurGear', 'backlash', str(_backlash.value))
|
||||||
|
|
||||||
|
# Get the current values.
|
||||||
|
if _pressureAngle.selectedItem.name == 'Custom':
|
||||||
|
pressureAngle = _pressureAngleCustom.value
|
||||||
|
else:
|
||||||
|
if _pressureAngle.selectedItem.name == '14.5 deg':
|
||||||
|
pressureAngle = 14.5 * (math.pi/180)
|
||||||
|
elif _pressureAngle.selectedItem.name == '20 deg':
|
||||||
|
pressureAngle = 20.0 * (math.pi/180)
|
||||||
|
elif _pressureAngle.selectedItem.name == '25 deg':
|
||||||
|
pressureAngle = 25.0 * (math.pi/180)
|
||||||
|
|
||||||
|
numTeeth = int(_numTeeth.value)
|
||||||
|
rootFilletRad = _rootFilletRad.value
|
||||||
|
thickness = _thickness.value
|
||||||
|
holeDiam = _holeDiam.value
|
||||||
|
backlash = _backlash.value
|
||||||
|
|
||||||
|
# Create the gear.
|
||||||
|
gearComp = drawGear(des, diaPitch, numTeeth, thickness, rootFilletRad, pressureAngle, backlash, holeDiam)
|
||||||
|
|
||||||
|
if gearComp:
|
||||||
|
if _standard.selectedItem.name == 'English':
|
||||||
|
desc = 'Spur Gear; Diametrial Pitch: ' + str(diaPitch) + '; '
|
||||||
|
elif _standard.selectedItem.name == 'Metric':
|
||||||
|
desc = 'Spur Gear; Module: ' + str(25.4 / diaPitch) + '; '
|
||||||
|
|
||||||
|
desc += 'Num Teeth: ' + str(numTeeth) + '; '
|
||||||
|
desc += 'Pressure Angle: ' + str(pressureAngle * (180/math.pi)) + '; '
|
||||||
|
|
||||||
|
desc += 'Backlash: ' + des.unitsManager.formatInternalValue(backlash, _units, True)
|
||||||
|
gearComp.description = desc
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Event handler for the inputChanged event.
|
||||||
|
class GearCommandInputChangedHandler(adsk.core.InputChangedEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
eventArgs = adsk.core.InputChangedEventArgs.cast(args)
|
||||||
|
changedInput = eventArgs.input
|
||||||
|
|
||||||
|
global _units
|
||||||
|
if changedInput.id == 'standard':
|
||||||
|
if _standard.selectedItem.name == 'English':
|
||||||
|
_imgInputMetric.isVisible = False
|
||||||
|
_imgInputEnglish.isVisible = True
|
||||||
|
|
||||||
|
_diaPitch.isVisible = True
|
||||||
|
_module.isVisible = False
|
||||||
|
|
||||||
|
_diaPitch.value = 25.4 / _module.value
|
||||||
|
|
||||||
|
_units = 'in'
|
||||||
|
elif _standard.selectedItem.name == 'Metric':
|
||||||
|
_imgInputMetric.isVisible = True
|
||||||
|
_imgInputEnglish.isVisible = False
|
||||||
|
|
||||||
|
_diaPitch.isVisible = False
|
||||||
|
_module.isVisible = True
|
||||||
|
|
||||||
|
_module.value = 25.4 / _diaPitch.value
|
||||||
|
|
||||||
|
_units = 'mm'
|
||||||
|
|
||||||
|
# Set each one to it's current value because otherwised if the user
|
||||||
|
# has edited it, the value won't update in the dialog because
|
||||||
|
# apparently it remembers the units when the value was edited.
|
||||||
|
# Setting the value using the API resets this.
|
||||||
|
_backlash.value = _backlash.value
|
||||||
|
_backlash.unitType = _units
|
||||||
|
_rootFilletRad.value = _rootFilletRad.value
|
||||||
|
_rootFilletRad.unitType = _units
|
||||||
|
_thickness.value = _thickness.value
|
||||||
|
_thickness.unitType = _units
|
||||||
|
_holeDiam.value = _holeDiam.value
|
||||||
|
_holeDiam.unitType = _units
|
||||||
|
|
||||||
|
# Update the pitch diameter value.
|
||||||
|
diaPitch = None
|
||||||
|
if _standard.selectedItem.name == 'English':
|
||||||
|
result = getCommandInputValue(_diaPitch, '')
|
||||||
|
if result[0]:
|
||||||
|
diaPitch = result[1]
|
||||||
|
elif _standard.selectedItem.name == 'Metric':
|
||||||
|
result = getCommandInputValue(_module, '')
|
||||||
|
if result[0]:
|
||||||
|
diaPitch = 25.4 / result[1]
|
||||||
|
if not diaPitch == None:
|
||||||
|
if _numTeeth.value.isdigit():
|
||||||
|
numTeeth = int(_numTeeth.value)
|
||||||
|
pitchDia = numTeeth/diaPitch
|
||||||
|
|
||||||
|
# The pitch dia has been calculated in inches, but this expects cm as the input units.
|
||||||
|
des = adsk.fusion.Design.cast(_app.activeProduct)
|
||||||
|
pitchDiaText = des.unitsManager.formatInternalValue(pitchDia * 2.54, _units, True)
|
||||||
|
_pitchDiam.text = pitchDiaText
|
||||||
|
else:
|
||||||
|
_pitchDiam.text = ''
|
||||||
|
else:
|
||||||
|
_pitchDiam.text = ''
|
||||||
|
|
||||||
|
if changedInput.id == 'pressureAngle':
|
||||||
|
if _pressureAngle.selectedItem.name == 'Custom':
|
||||||
|
_pressureAngleCustom.isVisible = True
|
||||||
|
else:
|
||||||
|
_pressureAngleCustom.isVisible = False
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
# Event handler for the validateInputs event.
|
||||||
|
class GearCommandValidateInputsHandler(adsk.core.ValidateInputsEventHandler):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
def notify(self, args):
|
||||||
|
try:
|
||||||
|
eventArgs = adsk.core.ValidateInputsEventArgs.cast(args)
|
||||||
|
|
||||||
|
_errMessage.text = ''
|
||||||
|
|
||||||
|
# Verify that at lesat 4 teath are specified.
|
||||||
|
if not _numTeeth.value.isdigit():
|
||||||
|
_errMessage.text = 'The number of teeth must be a whole number.'
|
||||||
|
eventArgs.areInputsValid = False
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
numTeeth = int(_numTeeth.value)
|
||||||
|
|
||||||
|
if numTeeth < 4:
|
||||||
|
_errMessage.text = 'The number of teeth must be 4 or more.'
|
||||||
|
eventArgs.areInputsValid = False
|
||||||
|
return
|
||||||
|
|
||||||
|
# Calculate some of the gear sizes to use in validation.
|
||||||
|
if _standard.selectedItem.name == 'English':
|
||||||
|
result = getCommandInputValue(_diaPitch, '')
|
||||||
|
if result[0] == False:
|
||||||
|
eventArgs.areInputsValid = False
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
diaPitch = result[1]
|
||||||
|
elif _standard.selectedItem.name == 'Metric':
|
||||||
|
result = getCommandInputValue(_module, '')
|
||||||
|
if result[0] == False:
|
||||||
|
eventArgs.areInputsValid = False
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
diaPitch = 25.4 / result[1]
|
||||||
|
|
||||||
|
diametralPitch = diaPitch / 2.54
|
||||||
|
pitchDia = numTeeth / diametralPitch
|
||||||
|
|
||||||
|
if (diametralPitch < (20 *(math.pi/180))-0.000001):
|
||||||
|
dedendum = 1.157 / diametralPitch
|
||||||
|
else:
|
||||||
|
circularPitch = math.pi / diametralPitch
|
||||||
|
if circularPitch >= 20:
|
||||||
|
dedendum = 1.25 / diametralPitch
|
||||||
|
else:
|
||||||
|
dedendum = (1.2 / diametralPitch) + (.002 * 2.54)
|
||||||
|
|
||||||
|
rootDia = pitchDia - (2 * dedendum)
|
||||||
|
|
||||||
|
if _pressureAngle.selectedItem.name == 'Custom':
|
||||||
|
pressureAngle = _pressureAngleCustom.value
|
||||||
|
else:
|
||||||
|
if _pressureAngle.selectedItem.name == '14.5 deg':
|
||||||
|
pressureAngle = 14.5 * (math.pi/180)
|
||||||
|
elif _pressureAngle.selectedItem.name == '20 deg':
|
||||||
|
pressureAngle = 20.0 * (math.pi/180)
|
||||||
|
elif _pressureAngle.selectedItem.name == '25 deg':
|
||||||
|
pressureAngle = 25.0 * (math.pi/180)
|
||||||
|
baseCircleDia = pitchDia * math.cos(pressureAngle)
|
||||||
|
baseCircleCircumference = 2 * math.pi * (baseCircleDia / 2)
|
||||||
|
|
||||||
|
des = adsk.fusion.Design.cast(_app.activeProduct)
|
||||||
|
|
||||||
|
result = getCommandInputValue(_holeDiam, _units)
|
||||||
|
if result[0] == False:
|
||||||
|
eventArgs.areInputsValid = False
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
holeDiam = result[1]
|
||||||
|
|
||||||
|
if holeDiam >= (rootDia - 0.01):
|
||||||
|
_errMessage.text = 'The center hole diameter is too large. It must be less than ' + des.unitsManager.formatInternalValue(rootDia - 0.01, _units, True)
|
||||||
|
eventArgs.areInputsValid = False
|
||||||
|
return
|
||||||
|
|
||||||
|
toothThickness = baseCircleCircumference / (numTeeth * 2)
|
||||||
|
if _rootFilletRad.value > toothThickness * .4:
|
||||||
|
_errMessage.text = 'The root fillet radius is too large. It must be less than ' + des.unitsManager.formatInternalValue(toothThickness * .4, _units, True)
|
||||||
|
eventArgs.areInputsValid = False
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
# Calculate points along an involute curve.
|
||||||
|
def involutePoint(baseCircleRadius, distFromCenterToInvolutePoint):
|
||||||
|
try:
|
||||||
|
# Calculate the other side of the right-angle triangle defined by the base circle and the current distance radius.
|
||||||
|
# This is also the length of the involute chord as it comes off of the base circle.
|
||||||
|
triangleSide = math.sqrt(math.pow(distFromCenterToInvolutePoint,2) - math.pow(baseCircleRadius,2))
|
||||||
|
|
||||||
|
# Calculate the angle of the involute.
|
||||||
|
alpha = triangleSide / baseCircleRadius
|
||||||
|
|
||||||
|
# Calculate the angle where the current involute point is.
|
||||||
|
theta = alpha - math.acos(baseCircleRadius / distFromCenterToInvolutePoint)
|
||||||
|
|
||||||
|
# Calculate the coordinates of the involute point.
|
||||||
|
x = distFromCenterToInvolutePoint * math.cos(theta)
|
||||||
|
y = distFromCenterToInvolutePoint * math.sin(theta)
|
||||||
|
|
||||||
|
# Create a point to return.
|
||||||
|
return adsk.core.Point3D.create(x, y, 0)
|
||||||
|
except:
|
||||||
|
if _ui:
|
||||||
|
_ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
|
||||||
|
|
||||||
|
|
||||||
|
# Builds a spur gear.
|
||||||
|
def drawGear(design, diametralPitch, numTeeth, thickness, rootFilletRad, pressureAngle, backlash, holeDiam):
|
||||||
|
try:
|
||||||
|
# The diametral pitch is specified in inches but everthing
|
||||||
|
# here expects all distances to be in centimeters, so convert
|
||||||
|
# for the gear creation.
|
||||||
|
diametralPitch = diametralPitch / 2.54
|
||||||
|
|
||||||
|
# Compute the various values for a gear.
|
||||||
|
pitchDia = numTeeth / diametralPitch
|
||||||
|
|
||||||
|
#addendum = 1.0 / diametralPitch
|
||||||
|
if (diametralPitch < (20 *(math.pi/180))-0.000001):
|
||||||
|
dedendum = 1.157 / diametralPitch
|
||||||
|
else:
|
||||||
|
circularPitch = math.pi / diametralPitch
|
||||||
|
if circularPitch >= 20:
|
||||||
|
dedendum = 1.25 / diametralPitch
|
||||||
|
else:
|
||||||
|
dedendum = (1.2 / diametralPitch) + (.002 * 2.54)
|
||||||
|
|
||||||
|
rootDia = pitchDia - (2 * dedendum)
|
||||||
|
|
||||||
|
baseCircleDia = pitchDia * math.cos(pressureAngle)
|
||||||
|
outsideDia = (numTeeth + 2) / diametralPitch
|
||||||
|
|
||||||
|
# Create a new component by creating an occurrence.
|
||||||
|
occs = design.rootComponent.occurrences
|
||||||
|
mat = adsk.core.Matrix3D.create()
|
||||||
|
newOcc = occs.addNewComponent(mat)
|
||||||
|
newComp = adsk.fusion.Component.cast(newOcc.component)
|
||||||
|
|
||||||
|
# Create a new sketch.
|
||||||
|
sketches = newComp.sketches
|
||||||
|
xyPlane = newComp.xYConstructionPlane
|
||||||
|
baseSketch = sketches.add(xyPlane)
|
||||||
|
|
||||||
|
# Draw a circle for the base.
|
||||||
|
baseSketch.sketchCurves.sketchCircles.addByCenterRadius(adsk.core.Point3D.create(0,0,0), rootDia/2.0)
|
||||||
|
|
||||||
|
# Draw a circle for the center hole, if the value is greater than 0.
|
||||||
|
prof = adsk.fusion.Profile.cast(None)
|
||||||
|
if holeDiam - (_app.pointTolerance * 2) > 0:
|
||||||
|
baseSketch.sketchCurves.sketchCircles.addByCenterRadius(adsk.core.Point3D.create(0,0,0), holeDiam/2.0)
|
||||||
|
|
||||||
|
# Find the profile that uses both circles.
|
||||||
|
for prof in baseSketch.profiles:
|
||||||
|
if prof.profileLoops.count == 2:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# Use the single profile.
|
||||||
|
prof = baseSketch.profiles.item(0)
|
||||||
|
|
||||||
|
#### Extrude the circle to create the base of the gear.
|
||||||
|
|
||||||
|
# Create an extrusion input to be able to define the input needed for an extrusion
|
||||||
|
# while specifying the profile and that a new component is to be created
|
||||||
|
extrudes = newComp.features.extrudeFeatures
|
||||||
|
extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.NewBodyFeatureOperation)
|
||||||
|
|
||||||
|
# Define that the extent is a distance extent of 5 cm.
|
||||||
|
distance = adsk.core.ValueInput.createByReal(thickness)
|
||||||
|
extInput.setDistanceExtent(False, distance)
|
||||||
|
|
||||||
|
# Create the extrusion.
|
||||||
|
baseExtrude = extrudes.add(extInput)
|
||||||
|
|
||||||
|
# Create a second sketch for the tooth.
|
||||||
|
toothSketch = sketches.add(xyPlane)
|
||||||
|
|
||||||
|
# Calculate points along the involute curve.
|
||||||
|
involutePointCount = 15;
|
||||||
|
involuteIntersectionRadius = baseCircleDia / 2.0
|
||||||
|
involutePoints = []
|
||||||
|
involuteSize = (outsideDia - baseCircleDia) / 2.0
|
||||||
|
for i in range(0, involutePointCount):
|
||||||
|
involuteIntersectionRadius = (baseCircleDia / 2.0) + ((involuteSize / (involutePointCount - 1)) * i)
|
||||||
|
newPoint = involutePoint(baseCircleDia / 2.0, involuteIntersectionRadius)
|
||||||
|
involutePoints.append(newPoint)
|
||||||
|
|
||||||
|
# Get the point along the tooth that's at the pictch diameter and then
|
||||||
|
# calculate the angle to that point.
|
||||||
|
pitchInvolutePoint = involutePoint(baseCircleDia / 2.0, pitchDia / 2.0)
|
||||||
|
pitchPointAngle = math.atan(pitchInvolutePoint.y / pitchInvolutePoint.x)
|
||||||
|
|
||||||
|
# Determine the angle defined by the tooth thickness as measured at
|
||||||
|
# the pitch diameter circle.
|
||||||
|
toothThicknessAngle = (2 * math.pi) / (2 * numTeeth)
|
||||||
|
|
||||||
|
# Determine the angle needed for the specified backlash.
|
||||||
|
backlashAngle = (backlash / (pitchDia / 2.0)) * .25
|
||||||
|
|
||||||
|
# Determine the angle to rotate the curve.
|
||||||
|
rotateAngle = -((toothThicknessAngle/2) + pitchPointAngle - backlashAngle)
|
||||||
|
|
||||||
|
# Rotate the involute so the middle of the tooth lies on the x axis.
|
||||||
|
cosAngle = math.cos(rotateAngle)
|
||||||
|
sinAngle = math.sin(rotateAngle)
|
||||||
|
for i in range(0, involutePointCount):
|
||||||
|
newX = involutePoints[i].x * cosAngle - involutePoints[i].y * sinAngle
|
||||||
|
newY = involutePoints[i].x * sinAngle + involutePoints[i].y * cosAngle
|
||||||
|
involutePoints[i] = adsk.core.Point3D.create(newX, newY, 0)
|
||||||
|
|
||||||
|
# Create a new set of points with a negated y. This effectively mirrors the original
|
||||||
|
# points about the X axis.
|
||||||
|
involute2Points = []
|
||||||
|
for i in range(0, involutePointCount):
|
||||||
|
involute2Points.append(adsk.core.Point3D.create(involutePoints[i].x, -involutePoints[i].y, 0))
|
||||||
|
|
||||||
|
curve1Dist = []
|
||||||
|
curve1Angle = []
|
||||||
|
for i in range(0, involutePointCount):
|
||||||
|
curve1Dist.append(math.sqrt(involutePoints[i].x * involutePoints[i].x + involutePoints[i].y * involutePoints[i].y))
|
||||||
|
curve1Angle.append(math.atan(involutePoints[i].y / involutePoints[i].x))
|
||||||
|
|
||||||
|
curve2Dist = []
|
||||||
|
curve2Angle = []
|
||||||
|
for i in range(0, involutePointCount):
|
||||||
|
curve2Dist.append(math.sqrt(involute2Points[i].x * involute2Points[i].x + involute2Points[i].y * involute2Points[i].y))
|
||||||
|
curve2Angle.append(math.atan(involute2Points[i].y / involute2Points[i].x))
|
||||||
|
|
||||||
|
toothSketch.isComputeDeferred = True
|
||||||
|
|
||||||
|
# Create and load an object collection with the points.
|
||||||
|
pointSet = adsk.core.ObjectCollection.create()
|
||||||
|
for i in range(0, involutePointCount):
|
||||||
|
pointSet.add(involutePoints[i])
|
||||||
|
|
||||||
|
# Create the first spline.
|
||||||
|
spline1 = toothSketch.sketchCurves.sketchFittedSplines.add(pointSet)
|
||||||
|
|
||||||
|
# Add the involute points for the second spline to an ObjectCollection.
|
||||||
|
pointSet = adsk.core.ObjectCollection.create()
|
||||||
|
for i in range(0, involutePointCount):
|
||||||
|
pointSet.add(involute2Points[i])
|
||||||
|
|
||||||
|
# Create the second spline.
|
||||||
|
spline2 = toothSketch.sketchCurves.sketchFittedSplines.add(pointSet)
|
||||||
|
|
||||||
|
# Draw the arc for the top of the tooth.
|
||||||
|
midPoint = adsk.core.Point3D.create((outsideDia / 2), 0, 0)
|
||||||
|
toothSketch.sketchCurves.sketchArcs.addByThreePoints(spline1.endSketchPoint, midPoint, spline2.endSketchPoint)
|
||||||
|
|
||||||
|
# Check to see if involute goes down to the root or not. If not, then
|
||||||
|
# create lines to connect the involute to the root.
|
||||||
|
if( baseCircleDia < rootDia ):
|
||||||
|
toothSketch.sketchCurves.sketchLines.addByTwoPoints(spline2.startSketchPoint, spline1.startSketchPoint)
|
||||||
|
else:
|
||||||
|
rootPoint1 = adsk.core.Point3D.create((rootDia / 2 - 0.001) * math.cos(curve1Angle[0] ), (rootDia / 2) * math.sin(curve1Angle[0]), 0)
|
||||||
|
line1 = toothSketch.sketchCurves.sketchLines.addByTwoPoints(rootPoint1, spline1.startSketchPoint)
|
||||||
|
|
||||||
|
rootPoint2 = adsk.core.Point3D.create((rootDia / 2 - 0.001) * math.cos(curve2Angle[0]), (rootDia / 2) * math.sin(curve2Angle[0]), 0)
|
||||||
|
line2 = toothSketch.sketchCurves.sketchLines.addByTwoPoints(rootPoint2, spline2.startSketchPoint)
|
||||||
|
|
||||||
|
baseLine = toothSketch.sketchCurves.sketchLines.addByTwoPoints(line1.startSketchPoint, line2.startSketchPoint)
|
||||||
|
|
||||||
|
# Make the lines tangent to the spline so the root fillet will behave correctly.
|
||||||
|
line1.isFixed = True
|
||||||
|
line2.isFixed = True
|
||||||
|
toothSketch.geometricConstraints.addTangent(spline1, line1)
|
||||||
|
toothSketch.geometricConstraints.addTangent(spline2, line2)
|
||||||
|
|
||||||
|
toothSketch.isComputeDeferred = False
|
||||||
|
|
||||||
|
### Extrude the tooth.
|
||||||
|
|
||||||
|
# Get the profile defined by the tooth.
|
||||||
|
prof = toothSketch.profiles.item(0)
|
||||||
|
|
||||||
|
# Create an extrusion input to be able to define the input needed for an extrusion
|
||||||
|
# while specifying the profile and that a new component is to be created
|
||||||
|
extInput = extrudes.createInput(prof, adsk.fusion.FeatureOperations.JoinFeatureOperation)
|
||||||
|
|
||||||
|
# Define that the extent is a distance extent of 5 cm.
|
||||||
|
distance = adsk.core.ValueInput.createByReal(thickness)
|
||||||
|
extInput.setDistanceExtent(False, distance)
|
||||||
|
|
||||||
|
# Create the extrusion.
|
||||||
|
toothExtrude = extrudes.add(extInput)
|
||||||
|
|
||||||
|
baseFillet = None
|
||||||
|
if rootFilletRad > 0:
|
||||||
|
### Find the edges between the base cylinder and the tooth.
|
||||||
|
|
||||||
|
# Get the outer cylindrical face from the base extrusion by checking the number
|
||||||
|
# of edges and if it's 2 get the other one.
|
||||||
|
cylFace = baseExtrude.sideFaces.item(0)
|
||||||
|
if cylFace.edges.count == 2:
|
||||||
|
cylFace = baseExtrude.sideFaces.item(1)
|
||||||
|
|
||||||
|
# Get the two linear edges, which are the connection between the cylinder and tooth.
|
||||||
|
edges = adsk.core.ObjectCollection.create()
|
||||||
|
for edge in cylFace.edges:
|
||||||
|
if isinstance(edge.geometry, adsk.core.Line3D):
|
||||||
|
edges.add(edge)
|
||||||
|
|
||||||
|
# Create a fillet input to be able to define the input needed for a fillet.
|
||||||
|
fillets = newComp.features.filletFeatures;
|
||||||
|
filletInput = fillets.createInput()
|
||||||
|
|
||||||
|
# Define that the extent is a distance extent of 5 cm.
|
||||||
|
radius = adsk.core.ValueInput.createByReal(rootFilletRad)
|
||||||
|
filletInput.addConstantRadiusEdgeSet(edges, radius, False)
|
||||||
|
|
||||||
|
# Create the extrusion.
|
||||||
|
baseFillet = fillets.add(filletInput)
|
||||||
|
|
||||||
|
# Create a pattern of the tooth extrude and the base fillet.
|
||||||
|
circularPatterns = newComp.features.circularPatternFeatures
|
||||||
|
entities = adsk.core.ObjectCollection.create()
|
||||||
|
entities.add(toothExtrude)
|
||||||
|
if baseFillet:
|
||||||
|
entities.add(baseFillet)
|
||||||
|
cylFace = baseExtrude.sideFaces.item(0)
|
||||||
|
patternInput = circularPatterns.createInput(entities, cylFace)
|
||||||
|
numTeethInput = adsk.core.ValueInput.createByString(str(numTeeth))
|
||||||
|
patternInput.quantity = numTeethInput
|
||||||
|
patternInput.patternComputeOption = adsk.fusion.PatternComputeOptions.IdenticalPatternCompute
|
||||||
|
pattern = circularPatterns.add(patternInput)
|
||||||
|
|
||||||
|
# Create an extra sketch that contains a circle of the diametral pitch.
|
||||||
|
diametralPitchSketch = sketches.add(xyPlane)
|
||||||
|
diametralPitchCircle = diametralPitchSketch.sketchCurves.sketchCircles.addByCenterRadius(adsk.core.Point3D.create(0,0,0), pitchDia/2.0)
|
||||||
|
diametralPitchCircle.isConstruction = True
|
||||||
|
diametralPitchCircle.isFixed = True
|
||||||
|
|
||||||
|
# Group everything used to create the gear in the timeline.
|
||||||
|
timelineGroups = design.timeline.timelineGroups
|
||||||
|
newOccIndex = newOcc.timelineObject.index
|
||||||
|
pitchSketchIndex = diametralPitchSketch.timelineObject.index
|
||||||
|
# ui.messageBox("Indices: " + str(newOccIndex) + ", " + str(pitchSketchIndex))
|
||||||
|
timelineGroup = timelineGroups.add(newOccIndex, pitchSketchIndex)
|
||||||
|
timelineGroup.name = 'Spur Gear'
|
||||||
|
|
||||||
|
# Add an attribute to the component with all of the input values. This might
|
||||||
|
# be used in the future to be able to edit the gear.
|
||||||
|
gearValues = {}
|
||||||
|
gearValues['diametralPitch'] = str(diametralPitch * 2.54)
|
||||||
|
gearValues['numTeeth'] = str(numTeeth)
|
||||||
|
gearValues['thickness'] = str(thickness)
|
||||||
|
gearValues['rootFilletRad'] = str(rootFilletRad)
|
||||||
|
gearValues['pressureAngle'] = str(pressureAngle)
|
||||||
|
gearValues['holeDiam'] = str(holeDiam)
|
||||||
|
gearValues['backlash'] = str(backlash)
|
||||||
|
attrib = newComp.attributes.add('SpurGear', 'Values',str(gearValues))
|
||||||
|
|
||||||
|
newComp.name = 'Spur Gear (' + str(numTeeth) + ' teeth)'
|
||||||
|
return newComp
|
||||||
|
except Exception as error:
|
||||||
|
_ui.messageBox("drawGear Failed : " + str(error))
|
||||||
|
return None
|
||||||
|
|
||||||