for the boyz

This commit is contained in:
lovebird 2022-10-15 19:16:08 +02:00
commit 9fe266ca3a
8188 changed files with 1567766 additions and 0 deletions

11
.gh-sync.json Normal file
View File

@ -0,0 +1,11 @@
{
"debug": false,
"matching": [
"*.json",
"*.md",
"*.yaml",
"*.csv",
"*.xls",
"*.html"
]
}

47
.gitignore vendored Normal file
View 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
View File

@ -0,0 +1,5 @@
tests
src
ref
web
scripts

24
LICENSE Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

6
cad/index.js Normal file
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

7
clear_history.sh Normal file
View 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

View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1,5 @@
{
"variables":{
"OSR_CAD_WEB":"https://osr-plastic.org/cad"
}
}

8
constants.js Normal file
View 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
View 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
View 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
View File

@ -0,0 +1,33 @@
# Integration
## [Alt-Tap Salamand](https://www.altap.cz/) - Custom Menus
To use OSR-CAD in custom menus, as follows
![](./assets/integration-as-custom-menu.PNG)
1. install osr-cad via ```npm i -g @plastichub/osr-cad```
2. Register a new custom menu (press F9 on any file)
![](./assets/integration-as-custom-menu-register.PNG)
**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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

20
format.js Normal file
View 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
View File

@ -0,0 +1 @@
{"version":3,"file":"format.js","sourceRoot":"","sources":["src/format.ts"],"names":[],"mappings":";;AAGA;;;;;;;;;;;;;;;;GAgBG"}

22
formatter.js Normal file
View 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
View 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"}

View 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
View File

View 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"
}
]
}

View File

@ -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"
}

View 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()))

View File

@ -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: {}"

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
This is help file of this addin.
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -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 "附加模块启动成功: {}"

View 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"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View 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
}

View 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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More