├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── facet_product.cxx ├── stp2webgl.cxx ├── stp2webgl.h ├── stp2webgl.vcxproj ├── stp2webgl.vcxproj.filters ├── win32.mak ├── write_stl.cxx ├── write_stlbin.cxx └── write_webxml.cxx /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for taking the time to contribute and we look forward to 4 | your pull requests! 5 | 6 | Your contribution must be compatible with the project license (Apache 7 | 2.0) and you must certify that you have the right to pass it on under 8 | that license as set forth in the Developer Certificate of Origin (DCO) 9 | shown below. 10 | 11 | ```text 12 | Developer Certificate of Origin 13 | Version 1.1 14 | 15 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 16 | 660 York Street, Suite 102, 17 | San Francisco, CA 94110 USA 18 | 19 | Everyone is permitted to copy and distribute verbatim copies of this 20 | license document, but changing it is not allowed. 21 | 22 | 23 | Developer's Certificate of Origin 1.1 24 | 25 | By making a contribution to this project, I certify that: 26 | 27 | (a) The contribution was created in whole or in part by me and I 28 | have the right to submit it under the open source license 29 | indicated in the file; or 30 | 31 | (b) The contribution is based upon previous work that, to the best 32 | of my knowledge, is covered under an appropriate open source 33 | license and I have the right under that license to submit that 34 | work with modifications, whether created in whole or in part 35 | by me, under the same open source license (unless I am 36 | permitted to submit under a different license), as indicated 37 | in the file; or 38 | 39 | (c) The contribution was provided directly to me by some other 40 | person who certified (a), (b) or (c) and I have not modified 41 | it. 42 | 43 | (d) I understand and agree that this project and the contribution 44 | are public and that a record of the contribution (including all 45 | personal information I submit with it, including my sign-off) is 46 | maintained indefinitely and may be redistributed consistent with 47 | this project or the open source license(s) involved. 48 | ``` 49 | 50 | To indicate that you certify the above, add a line to your description 51 | of the contribution saying "Signed-off-by:" followed by your real name 52 | and email address. A sample line is shown below: 53 | 54 | ``` 55 | Signed-off-by: Random J Developer 56 | ``` 57 | 58 | You can automatically add a Signed-off-by line at the end of your 59 | commit log message by calling `git commit -s` or `git commit 60 | --signoff`. 61 | 62 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stp2webgl 2 | ======= 3 | 4 | Facet STEP for Lightweight Viewing 5 | -- 6 | 7 | This command line tool converts STEP CAD data into triangular meshes, 8 | and then writes the result into lightweight files for use in WebGL and 9 | other visualization applications. 10 | 11 | The STEP reading and faceting is handled by ST-Developer libraries. 12 | This code traverses the resulting mesh data and writes STL or a simple 13 | webxml format. If you have a mesh format that you prefer, consider 14 | adding a writer for it and including it as a command line option. 15 | 16 | The webxml format description and a javascript client for displaying 17 | it as WebGL can be found at: 18 | 19 | - http://www.steptools.com/support/stdev_docs/stixmesh/XMLFormat.html 20 | - http://www.steptools.com/demos/ 21 | 22 | 23 | 24 | ## Building 25 | 26 | This package contains a Visual Studio 2013 project file for building. 27 | When using with ST-Developer Personal Edition, set the platform to 28 | either "Release DLL" or "Debug DLL". There is also an NMAKE makefile 29 | called win32.mak which can be used for command line builds. 30 | 31 | The package uses the ST-Developer libraries to read/write STEP files 32 | and mesh the CAD geometry. A downloadable version that is free for 33 | personal use can be found at: 34 | 35 | ST-Developer Personal Edition 36 | - Download - http://www.steptools.com/products/stdev/personal.html 37 | - API Docs - http://www.steptools.com/support/stdev_docs/ 38 | 39 | 40 | ## Extending 41 | 42 | Is there a different back end that you would need? Create your own 43 | `write_foo.cxx` output driver by using one of the existing ones as a 44 | template. See [CONTRIBUTING.md](CONTRIBUTING.md) if you would like to 45 | send a pull request with your changes. 46 | -------------------------------------------------------------------------------- /facet_product.cxx: -------------------------------------------------------------------------------- 1 | /* $RCSfile: $ 2 | * $Revision: $ $Date: $ 3 | * Auth: David Loffredo (loffredo@steptools.com) 4 | * 5 | * Copyright (c) 1991-2015 by STEP Tools Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "stp2webgl.h" 28 | 29 | 30 | // FACET THE SHAPE INFORMATION -- This follows the tree of shape 31 | // information attached to a product and attempts to build a faceted 32 | // version of each shape rep. In an assembly, some reps only contain 33 | // placements for subcomponents, so they will not have a mesh. 34 | // 35 | static void facet_shape_tree( 36 | stp2webgl_opts * opts, 37 | StixMeshStpAsyncMaker * mesher, 38 | stp_representation * rep 39 | ) 40 | { 41 | unsigned i,sz; 42 | 43 | if (!rep || rose_is_marked(rep)) return; 44 | rose_mark_set(rep); 45 | 46 | // Find all of the solids and schedule them for mesh creation. 47 | // Later we will retrieve the completed meshes and attach them to 48 | // the STEP object. Normally, we must delete the returned mesh 49 | // when finished, but the cache functions take care of that and 50 | // delete the cached mesh when the STEP data is deleted. 51 | // 52 | SetOfstp_representation_item * items = rep->items(); 53 | for (i=0, sz=items->size(); iget(i); 56 | 57 | if (!StixMeshStpBuilder::canMake(rep, it)) 58 | continue; 59 | 60 | // Chance that it might have been previously faceted if it is 61 | // somehow reused by a different part. 62 | if (stixmesh_cache_find(it)) 63 | continue; 64 | 65 | if (mesher-> startMesh(rep, it, &opts->mesh)) { 66 | // printf ("Solid #%lu started\n", it-> entity_id()); 67 | } 68 | } 69 | 70 | 71 | // Now look for attached shapes 72 | StixMgrAsmShapeRep * rep_mgr = StixMgrAsmShapeRep::find(rep); 73 | if (!rep_mgr) return; 74 | 75 | 76 | // All shapes attached by a representation_relationship 77 | for (i=0, sz=rep_mgr->child_rels.size(); ichild_rels[i]; 80 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 81 | 82 | facet_shape_tree(opts, mesher, child); 83 | } 84 | 85 | 86 | // All shapes attached by mapped_item 87 | for (i=0, sz=rep_mgr->child_mapped_items.size(); ichild_mapped_items[i]; 90 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 91 | 92 | facet_shape_tree (opts, mesher, child); 93 | } 94 | } 95 | 96 | 97 | 98 | static void facet_product( 99 | stp2webgl_opts * opts, 100 | StixMeshStpAsyncMaker * mesher, 101 | stp_product_definition * pd 102 | ) 103 | { 104 | if (!pd || rose_is_marked(pd)) return; 105 | rose_mark_set(pd); 106 | 107 | unsigned i,sz; 108 | StixMgrAsmProduct * pd_mgr = StixMgrAsmProduct::find(pd); 109 | if (!pd_mgr) return; // not a proper part 110 | 111 | // facet all direct shapes and any related shapes. 112 | for (i=0, sz=pd_mgr->shapes.size(); ishapes[i]; 115 | facet_shape_tree (opts, mesher, rep); 116 | } 117 | } 118 | 119 | 120 | extern void facet_all_products ( 121 | stp2webgl_opts * opts 122 | ) 123 | { 124 | // Mesh the geometry present in each assembly 125 | StixMeshStpAsyncMaker mesher; 126 | unsigned i,sz; 127 | 128 | rose_mark_begin(); 129 | for (i=0, sz=opts->root_prods.size(); iroot_prods[i]); 132 | } 133 | rose_mark_end(); 134 | 135 | // Now collect the meshed representations as they are completed. 136 | // The getResults() function takes an argument that tells it 137 | // whether to block or poll. Here we block, but you may want to 138 | // poll if your application is also servicing a UI. 139 | // 140 | StixMeshStp * mesh; 141 | while ((mesh = mesher.getResult(1)) != 0) 142 | { 143 | stp_representation * rep = mesh-> getRepresentation(); 144 | stp_representation_item * it = mesh->getStepSolid(); 145 | stixmesh_cache_add (it, mesh); 146 | 147 | // printf ("Rep #%lu, Solid #%lu completed\n", 148 | // rep-> entity_id(), it-> entity_id() 149 | // ); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /stp2webgl.cxx: -------------------------------------------------------------------------------- 1 | /* $RCSfile: $ 2 | * $Revision: $ $Date: $ 3 | * Auth: David Loffredo (loffredo@steptools.com) 4 | * 5 | * Copyright (c) 1991-2015 by STEP Tools Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "stp2webgl.h" 25 | 26 | enum FileFormat { FmtWebXML, FmtTxtSTL, FmtBinSTL }; 27 | 28 | extern int write_webxml (stp2webgl_opts * opts); 29 | extern int write_ascii_stl (stp2webgl_opts * opts); 30 | extern int write_binary_stl (stp2webgl_opts * opts); 31 | 32 | 33 | const char * tool_name = "Facet STEP for Lightweight Viewing"; 34 | const char * tool_trace = "stp2webgl"; 35 | 36 | const char * usage_msg = "Usage: %s [options] [shape_eids]\n"; 37 | const char * opts_short = 38 | " -help for a list of available options.\n\n"; 39 | 40 | const char * opts_long = 41 | "\n" 42 | " This tool converts STEP CAD data into triangular meshes, and then\n" 43 | " writes the result into lightweight files for use in WebGL and other\n" 44 | " visualization applications.\n" 45 | "\n" 46 | " -help\t\t - Print this help message. \n" 47 | " -stl\t\t - Write STL data in ascii text format. \n" 48 | " -stlbin\t\t - Write STL data in binary format. \n" 49 | " -webxml\t\t - Write XML for WebGl client (default). \n" 50 | "\n" 51 | " -tol \t - Absolute linearization tolerance. When linearizing\n" 52 | "\t\t curves, this is the maximum that a line segment can\n" 53 | "\t\t deviate from the original. Distance given in native\n" 54 | "\t\t units of the part. (eg 0.001)\n" 55 | "\n" 56 | " -ftol \t - Fractional linearization tolerance. As above, but\n" 57 | " \t\t the value is given as a fraction of the bounding\n" 58 | " \t\t box of the curve or surface. (eg 0.1 for 10%)\n" 59 | "\n" 60 | " -min \t - Absolute minimum face size to facet. Faces with a\n" 61 | " \t\t bounding box smaller than this size are collapsed into\n" 62 | "\t\t a point. Size given in native units of the part.\n" 63 | "\n" 64 | " -fmin \t - Fractional minimum face size to facet. As above, but\n" 65 | " \t\t the value is given as a fraction of the bounding box\n" 66 | "\t\t of the face. (eg 0.1 for 10%%)\n" 67 | "\n" 68 | " -root \t - Write the subassembly rooted at the #eid instance,\n" 69 | " \t\t which should be a product_definition\n" 70 | "\n" 71 | " -o \t - Write output to given file\n" 72 | " -d\t\t - Write multiple files (-o is a directory)\n" 73 | "\n" 74 | ; 75 | 76 | static void usage (const char * name) 77 | { 78 | fprintf (stderr, usage_msg, name); 79 | fputs (opts_short, stderr); 80 | exit (1); 81 | } 82 | 83 | static void long_usage (const char * name) 84 | { 85 | printf (usage_msg, name); 86 | puts (opts_long); 87 | exit (0); 88 | } 89 | 90 | 91 | #define NEXT_ARG(i,argc,argv) ((i\n"); 131 | exit (1); 132 | } 133 | opts.mesh.setToleranceAbsolute(tmp); 134 | } 135 | 136 | else if (!strcmp(arg, "-ftol")) 137 | { 138 | double tmp; 139 | const char * val = NEXT_ARG(idx,argc,argv); 140 | if (!val || (sscanf (val, "%lf", &tmp) != 1)) { 141 | fprintf (stderr, "option: -ftol \n"); 142 | exit (1); 143 | } 144 | opts.mesh.setToleranceFraction(tmp); 145 | } 146 | 147 | else if (!strcmp(arg, "-min")) 148 | { 149 | double tmp; 150 | const char * val = NEXT_ARG(idx,argc,argv); 151 | if (!val || (sscanf (val, "%lf", &tmp) != 1)) { 152 | fprintf (stderr, "option: -min \n"); 153 | exit (1); 154 | } 155 | opts.mesh.setMinFaceAbsolute(tmp); 156 | } 157 | else if (!strcmp(arg, "-fmin")) 158 | { 159 | double tmp; 160 | const char * val = NEXT_ARG(idx,argc,argv); 161 | if (!val || (sscanf (val, "%lf", &tmp) != 1)) { 162 | fprintf (stderr, "option: -fmin \n"); 163 | exit (1); 164 | } 165 | opts.mesh.setMinFaceFraction(tmp); 166 | } 167 | else if (!strcmp(arg, "-root")) 168 | { 169 | unsigned tmp; 170 | const char * val = NEXT_ARG(idx,argc,argv); 171 | 172 | if (!val || (tmp=atol(val)) == 0) { 173 | fprintf (stderr, "invalid entity id for -root\n"); 174 | exit (1); 175 | } 176 | opts.root_ids.append(tmp); 177 | 178 | } 179 | else if (!strcmp(arg, "-o")) 180 | { 181 | const char * val = NEXT_ARG(idx,argc,argv); 182 | if (!val) { 183 | fprintf (stderr, "option: -o \n"); 184 | exit (1); 185 | } 186 | opts.dstfile = val; 187 | } 188 | 189 | else if (!strcmp(arg, "-d")) 190 | { 191 | opts.do_split = 1; 192 | } 193 | 194 | else if (*arg == '-') 195 | { 196 | fprintf (stderr, "unknown option: %s\n", arg); 197 | exit (1); 198 | } 199 | else if (!opts.srcfile) 200 | { 201 | opts.srcfile = arg; 202 | } 203 | else 204 | { 205 | // already seen a filename, so this must be 206 | // a shape rep id 207 | unsigned eid = atol(arg); 208 | if (!eid) { 209 | printf ("Bad EID: %s\n", arg); 210 | exit (1); 211 | } 212 | opts.shape_ids.append(eid); 213 | } 214 | } 215 | 216 | if (!opts.srcfile) 217 | usage(argv[0]); 218 | 219 | 220 | // Read the step file 221 | opts.design = ROSE.findDesign(opts.srcfile); 222 | if (!opts.design) { 223 | printf ("Could not open design %s\n", opts.srcfile); 224 | exit (2); 225 | } 226 | 227 | // prepare for working with assemblies 228 | rose_compute_backptrs (opts.design); 229 | stix_tag_asms (opts.design); 230 | stix_tag_units (opts.design); 231 | stixmesh_resolve_presentation (opts.design); 232 | 233 | // Find the assembly roots to export. Given as a list of product 234 | // definition #IDs or all roots by default. 235 | // 236 | unsigned i,sz; 237 | for (i=0, sz=opts.root_ids.size(); ifindByEntityId(eid) 243 | ); 244 | 245 | if (!pd) { 246 | printf ("Could not find product definition #%d\n", eid); 247 | exit (2); 248 | } 249 | opts.root_prods.append(pd); 250 | } 251 | 252 | // default to all of the assembly roots if none given 253 | if (!opts.root_prods.size()) 254 | stix_find_root_products(&opts.root_prods, opts.design); 255 | 256 | 257 | // Recursively traverse the root assemblies and write out the 258 | // faceted data. 259 | switch (fmt) { 260 | case FmtTxtSTL: 261 | return write_ascii_stl(&opts); 262 | 263 | case FmtBinSTL: 264 | return write_binary_stl(&opts); 265 | 266 | case FmtWebXML: 267 | return write_webxml(&opts); 268 | 269 | //------------------------------ 270 | // Other lightweight visualization formats can be added here 271 | // by creating your own write_foo() driver. You can use the 272 | // existing drivers as a template. The webxml driver emits 273 | // product structure as well as facets, while the STL driver 274 | // just emits a single collection of facets for everything. 275 | // 276 | 277 | default: 278 | printf ("No support for format %d\n", (int)fmt); 279 | return 1; 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /stp2webgl.h: -------------------------------------------------------------------------------- 1 | /* $RCSfile: $ 2 | * $Revision: $ $Date: $ 3 | * Auth: David Loffredo (loffredo@steptools.com) 4 | * 5 | * Copyright (c) 1991-2015 by STEP Tools Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | class stp2webgl_opts { 22 | public: 23 | StpAsmProductDefVec root_prods; 24 | 25 | rose_uint_vector root_ids; 26 | rose_uint_vector shape_ids; 27 | 28 | StixMeshOptions mesh; 29 | 30 | RoseDesign * design; 31 | 32 | const char * srcfile; 33 | const char * dstfile; 34 | const char * dstdir; 35 | 36 | int do_split; 37 | 38 | 39 | stp2webgl_opts() 40 | : design(0), 41 | srcfile(0), 42 | dstfile(0), 43 | dstdir(0), 44 | do_split(0) 45 | { 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /stp2webgl.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | X64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | X64 19 | 20 | 21 | Debug DLL 22 | Win32 23 | 24 | 25 | Debug DLL 26 | X64 27 | 28 | 29 | Release DLL 30 | Win32 31 | 32 | 33 | Release DLL 34 | X64 35 | 36 | 37 | 38 | 39 | Win32Proj 40 | stp2webgl 41 | 42 | 43 | 44 | Application 45 | v120 46 | 47 | 48 | Application 49 | v120 50 | 51 | 52 | Application 53 | true 54 | v120 55 | 56 | 57 | Application 58 | true 59 | v120 60 | 61 | 62 | Application 63 | v120 64 | 65 | 66 | Application 67 | v120 68 | 69 | 70 | Application 71 | true 72 | v120 73 | 74 | 75 | Application 76 | true 77 | v120 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Level3 109 | Disabled 110 | EnableFastChecks 111 | MultiThreadedDebugDLL 112 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 113 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 114 | 115 | 116 | Console 117 | true 118 | $(ROSE)\lib\i86_win32_vc12_md 119 | stpcad stpcad_stixmesh.lib;stpcad_stix.lib;p28e2.lib;rose.lib;dtnurbsc.lib;vcf2c.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 120 | MSVCRT 121 | 122 | 123 | 124 | 125 | Level3 126 | Disabled 127 | EnableFastChecks 128 | MultiThreadedDebugDLL 129 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 130 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 131 | 132 | 133 | Console 134 | true 135 | $(ROSE)\lib\x64_win64_vc12_md 136 | stpcad stpcad_stixmesh.lib;stpcad_stix.lib;p28e2.lib;rose.lib;dtnurbsc.lib;vcf2c.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 137 | MSVCRT 138 | 139 | 140 | 141 | 142 | Level3 143 | ProgramDatabase 144 | MaxSpeed 145 | MultiThreadedDLL 146 | true 147 | true 148 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 149 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 150 | 151 | 152 | Console 153 | true 154 | true 155 | true 156 | $(ROSE)\lib\i86_win32_vc12_md 157 | stpcad stpcad_stixmesh.lib;stpcad_stix.lib;p28e2.lib;rose.lib;dtnurbsc.lib;vcf2c.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 158 | 159 | 160 | 161 | 162 | Level3 163 | ProgramDatabase 164 | MaxSpeed 165 | MultiThreadedDLL 166 | true 167 | true 168 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 169 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 170 | 171 | 172 | Console 173 | true 174 | true 175 | true 176 | $(ROSE)\lib\x64_win64_vc12_md 177 | stpcad stpcad_stixmesh.lib;stpcad_stix.lib;p28e2.lib;rose.lib;dtnurbsc.lib;vcf2c.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 178 | 179 | 180 | 181 | 182 | Level3 183 | Disabled 184 | EnableFastChecks 185 | MultiThreadedDebugDLL 186 | WIN32;_DEBUG;_CONSOLE;ROSE_DLL;ROSE_CLSDLL;%(PreprocessorDefinitions) 187 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 188 | 189 | 190 | Console 191 | true 192 | $(ROSE)\lib\i86_win32_vc12_md 193 | stpcad stpcad_stixmeshdlld.lib;stpcad_stixdlld.lib;p28e2dlld.lib;rosedlld.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 194 | MSVCRT 195 | 196 | 197 | 198 | 199 | Level3 200 | Disabled 201 | EnableFastChecks 202 | MultiThreadedDebugDLL 203 | WIN32;_DEBUG;_CONSOLE;ROSE_DLL;ROSE_CLSDLL;%(PreprocessorDefinitions) 204 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 205 | 206 | 207 | Console 208 | true 209 | $(ROSE)\lib\x64_win64_vc12_md 210 | stpcad stpcad_stixmeshdlld.lib;stpcad_stixdlld.lib;p28e2dlld.lib;rosedlld.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 211 | MSVCRT 212 | 213 | 214 | 215 | 216 | Level3 217 | ProgramDatabase 218 | MaxSpeed 219 | MultiThreadedDLL 220 | true 221 | true 222 | WIN32;NDEBUG;_CONSOLE;ROSE_DLL;ROSE_CLSDLL;%(PreprocessorDefinitions) 223 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 224 | 225 | 226 | Console 227 | true 228 | true 229 | true 230 | $(ROSE)\lib\i86_win32_vc12_md 231 | stpcad stpcad_stixmeshdll.lib;stpcad_stixdll.lib;p28e2dll.lib;rosedll.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 232 | 233 | 234 | 235 | 236 | Level3 237 | ProgramDatabase 238 | MaxSpeed 239 | MultiThreadedDLL 240 | true 241 | true 242 | WIN32;NDEBUG;_CONSOLE;ROSE_DLL;ROSE_CLSDLL;%(PreprocessorDefinitions) 243 | $(ROSE_INCLUDE);$(ROSE_INCLUDE)\stpcad;$(ROSE_INCLUDE)\stixmesh;$(ROSE_INCLUDE)\stix 244 | 245 | 246 | Console 247 | true 248 | true 249 | true 250 | $(ROSE)\lib\x64_win64_vc12_md 251 | stpcad stpcad_stixmeshdll.lib;stpcad_stixdll.lib;p28e2dll.lib;rosedll.lib;kernel32.lib;user32.lib;advapi32.lib;%(AdditionalDependencies) 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | -------------------------------------------------------------------------------- /stp2webgl.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | h;hpp;hxx;hm;inl;inc;xsd 6 | 7 | 8 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 9 | 10 | 11 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Source Files 20 | Source Files 21 | Source Files 22 | Source Files 23 | Source Files 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /win32.mak: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for Windows 3 | # 4 | # Call as "NMAKE /f win32.mak" 5 | # 6 | # Most defaults are brought in by the rose_config file. This file 7 | # links against the ST-Developer DLLs so it will work with Personal 8 | # Edition. 9 | # 10 | !include $(ROSE_CONFIG) 11 | 12 | EXEC = stp2webgl.exe 13 | 14 | CXX_CFLAGS = \ 15 | /DROSE_DLL \ 16 | /I"$(ROSE_INCLUDE)" \ 17 | /I"$(ROSE_INCLUDE)\stpcad" \ 18 | /I"$(ROSE_INCLUDE)\stixmesh" \ 19 | /I"$(ROSE_INCLUDE)\stix" 20 | 21 | CXX_LDFLAGS = /LIBPATH:"$(ROSE_LIB)" 22 | 23 | LIBRARIES = \ 24 | stpcad_stixmeshdll.lib stpcad_stixdll.lib stpcaddll.lib \ 25 | p28e2dll.lib rosedll.lib $(CXX_SYSLIBS) 26 | 27 | OBJECTS = \ 28 | stp2webgl$o \ 29 | facet_product$o \ 30 | write_stl$o \ 31 | write_stlbin$o \ 32 | write_webxml$o 33 | 34 | 35 | #======================================== 36 | # Standard Symbolic Targets 37 | # 38 | default: $(EXEC) 39 | install: $(EXEC) 40 | 41 | clean: 42 | - $(RM) *.obj 43 | - $(RM) *.exe 44 | - $(RM) *.exe.manifest 45 | 46 | very-clean: clean 47 | spotless: very-clean 48 | 49 | #======================================== 50 | # Executables and other targets 51 | # 52 | $(EXEC): $(OBJECTS) 53 | $(CXX_LINK) /out:$@ $(OBJECTS) $(LIBRARIES) 54 | $(CXX_EMBED_EXE_MANIFEST) 55 | 56 | 57 | -------------------------------------------------------------------------------- /write_stl.cxx: -------------------------------------------------------------------------------- 1 | /* $RCSfile: $ 2 | * $Revision: $ $Date: $ 3 | * Auth: David Loffredo (loffredo@steptools.com) 4 | * 5 | * Copyright (c) 1991-2015 by STEP Tools Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "stp2webgl.h" 25 | 26 | // write_stl() -- write a single STL file for a STEP model. This 27 | // facets everything in one pass, and then work on the cached data. 28 | // It then recursively walks down through any assemblies, applying 29 | // transforms to the facet data and writing ASCII STL. 30 | // 31 | 32 | extern void facet_all_products (stp2webgl_opts * opts); 33 | extern int write_ascii_stl (stp2webgl_opts * opts); 34 | 35 | static void print_mesh_for_product ( 36 | FILE * stlfile, 37 | stp_product_definition * pd, 38 | StixMtrx &starting_placement 39 | ); 40 | 41 | // ====================================================================== 42 | 43 | extern int write_ascii_stl (stp2webgl_opts * opts) 44 | { 45 | FILE * stlfile = stdout; 46 | unsigned i,sz; 47 | 48 | if (opts->do_split) 49 | { 50 | printf ("Only single STL file output currently implemented\n"); 51 | return 2; 52 | } 53 | 54 | if (opts->dstfile) 55 | { 56 | stlfile = rose_fopen(opts->dstfile, "w"); 57 | if (!stlfile) { 58 | printf ("Could not open output file\n"); 59 | return 2; 60 | } 61 | } 62 | 63 | // Recursively facet all of the products in the root assemblies 64 | // and attach each resulting mesh to the representation item for 65 | // each solid. 66 | // 67 | facet_all_products(opts); 68 | 69 | 70 | fputs ("solid ", stlfile); 71 | if (opts-> dstfile) fputs (opts-> dstfile, stlfile); 72 | fputs ("\n", stlfile); 73 | 74 | // Now print the mesh details along with placement info 75 | for (i=0, sz=opts->root_prods.size(); iroot_prods[i], root_placement); 83 | } 84 | 85 | fputs ("endsolid ", stlfile); 86 | if (opts-> dstfile) fputs (opts-> dstfile, stlfile); 87 | fputs ("\n", stlfile); 88 | 89 | return 0; 90 | } 91 | 92 | 93 | 94 | //------------------------------------------------------------ 95 | //------------------------------------------------------------ 96 | // PRINT THE FACET INFORMATION -- This follows the shape information 97 | // attached to a single product or assembly and prints it to the STL 98 | // file. This is adapted from the stixmesh facet assembly sample. 99 | // 100 | // Since the shapes are in a tree that parallels the product tree, we 101 | // look for attached next_assembly_usage_occurrences (NAUO) that tell 102 | // us when we are moving into the shape of another product. 103 | //------------------------------------------------------------ 104 | //------------------------------------------------------------ 105 | 106 | 107 | 108 | static void print_triangle ( 109 | FILE * stlfile, 110 | const StixMeshFacetSet * fs, 111 | StixMtrx &xform, 112 | unsigned facet_num 113 | ) 114 | { 115 | double v[3]; 116 | double n[3]; 117 | const StixMeshFacet * f = fs-> getFacet(facet_num); 118 | const char * vertexfmt = " vertex %.15g %.15g %.15g\n"; 119 | 120 | if (!f) return; 121 | 122 | // The components of the triangle verticies and vertex normals are 123 | // given by an index into internal tables. Apply the transform so 124 | // that the facet is placed correctly in the part space. 125 | // 126 | // facet_normal_now_computed_in_latest_versions 127 | #ifdef LATEST_STDEV 128 | fs->getFacetNormal(n, f); 129 | stixmesh_transform_dir (n, xform, n); 130 | #else 131 | stixmesh_transform_dir (n, xform, fs-> getNormal(f-> facet_normal)); 132 | #endif 133 | fprintf(stlfile, "facet normal %.15g %.15g %.15g\n", n[0], n[1], n[2]); 134 | 135 | fputs(" outer loop\n", stlfile); 136 | 137 | stixmesh_transform (v, xform, fs-> getVertex(f-> verts[0])); 138 | fprintf(stlfile, vertexfmt, v[0], v[1], v[2]); 139 | 140 | stixmesh_transform (v, xform, fs-> getVertex(f-> verts[1])); 141 | fprintf(stlfile, vertexfmt, v[0], v[1], v[2]); 142 | 143 | stixmesh_transform (v, xform, fs-> getVertex(f-> verts[2])); 144 | fprintf(stlfile, vertexfmt, v[0], v[1], v[2]); 145 | fputs(" endloop\n", stlfile); 146 | fputs("endfacet\n", stlfile); 147 | } 148 | 149 | 150 | 151 | 152 | static void print_mesh_for_shape ( 153 | FILE * stlfile, 154 | stp_representation * rep, 155 | StixMtrx &rep_xform 156 | ) 157 | { 158 | unsigned i, sz; 159 | unsigned j, szz; 160 | 161 | if (!rep) return; 162 | 163 | // Does the rep have any meshed items? In an assembly, some reps 164 | // just contain placements for transforming components. If there 165 | // are solids, we should have previously generated meshes. 166 | // 167 | SetOfstp_representation_item * items = rep->items(); 168 | for (i=0, sz=items->size(); iget(i); 171 | StixMeshStp * mesh = stixmesh_cache_find (it); 172 | if (!mesh) continue; 173 | 174 | const StixMeshFacetSet * fs = mesh-> getFacetSet(); 175 | 176 | for (j=0, szz=fs->getFacetCount(); j< szz; j++) { 177 | print_triangle (stlfile, fs, rep_xform, j); 178 | } 179 | } 180 | 181 | 182 | // Go through all of the child shapes which can be attached by a 183 | // shape_reprepresentation_relationship or a mapped_item. If the 184 | // relation has a NAUO associated with it, then it is the start of 185 | // a different product, otherwise it is still part of the shape of 186 | // this one. 187 | // 188 | StixMgrAsmShapeRep * rep_mgr = StixMgrAsmShapeRep::find(rep); 189 | if (!rep_mgr) return; 190 | 191 | for (i=0, sz=rep_mgr->child_rels.size(); ichild_rels[i]; 194 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 195 | 196 | // Move to location in enclosing asm 197 | StixMtrx child_xform = stix_get_shape_usage_xform (rel); 198 | child_xform = child_xform * rep_xform; 199 | 200 | print_mesh_for_shape (stlfile, child, child_xform); 201 | } 202 | 203 | 204 | for (i=0, sz=rep_mgr->child_mapped_items.size(); ichild_mapped_items[i]; 207 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 208 | 209 | // Move to location in enclosing asm 210 | StixMtrx child_xform = stix_get_shape_usage_xform (rel); 211 | child_xform = child_xform * rep_xform; 212 | 213 | print_mesh_for_shape (stlfile, child, child_xform); 214 | } 215 | } 216 | 217 | 218 | static void print_mesh_for_product ( 219 | FILE * stlfile, 220 | stp_product_definition * pd, 221 | StixMtrx &starting_placement 222 | ) 223 | { 224 | // Print the shape tree for each shape associated with a product, 225 | // and then follow the shape tree downward. At each level we 226 | // check the shape relationship for a link to product relations 227 | // because shape side because there can be relationships there 228 | // that are not linked to products. 229 | // 230 | unsigned i, sz; 231 | StixMgrAsmProduct * pm = StixMgrAsmProduct::find(pd); 232 | if (!pm) return; 233 | 234 | for (i=0, sz=pm->shapes.size(); ishapes[i]; 237 | print_mesh_for_shape (stlfile, rep, starting_placement); 238 | } 239 | } 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /write_stlbin.cxx: -------------------------------------------------------------------------------- 1 | /* $RCSfile: $ 2 | * $Revision: $ $Date: $ 3 | * Auth: David Loffredo (loffredo@steptools.com) 4 | * 5 | * Copyright (c) 1991-2015 by STEP Tools Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "stp2webgl.h" 25 | 26 | 27 | // write_binary_stl() -- write a single STL file for a STEP model. 28 | // This facets everything in one pass, and then work on the cached 29 | // data. It then recursively walks down through any assemblies, 30 | // applying transforms to the facet data and writing Binary STL. 31 | // 32 | 33 | extern void facet_all_products (stp2webgl_opts * opts); 34 | extern int write_binary_stl (stp2webgl_opts * opts); 35 | 36 | static void write_float (FILE * file, double val); 37 | static void write_unsigned (FILE * file, unsigned val); 38 | 39 | static unsigned count_mesh_for_product ( 40 | stp_product_definition * pd 41 | ) ; 42 | static void print_mesh_for_product ( 43 | FILE * stlfile, 44 | stp_product_definition * pd, 45 | StixMtrx &starting_placement 46 | ); 47 | 48 | // ====================================================================== 49 | 50 | 51 | extern int write_binary_stl (stp2webgl_opts * opts) 52 | { 53 | FILE * stlfile = stdout; 54 | unsigned i,sz; 55 | unsigned count = 0; 56 | 57 | if (opts->do_split) 58 | { 59 | printf ("Only single STL file output currently implemented\n"); 60 | return 2; 61 | } 62 | 63 | if (opts->dstfile) 64 | { 65 | stlfile = rose_fopen(opts->dstfile, "wb"); 66 | if (!stlfile) { 67 | printf ("Could not open output file\n"); 68 | return 2; 69 | } 70 | } 71 | 72 | // Recursively facet all of the products in the root assemblies 73 | // and attach each resulting mesh to the representation item for 74 | // each solid. 75 | // 76 | facet_all_products(opts); 77 | 78 | // Now print the mesh details along with placement info 79 | for (i=0, sz=opts->root_prods.size(); iroot_prods[i]); 82 | } 83 | 84 | unsigned char buf[80]; 85 | 86 | memset (buf, 0, 80); 87 | strcpy ((char*)buf, "binary stl"); 88 | fwrite (buf, sizeof (unsigned char), 80, stlfile); 89 | write_unsigned(stlfile, count); 90 | 91 | // Now print the mesh details along with placement info 92 | for (i=0, sz=opts->root_prods.size(); iroot_prods[i], root_placement); 100 | } 101 | 102 | fclose(stlfile); 103 | return 0; 104 | } 105 | 106 | 107 | 108 | //------------------------------------------------------------ 109 | //------------------------------------------------------------ 110 | // COUNT FACETS -- Binary STL needs an upfront count, which we 111 | // need to compute ahead of time. 112 | // 113 | 114 | unsigned count_mesh_for_shape ( 115 | stp_representation * rep 116 | ) 117 | { 118 | unsigned i, sz; 119 | unsigned count = 0; 120 | 121 | if (!rep) return count; 122 | 123 | // Count any local meshes 124 | SetOfstp_representation_item * items = rep->items(); 125 | for (i=0, sz=items->size(); iget(i); 128 | StixMeshStp * mesh = stixmesh_cache_find (it); 129 | if (!mesh) continue; 130 | 131 | count += mesh-> getFacetSet()->getFacetCount(); 132 | } 133 | 134 | // Count all of the child shapes 135 | StixMgrAsmShapeRep * rep_mgr = StixMgrAsmShapeRep::find(rep); 136 | if (!rep_mgr) return count; 137 | 138 | for (i=0, sz=rep_mgr->child_rels.size(); ichild_rels[i]; 141 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 142 | count += count_mesh_for_shape (child); 143 | } 144 | 145 | for (i=0, sz=rep_mgr->child_mapped_items.size(); ichild_mapped_items[i]; 148 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 149 | count += count_mesh_for_shape (child); 150 | } 151 | return count; 152 | } 153 | 154 | 155 | unsigned count_mesh_for_product ( 156 | stp_product_definition * pd 157 | ) 158 | { 159 | unsigned i, sz; 160 | unsigned count = 0; 161 | StixMgrAsmProduct * pm = StixMgrAsmProduct::find(pd); 162 | if (!pm) return count; 163 | 164 | for (i=0, sz=pm->shapes.size(); ishapes[i]; 167 | count += count_mesh_for_shape (rep); 168 | } 169 | return count; 170 | } 171 | 172 | 173 | 174 | 175 | //------------------------------------------------------------ 176 | //------------------------------------------------------------ 177 | // PRINT THE FACET INFORMATION -- This follows the shape information 178 | // attached to a single product or assembly and prints it to the STL 179 | // file. This is adapted from the stixmesh facet assembly sample. 180 | // 181 | // Since the shapes are in a tree that parallels the product tree, we 182 | // look for attached next_assembly_usage_occurrences (NAUO) that tell 183 | // us when we are moving into the shape of another product. 184 | //------------------------------------------------------------ 185 | //------------------------------------------------------------ 186 | 187 | static void print_triangle ( 188 | FILE * stlfile, 189 | const StixMeshFacetSet * fs, 190 | StixMtrx &xform, 191 | unsigned facet_num 192 | ) 193 | { 194 | double v[3]; 195 | double n[3]; 196 | const StixMeshFacet * f = fs-> getFacet(facet_num); 197 | if (!f) return; 198 | 199 | // The components of the triangle verticies and vertex normals are 200 | // given by an index into internal tables. Apply the transform so 201 | // that the facet is placed correctly in the part space. 202 | // 203 | //FACET_NORMAL_NOW_COMPUTED_IN_LATEST_VERSIONS 204 | #ifdef LATEST_STDEV 205 | fs->getFacetNormal(n, f); 206 | stixmesh_transform_dir (n, xform, n); 207 | #else 208 | stixmesh_transform_dir (n, xform, fs-> getNormal(f-> facet_normal)); 209 | #endif 210 | write_float(stlfile, n[0]); 211 | write_float(stlfile, n[1]); 212 | write_float(stlfile, n[2]); 213 | 214 | stixmesh_transform (v, xform, fs-> getVertex(f-> verts[0])); 215 | write_float(stlfile, v[0]); 216 | write_float(stlfile, v[1]); 217 | write_float(stlfile, v[2]); 218 | 219 | stixmesh_transform (v, xform, fs-> getVertex(f-> verts[1])); 220 | write_float(stlfile, v[0]); 221 | write_float(stlfile, v[1]); 222 | write_float(stlfile, v[2]); 223 | 224 | stixmesh_transform (v, xform, fs-> getVertex(f-> verts[2])); 225 | write_float(stlfile, v[0]); 226 | write_float(stlfile, v[1]); 227 | write_float(stlfile, v[2]); 228 | 229 | putc(0, stlfile); // 16bit zero 230 | putc(0, stlfile); 231 | } 232 | 233 | 234 | static void print_mesh_for_shape ( 235 | FILE * stlfile, 236 | stp_representation * rep, 237 | StixMtrx &rep_xform 238 | ) 239 | { 240 | unsigned i, sz; 241 | unsigned j, szz; 242 | 243 | if (!rep) return; 244 | 245 | // Does the rep have any meshed items? In an assembly, some reps 246 | // just contain placements for transforming components. If there 247 | // are solids, we should have previously generated meshes. 248 | // 249 | SetOfstp_representation_item * items = rep->items(); 250 | for (i=0, sz=items->size(); iget(i); 253 | StixMeshStp * mesh = stixmesh_cache_find (it); 254 | if (!mesh) continue; 255 | 256 | const StixMeshFacetSet * fs = mesh-> getFacetSet(); 257 | 258 | for (j=0, szz=fs->getFacetCount(); j< szz; j++) { 259 | print_triangle (stlfile, fs, rep_xform, j); 260 | } 261 | } 262 | 263 | 264 | // Go through all of the child shapes which can be attached by a 265 | // shape_reprepresentation_relationship or a mapped_item. If the 266 | // relation has a NAUO associated with it, then it is the start of 267 | // a different product, otherwise it is still part of the shape of 268 | // this one. 269 | // 270 | StixMgrAsmShapeRep * rep_mgr = StixMgrAsmShapeRep::find(rep); 271 | if (!rep_mgr) return; 272 | 273 | for (i=0, sz=rep_mgr->child_rels.size(); ichild_rels[i]; 276 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 277 | 278 | // Move to location in enclosing asm 279 | StixMtrx child_xform = stix_get_shape_usage_xform (rel); 280 | child_xform = child_xform * rep_xform; 281 | 282 | print_mesh_for_shape (stlfile, child, child_xform); 283 | } 284 | 285 | 286 | for (i=0, sz=rep_mgr->child_mapped_items.size(); ichild_mapped_items[i]; 289 | stp_representation * child = stix_get_shape_usage_child_rep (rel); 290 | 291 | // Move to location in enclosing asm 292 | StixMtrx child_xform = stix_get_shape_usage_xform (rel); 293 | child_xform = child_xform * rep_xform; 294 | 295 | print_mesh_for_shape (stlfile, child, child_xform); 296 | } 297 | } 298 | 299 | 300 | static void print_mesh_for_product ( 301 | FILE * stlfile, 302 | stp_product_definition * pd, 303 | StixMtrx &starting_placement 304 | ) 305 | { 306 | // Print the shape tree for each shape associated with a product, 307 | // and then follow the shape tree downward. At each level we 308 | // check the shape relationship for a link to product relations 309 | // because shape side because there can be relationships there 310 | // that are not linked to products. 311 | // 312 | unsigned i, sz; 313 | StixMgrAsmProduct * pm = StixMgrAsmProduct::find(pd); 314 | if (!pm) return; 315 | 316 | for (i=0, sz=pm->shapes.size(); ishapes[i]; 319 | print_mesh_for_shape (stlfile, rep, starting_placement); 320 | } 321 | } 322 | 323 | 324 | 325 | //------------------------------------------------------------ 326 | //------------------------------------------------------------ 327 | // Binary utilities -- Binary STL uses little endian 32bit float, and 328 | // little endan 32bit unsigned integer. This matches the common intel 329 | // usage for windows, mac and linux. We swap big endian if working on 330 | // aix, sparc, hpux or ppc macs. 331 | //------------------------------------------------------------ 332 | //------------------------------------------------------------ 333 | 334 | #if defined(_AIX) || defined(__sparc) || defined(__hpux) 335 | #define BIG_ENDIAN 336 | #endif 337 | 338 | #ifdef __APPLE__ 339 | #if defined (__ppc__) || defined(__ppc64__) 340 | #define BIG_ENDIAN 341 | #endif 342 | #endif 343 | 344 | static void write_float (FILE * file, double val) 345 | { 346 | union { 347 | float float_elem; /* assume 32bit float */ 348 | unsigned char words[4]; 349 | } olbuf; 350 | 351 | olbuf.float_elem = (float) val; 352 | 353 | #ifdef BIG_ENDIAN 354 | putc (olbuf.words[3], file); 355 | putc (olbuf.words[2], file); 356 | putc (olbuf.words[1], file); 357 | putc (olbuf.words[0], file); 358 | #else 359 | putc (olbuf.words[0], file); 360 | putc (olbuf.words[1], file); 361 | putc (olbuf.words[2], file); 362 | putc (olbuf.words[3], file); 363 | #endif 364 | } 365 | 366 | static void write_unsigned (FILE * file, unsigned val) 367 | { 368 | // shifts work properly regardless of endian-ness 369 | putc (val & 0xff, file); 370 | putc ((val >> 8) & 0xff, file); 371 | putc ((val >> 16) & 0xff, file); 372 | putc ((val >> 24) & 0xff, file); 373 | } 374 | -------------------------------------------------------------------------------- /write_webxml.cxx: -------------------------------------------------------------------------------- 1 | /* $RCSfile: $ 2 | * $Revision: $ $Date: $ 3 | * Auth: David Loffredo (loffredo@steptools.com) 4 | * 5 | * Copyright (c) 1991-2015 by STEP Tools Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "stp2webgl.h" 28 | 29 | // transfor moved into stix in latest version 30 | #ifndef LATEST_STDEV 31 | #define stix_get_transform stixmesh_get_transform 32 | #endif 33 | 34 | // This function writes a lightweight XML description of the STEP 35 | // product structure and faceted shapes using the format described 36 | // below. 37 | // 38 | // http://www.steptools.com/support/stdev_docs/stixmesh/XMLFormat.html 39 | // 40 | // The product structure is written in a first pass and all of the 41 | // shapes are submitted to the facetter. Then the shell facets are 42 | // written as they become available and then the facetted data is 43 | // released. This is a more complex arrangement than just facetting 44 | // everything in one batch, but it may be more memory efficient. 45 | // 46 | 47 | 48 | extern int write_webxml (stp2webgl_opts * opts); 49 | 50 | 51 | //====================================================================== 52 | 53 | 54 | static void append_double(RoseXMLWriter * xml, double val) 55 | { 56 | char buff[64]; 57 | sprintf (buff, "%.15g", val); 58 | xml->text(buff); 59 | } 60 | 61 | static void append_integer(RoseXMLWriter * xml, long val) 62 | { 63 | char buff[64]; 64 | sprintf (buff, "%ld", val); 65 | xml->text(buff); 66 | } 67 | 68 | static void append_color(RoseXMLWriter * xml, unsigned val) 69 | { 70 | char buff[] = "rrggbb "; 71 | sprintf (buff, "%06x", val); 72 | xml->addAttribute("color", buff); 73 | } 74 | 75 | 76 | static void append_ref (RoseXMLWriter * xml, RoseObject * obj) 77 | { 78 | if (obj->isa(ROSE_DOMAIN(RoseUnion))) { 79 | obj = rose_get_nested_object(ROSE_CAST(RoseUnion, obj)); 80 | } 81 | 82 | if (!obj->entity_id()) { 83 | printf ("No entity id for %p: %s\n", obj, obj->domain()->name()); 84 | exit (2); 85 | } 86 | 87 | char buff[20]; 88 | sprintf (buff, "id%lu", obj->entity_id()); 89 | xml->text(buff); 90 | } 91 | 92 | 93 | static void append_refatt ( 94 | RoseXMLWriter * xml, 95 | const char * att, 96 | RoseObject * obj 97 | ) 98 | { 99 | if (obj) { 100 | xml->beginAttribute(att); 101 | append_ref(xml, obj); 102 | xml->endAttribute(); 103 | } 104 | } 105 | 106 | static FILE * open_dir_file(const char * dir, const char * fname) 107 | { 108 | RoseStringObject path = dir; 109 | path.cat("/"); 110 | path.cat(fname); 111 | 112 | return fopen(path, "w"); 113 | } 114 | 115 | 116 | //====================================================================== 117 | // STEP PMI Annotations -- GD&T and construction planes 118 | // 119 | 120 | 121 | 122 | static void write_poly_point(RoseXMLWriter * xml, double vals[3]) 123 | { 124 | xml->beginElement("p"); 125 | xml->beginAttribute ("l"); 126 | append_double(xml, vals[0]); xml->text(" "); 127 | append_double(xml, vals[1]); xml->text(" "); 128 | append_double(xml, vals[2]); 129 | xml->endAttribute(); 130 | xml->endElement("p"); 131 | } 132 | 133 | static void write_poly_point(RoseXMLWriter * xml, ListOfDouble * vals) 134 | { 135 | xml->beginElement("p"); 136 | xml->beginAttribute ("l"); 137 | append_double(xml, vals->get(0)); xml->text(" "); 138 | append_double(xml, vals->get(1)); xml->text(" "); 139 | append_double(xml, vals->get(2)); 140 | xml->endAttribute(); 141 | xml->endElement("p"); 142 | } 143 | 144 | 145 | static void append_step_curve(RoseXMLWriter * xml, stp_curve * c) 146 | { 147 | /* May also want to handle composite curves here in this routine, since 148 | * a composite curve may contain via points, and thus run into trouble.*/ 149 | unsigned i,sz; 150 | 151 | if (c->isa(ROSE_DOMAIN(stp_polyline))) { 152 | 153 | stp_polyline * poly = ROSE_CAST(stp_polyline, c); 154 | ListOfstp_cartesian_point * pts = poly->points(); 155 | 156 | if (!pts || pts->size() < 2) 157 | return; 158 | 159 | xml->beginElement("polyline"); 160 | 161 | for (i=0, sz=pts->size(); iget(i); 163 | ListOfDouble * vals = pt->coordinates(); 164 | write_poly_point(xml, vals); 165 | } 166 | 167 | xml->endElement("polyline"); 168 | } 169 | 170 | } 171 | 172 | static void append_annotation( 173 | RoseXMLWriter * xml, 174 | stp_geometric_set * gset 175 | ) 176 | { 177 | SetOfstp_geometric_set_select * elems = gset->elements(); 178 | if (!elems) return; 179 | 180 | unsigned i,sz; 181 | for (i=0, sz=elems->size(); iget(i); 183 | if (sel-> is_curve()) { 184 | append_step_curve(xml, sel->_curve()); 185 | } 186 | else if (sel-> is_point()) { 187 | } 188 | else if (sel-> is_surface()) { 189 | } 190 | 191 | } 192 | } 193 | 194 | static void append_annotation( 195 | RoseXMLWriter * xml, 196 | stp_representation_item * it 197 | ) 198 | { 199 | if (!it) return; 200 | 201 | if (it-> isa(ROSE_DOMAIN(stp_annotation_plane))) 202 | { 203 | // do we do anything special with the plane? 204 | unsigned i, sz; 205 | stp_annotation_plane * ap = ROSE_CAST(stp_annotation_plane,it); 206 | 207 | for (i=0, sz=ap->elements()->size(); i elements()-> get(i))); 214 | 215 | append_annotation (xml, elem); 216 | } 217 | } 218 | 219 | else if (it-> isa(ROSE_DOMAIN(stp_annotation_occurrence))) 220 | { 221 | stp_annotation_occurrence * ao 222 | = ROSE_CAST(stp_annotation_occurrence,it); 223 | 224 | if (!ao-> item()) return; 225 | 226 | if (ao-> item()-> isa(ROSE_DOMAIN(stp_geometric_set))) { 227 | append_annotation(xml, ROSE_CAST(stp_geometric_set,ao->item())); 228 | } 229 | } 230 | 231 | else { 232 | printf("append_annotation unimplemented case: %s\n", 233 | it->domain()->name()); 234 | } 235 | 236 | } 237 | 238 | 239 | static void append_model_body( 240 | stp2webgl_opts * opts, 241 | RoseXMLWriter * xml, 242 | stp_representation * model) 243 | { 244 | xml->beginElement("annotation"); 245 | append_refatt (xml, "id", model); 246 | 247 | SetOfstp_representation_item * items = model->items(); 248 | unsigned sz = items->size(); 249 | for (unsigned i=0; iget(i); 251 | append_annotation(xml, it); 252 | } 253 | 254 | xml->endElement("annotation"); 255 | } 256 | 257 | 258 | static void append_model( 259 | stp2webgl_opts * opts, 260 | RoseXMLWriter * xml, 261 | stp_representation * model 262 | ) 263 | { 264 | if (!model || rose_is_marked(model)) return; 265 | rose_mark_set(model); 266 | 267 | if (!opts->do_split) 268 | append_model_body(opts, xml, model); 269 | else 270 | { 271 | char fname[100]; 272 | sprintf (fname, "annotation_id%lu.xml", model->entity_id()); 273 | 274 | xml->beginElement("annotation"); 275 | append_refatt (xml, "id", model); 276 | xml->addAttribute("href", fname); 277 | xml->endElement("annotation"); 278 | 279 | FILE * fd = open_dir_file(opts->dstdir, fname); 280 | 281 | RoseOutputFile xmlfile (fd, fname); 282 | RoseXMLWriter part_xml(&xmlfile); 283 | part_xml.escape_dots = ROSE_FALSE; 284 | part_xml.writeHeader(); 285 | 286 | append_model_body(opts, &part_xml, model); 287 | 288 | part_xml.close(); 289 | xmlfile.flush(); 290 | fclose(fd); 291 | } 292 | } 293 | 294 | 295 | static void append_step_curve( 296 | RoseXMLWriter * xml, 297 | stp_representation * rep, 298 | stp_bounded_curve * curve 299 | ) 300 | { 301 | StixMeshNurbs nurbs; 302 | stixmesh_create_bounded_curve(&nurbs, curve, rep); 303 | 304 | StixMeshBoundingBox bbox; 305 | 306 | if (!nurbs.getConvexHull(&bbox)) { 307 | printf ("Could not get convec hull of curve, skipping"); 308 | return; 309 | } 310 | double tol = bbox.diagonal() / 100.; 311 | 312 | rose_real_vector u_vals; 313 | nurbs.extractTolerancedPoints(&u_vals, tol, 1); 314 | 315 | xml->beginElement("polyline"); 316 | 317 | unsigned i,sz; 318 | for (i=0, sz=u_vals.size(); iendElement("polyline"); 325 | } 326 | 327 | static void append_rep_item( 328 | RoseXMLWriter * xml, 329 | stp_representation * rep, 330 | stp_representation_item * it 331 | ) 332 | { 333 | if (!it) 334 | return; 335 | 336 | if (it->isa(ROSE_DOMAIN(stp_bounded_curve))) { 337 | append_step_curve(xml, rep, ROSE_CAST(stp_bounded_curve, it)); 338 | } 339 | 340 | } 341 | 342 | static void append_constructive_geom_body( 343 | stp2webgl_opts * opts, 344 | RoseXMLWriter * xml, 345 | stp_constructive_geometry_representation * cgr 346 | ) 347 | { 348 | unsigned i,sz; 349 | xml->beginElement("annotation"); 350 | append_refatt (xml, "id", cgr); 351 | 352 | SetOfstp_representation_item * items = cgr->items(); 353 | for (i=0, sz=items->size(); iget(i); 355 | append_rep_item(xml, cgr, it); 356 | } 357 | 358 | xml->endElement("annotation"); 359 | } 360 | 361 | 362 | static void append_constructive_geom( 363 | stp2webgl_opts * opts, 364 | RoseXMLWriter * xml, 365 | stp_constructive_geometry_representation * cg 366 | ) 367 | { 368 | if (!cg || rose_is_marked(cg)) return; 369 | rose_mark_set(cg); 370 | 371 | if (!opts->do_split) 372 | append_constructive_geom_body(opts, xml, cg); 373 | else 374 | { 375 | char fname[100]; 376 | sprintf (fname, "constructive_id%lu.xml", cg->entity_id()); 377 | 378 | xml->beginElement("annotation"); 379 | append_refatt (xml, "id", cg); 380 | xml->addAttribute("href", fname); 381 | xml->endElement("annotation"); 382 | 383 | FILE * fd = open_dir_file(opts->dstdir, fname); 384 | 385 | RoseOutputFile xmlfile (fd, fname); 386 | RoseXMLWriter part_xml(&xmlfile); 387 | part_xml.escape_dots = ROSE_FALSE; 388 | part_xml.writeHeader(); 389 | 390 | append_constructive_geom_body(opts, &part_xml, cg); 391 | 392 | part_xml.close(); 393 | xmlfile.flush(); 394 | fclose(fd); 395 | } 396 | } 397 | 398 | 399 | 400 | static void append_annotation_refs( 401 | RoseXMLWriter * xml, 402 | stp_representation * rep 403 | ) 404 | { 405 | /* FIXME - this generates both constructive geometry and 406 | * annotations. theses should be split out, but are are not 407 | * (currently) doing so since that would require updating the 408 | * webgl javascript. 409 | */ 410 | unsigned i,sz; 411 | unsigned cnt = 0; 412 | 413 | if (!rep->isa(ROSE_DOMAIN(stp_shape_representation))) 414 | return; 415 | 416 | StixMeshRepresentationVec * models = stixmesh_get_draughting_models( 417 | ROSE_CAST(stp_shape_representation, rep) 418 | ); 419 | 420 | StixMeshConstructiveGeomVec * cgeom = 421 | stixmesh_get_constructive_geometry(rep); 422 | 423 | if (!models && !cgeom) 424 | return; 425 | 426 | xml->beginAttribute("annotation"); 427 | 428 | if (models) { 429 | for (i=0, sz=models->size(); itext (" "); 431 | append_ref(xml, models->get(i)); 432 | cnt++; 433 | } 434 | } 435 | 436 | if (cgeom) { 437 | for (i=0, sz=cgeom->size(); itext (" "); 439 | append_ref(xml, cgeom->get(i)); 440 | cnt++; 441 | } 442 | } 443 | 444 | xml->endAttribute(); 445 | } 446 | 447 | 448 | 449 | static void append_annotations( 450 | stp2webgl_opts * opts, 451 | RoseXMLWriter * xml, 452 | stp_representation * rep 453 | ) 454 | { 455 | unsigned i, sz; 456 | 457 | if (!rep->isa(ROSE_DOMAIN(stp_shape_representation))) 458 | return; 459 | 460 | StixMeshRepresentationVec * models = stixmesh_get_draughting_models( 461 | ROSE_CAST(stp_shape_representation, rep)); 462 | 463 | StixMeshConstructiveGeomVec * cgeom = 464 | stixmesh_get_constructive_geometry(rep); 465 | 466 | if (!models && !cgeom) 467 | return; 468 | 469 | if (models) { 470 | for (i=0, sz = models->size(); iget(i); 472 | append_model(opts, xml, model); 473 | } 474 | } 475 | 476 | if (cgeom) { 477 | for (i=0, sz = cgeom->size(); iget(i); 479 | append_constructive_geom(opts, xml, cg); 480 | } 481 | } 482 | 483 | } 484 | 485 | 486 | //====================================================================== 487 | // Queue STEP Representation -- Add shape data to facetter queue and 488 | // write forward information about the step shell. 489 | // 490 | void append_shell_refs( 491 | RoseXMLWriter * xml, 492 | stp_representation * rep 493 | ) 494 | { 495 | unsigned i,sz; 496 | unsigned count=0; 497 | SetOfstp_representation_item * items = rep->items(); 498 | 499 | for (i=0, sz=items->size(); iget(i); 502 | if (!StixMeshStpBuilder::isShell(rep, it)) 503 | continue; 504 | 505 | if (!count) xml->beginAttribute ("shell"); 506 | if (count++) xml->text (" "); 507 | append_ref (xml, it); 508 | } 509 | 510 | if (count) xml->endAttribute(); 511 | } 512 | 513 | 514 | static void append_asm_child( 515 | stp2webgl_opts * opts, 516 | RoseXMLWriter * xml, 517 | RoseObject * rel 518 | ) 519 | { 520 | StixMgrAsmRelation * mgr = StixMgrAsmRelation::find(rel); 521 | if (!mgr) return; 522 | 523 | stp_representation * child = mgr->child; 524 | 525 | xml->beginElement("child"); 526 | append_refatt (xml, "ref", child); 527 | 528 | unsigned i,j; 529 | StixMtrx xform = stix_get_transform(mgr); 530 | xml->beginAttribute ("xform"); 531 | for (i=0; i<4; i++) { 532 | for (j=0; j<4; j++) { 533 | if (i || j) xml->text(" "); 534 | append_double(xml, xform.get(j,i)); 535 | } 536 | } 537 | xml->endAttribute(); 538 | xml->endElement("child"); 539 | } 540 | 541 | 542 | void queue_shapes( 543 | stp2webgl_opts * opts, 544 | RoseXMLWriter * xml, 545 | StixMeshStpAsyncMaker * mesher, 546 | stp_representation * rep 547 | ) 548 | { 549 | unsigned i, j, sz; 550 | 551 | if (!rep || rose_is_marked(rep)) return; 552 | rose_mark_set(rep); 553 | 554 | StixMgrAsmShapeRep * mgr = StixMgrAsmShapeRep::find(rep); 555 | if (!mgr) return; 556 | 557 | // Write facets by default, unless we have a list of reps. In the 558 | // latter case only write facets if a rep is in the list. 559 | 560 | int do_facets = 1; 561 | if (opts->root_ids.size()) 562 | { 563 | unsigned eid = rep->entity_id(); 564 | do_facets = 0; 565 | 566 | for (i=0, sz=opts->root_ids.size(); iroot_ids[i] == eid) { 569 | do_facets = 1; 570 | break; 571 | } 572 | } 573 | } 574 | 575 | xml->beginElement("shape"); 576 | append_refatt (xml, "id", rep); 577 | 578 | StixUnit unit = stix_get_context_length_unit(rep); 579 | if (unit != stixunit_unknown) 580 | { 581 | xml->beginAttribute("unit"); 582 | xml->text (stix_get_unit_name(unit)); 583 | char buff[20]; 584 | sprintf (buff, " %f", stix_get_converted_measure(1., unit, stixunit_m)); 585 | xml->text(buff); 586 | xml->endAttribute(); 587 | } 588 | 589 | if (do_facets) 590 | append_shell_refs(xml, rep); 591 | 592 | append_annotation_refs(xml, rep); 593 | 594 | for (j=0, sz=mgr->child_rels.size(); jchild_rels[j]); 596 | 597 | for (j=0, sz=mgr->child_mapped_items.size(); jchild_mapped_items[j]); 599 | 600 | xml->endElement("shape"); 601 | 602 | for (j=0, sz=mgr->child_rels.size(); jchild_rels[j] 605 | ); 606 | if (rm) queue_shapes(opts, xml, mesher, rm->child); 607 | } 608 | 609 | for (j=0, sz=mgr->child_mapped_items.size(); jchild_mapped_items[j] 612 | ); 613 | if (rm) queue_shapes(opts, xml, mesher, rm->child); 614 | } 615 | 616 | 617 | if (do_facets) 618 | { 619 | SetOfstp_representation_item * items = rep->items(); 620 | unsigned sz = items->size(); 621 | 622 | for (unsigned i=0; iget(i); 624 | 625 | if (StixMeshStpBuilder::canMake(rep, ri)) 626 | mesher->startMesh(rep, ri, &opts->mesh); 627 | } 628 | 629 | append_annotations(opts, xml, rep); 630 | } 631 | } 632 | 633 | 634 | 635 | //====================================================================== 636 | // Write Triangle Data for a Facetted Shell 637 | // 638 | static void append_facet( 639 | RoseXMLWriter * xml, 640 | const StixMeshFacetSet * fs, 641 | unsigned fidx, 642 | int write_normal 643 | ) 644 | { 645 | const StixMeshFacet * f = fs->getFacet(fidx); 646 | if (!f) return; 647 | 648 | xml->beginElement("f"); 649 | xml->beginAttribute("v"); 650 | append_integer(xml, f->verts[0]); xml->text(" "); 651 | append_integer(xml, f->verts[1]); xml->text(" "); 652 | append_integer(xml, f->verts[2]); 653 | xml->endAttribute(); 654 | 655 | if (write_normal) { 656 | // facet_normal_now_computed_in_latest_versions 657 | #ifdef LATEST_STDEV 658 | double fnorm[3]; 659 | fs->getFacetNormal(fnorm, fidx); 660 | #else 661 | const double * fnorm = fs-> getNormal(f-> facet_normal); 662 | #endif 663 | xml->beginAttribute("fn"); 664 | append_double(xml, fnorm[0]); xml->text(" "); 665 | append_double(xml, fnorm[1]); xml->text(" "); 666 | append_double(xml, fnorm[2]); 667 | xml->endAttribute(); 668 | } 669 | 670 | for (unsigned j=0; j<3; j++) { 671 | // facet_normal_now_computed_in_latest_versions 672 | #ifdef LATEST_STDEV 673 | const double * normal = fs->getNormal(f->normals[j]); 674 | #else 675 | const double * normal = fs->getNormal(f->vert_normals[j]); 676 | #endif 677 | if (normal) 678 | { 679 | xml->beginElement("n"); 680 | xml->beginAttribute("d"); 681 | append_double(xml, normal[0]); xml->text(" "); 682 | append_double(xml, normal[1]); xml->text(" "); 683 | append_double(xml, normal[2]); 684 | xml->endAttribute(); 685 | xml->endElement("n"); 686 | } 687 | } 688 | xml->endElement("f"); 689 | } 690 | 691 | 692 | void append_shell_facets( 693 | RoseXMLWriter * xml, 694 | const StixMeshStp * shell 695 | ) 696 | { 697 | int WRITE_NORMAL = 0; 698 | unsigned i,sz; 699 | unsigned j,szz; 700 | const StixMeshFacetSet * facets = shell->getFacetSet(); 701 | 702 | xml->beginElement("shell"); 703 | append_refatt(xml, "id", shell->getStepSolid()); 704 | 705 | unsigned dflt_color = stixmesh_get_color (shell->getStepSolid()); 706 | if (dflt_color != STIXMESH_NULL_COLOR) 707 | append_color(xml, dflt_color); 708 | 709 | xml->beginElement("verts"); 710 | for (i=0, sz=facets->getVertexCount(); igetVertex(i); 713 | xml->beginElement("v"); 714 | xml->beginAttribute("p"); 715 | append_double(xml, pt[0]); xml->text(" "); 716 | append_double(xml, pt[1]); xml->text(" "); 717 | append_double(xml, pt[2]); 718 | xml->endAttribute(); 719 | xml->endElement("v"); 720 | } 721 | xml->endElement("verts"); 722 | 723 | 724 | // The facet set has all of the facets for the shell. Break it up 725 | // into groups by step face. 726 | 727 | for (i=0, sz=shell->getFaceCount(); igetFaceInfo(i); 730 | unsigned first = fi->getFirstFacet(); 731 | unsigned color = stixmesh_get_color(fi->getFace()); 732 | if (first == ROSE_NOTFOUND) 733 | continue; 734 | 735 | xml->beginElement("facets"); 736 | 737 | // Always tag the face with a color, unless everything is null. 738 | if (color == STIXMESH_NULL_COLOR) 739 | color = dflt_color; 740 | 741 | if (color != STIXMESH_NULL_COLOR) 742 | append_color(xml, color); 743 | 744 | for (j=0, szz=fi->getFacetCount(); jendElement("facets"); 748 | } 749 | 750 | xml->endElement("shell"); 751 | } 752 | 753 | 754 | static void export_shell( 755 | stp2webgl_opts * opts, 756 | RoseXMLWriter * xml, 757 | const StixMeshStp * shell 758 | ) 759 | { 760 | if (!shell) return; 761 | 762 | if (!opts->do_split) { 763 | append_shell_facets(xml, shell); 764 | } 765 | else 766 | { 767 | unsigned i,sz; 768 | StixMeshBoundingBox bbox; 769 | const StixMeshFacetSet * facets = shell->getFacetSet(); 770 | 771 | // compute the bounding box for the shell 772 | for (i=0, sz=facets->getVertexCount(); igetVertex(i); 775 | bbox.update(pt); 776 | } 777 | 778 | char fname[100]; 779 | sprintf (fname, "shell_id%lu.xml", shell->getStepSolid()->entity_id()); 780 | 781 | xml->beginElement("shell"); 782 | append_refatt(xml, "id", shell->getStepSolid()); 783 | 784 | xml->beginAttribute("size"); 785 | append_integer(xml, facets->getFacetCount()); 786 | xml->endAttribute(); 787 | 788 | xml->beginAttribute("bbox"); 789 | append_double(xml, bbox.minx); xml->text(" "); 790 | append_double(xml, bbox.miny); xml->text(" "); 791 | append_double(xml, bbox.minz); xml->text(" "); 792 | append_double(xml, bbox.maxx); xml->text(" "); 793 | append_double(xml, bbox.maxy); xml->text(" "); 794 | append_double(xml, bbox.maxz); 795 | xml->endAttribute(); 796 | 797 | // append the area 798 | double area = 0.; 799 | for (i=0, sz=shell->getFaceCount(); igetFaceInfo(i); 801 | area += face->getArea(); 802 | } 803 | xml->beginAttribute("a"); 804 | append_double (xml, area); 805 | xml->endAttribute(); 806 | 807 | xml->addAttribute("href", fname); 808 | xml->endElement("shell"); 809 | 810 | /* Write the shell in its own XML file */ 811 | FILE * fd = open_dir_file(opts->dstdir, fname); 812 | RoseOutputFile xmlfile (fd, fname); 813 | RoseXMLWriter shell_xml(&xmlfile); 814 | shell_xml.escape_dots = ROSE_FALSE; 815 | shell_xml.writeHeader(); 816 | 817 | append_shell_facets(&shell_xml, shell); 818 | 819 | shell_xml.close(); 820 | xmlfile.flush(); 821 | fclose(fd); 822 | } 823 | } 824 | 825 | 826 | 827 | 828 | //====================================================================== 829 | // Write STEP Product Structure 830 | // 831 | 832 | static const char * get_product_name(stp_next_assembly_usage_occurrence* nauo) 833 | { 834 | stp_product_definition * pd = stix_get_related_pdef(nauo); 835 | stp_product_definition_formation * pdf = pd? pd->formation(): 0; 836 | stp_product * prod = pdf? pdf->of_product(): 0; 837 | 838 | return prod? prod->name(): 0; 839 | } 840 | 841 | int nauo_product_cmp(const void* a, const void* b) 842 | { 843 | const char * name_a = get_product_name( 844 | *(stp_next_assembly_usage_occurrence**) a 845 | ); 846 | 847 | const char * name_b = get_product_name( 848 | *(stp_next_assembly_usage_occurrence**) b 849 | ); 850 | 851 | if (name_a == name_b) return 0; 852 | if (!name_a) return +1; 853 | if (!name_b) return -1; 854 | 855 | return strcmp(name_a, name_b); 856 | } 857 | 858 | static void append_stplink ( 859 | stp2webgl_opts * opts, 860 | RoseXMLWriter * xml, 861 | stp_product_definition * pd 862 | ) 863 | { 864 | // write reference to a component stepfile. Only used when 865 | // splitting a large assembly into a a collection of part files 866 | // and when a file exists for this particular product. 867 | // 868 | if (!opts->do_split) return; 869 | 870 | RoseStringObject name ("part"); 871 | 872 | stp_product_definition_formation * pdf = pd-> formation(); 873 | stp_product * p = pdf? pdf-> of_product(): 0; 874 | 875 | char * pname = p? p-> name(): 0; 876 | if (!pname || !*pname) pname = (char *) "none"; 877 | 878 | if (!name.is_empty()) name += "_"; 879 | name += pname; 880 | 881 | // change whitespace and other non filesystem safe 882 | // characters to underscores 883 | // 884 | char * c = name; 885 | while (*c) { 886 | if (isspace(*c)) *c = '_'; 887 | if (*c == '?') *c = '_'; 888 | if (*c == '/') *c = '_'; 889 | if (*c == '\\') *c = '_'; 890 | if (*c == ':') *c = '_'; 891 | if (*c == '"') *c = '_'; 892 | if (*c == '\'') *c = '_'; 893 | c++; 894 | } 895 | 896 | if (pd-> design()-> fileExtension()) { 897 | name += "."; 898 | name += pd-> design()-> fileExtension(); 899 | } 900 | 901 | RoseStringObject path = opts->dstdir; 902 | path += "/"; 903 | path += name; 904 | 905 | // expects the component files to be present already. Do not 906 | // generate link if not there. 907 | if (rose_file_exists(path)) { 908 | xml->addAttribute("step", name); 909 | } 910 | } 911 | 912 | 913 | static void export_product( 914 | stp2webgl_opts * opts, 915 | RoseXMLWriter * xml, 916 | stp_product_definition * pd 917 | ) 918 | { 919 | unsigned i,sz; 920 | 921 | if (!pd || rose_is_marked(pd)) return; 922 | rose_mark_set(pd); 923 | 924 | StixMgrAsmProduct * mgr = StixMgrAsmProduct::find(pd); 925 | 926 | xml->beginElement("product"); 927 | append_refatt(xml, "id", pd); 928 | append_stplink (opts, xml, pd); 929 | 930 | stp_product_definition_formation * pdf = pd->formation(); 931 | stp_product * prod = pdf->of_product(); 932 | 933 | xml->addAttribute("name", prod->name()); 934 | 935 | if (mgr->shapes.size()) { 936 | xml->beginAttribute("shape"); 937 | for (i=0, sz=mgr->shapes.size(); i 0) xml->text(" "); 940 | append_ref(xml, mgr->shapes[i]); 941 | } 942 | xml->endAttribute(); 943 | } 944 | 945 | if (mgr->child_nauos.size()) 946 | { 947 | qsort(mgr->child_nauos._buffer(), 948 | mgr->child_nauos.size(), 949 | sizeof(stp_next_assembly_usage_occurrence*), 950 | &nauo_product_cmp 951 | ); 952 | 953 | xml->beginAttribute("children"); 954 | 955 | for (i=0, sz=mgr->child_nauos.size(); i 0) xml->text(" "); 958 | stp_next_assembly_usage_occurrence * nauo = mgr->child_nauos[i]; 959 | append_ref(xml, stix_get_related_pdef(mgr->child_nauos[i])); 960 | } 961 | xml->endAttribute(); 962 | } 963 | xml->endElement("product"); 964 | 965 | for (i=0, sz=mgr->child_nauos.size(); ichild_nauos[i]; 968 | export_product(opts, xml, stix_get_related_pdef(nauo)); 969 | } 970 | } 971 | 972 | 973 | // ====================================================================== 974 | 975 | 976 | int write_webxml (stp2webgl_opts * opts) 977 | { 978 | FILE * xmlout = 0; 979 | RoseStringObject index_file; 980 | unsigned i,sz; 981 | 982 | if (opts->do_split) 983 | { 984 | opts->dstdir = opts->dstfile; 985 | if (!opts->dstdir) 986 | opts->dstdir = "step_data"; 987 | 988 | index_file = opts->dstdir; 989 | index_file.cat("/index.xml"); 990 | opts->dstfile = index_file; 991 | 992 | if (!rose_dir_exists (opts->dstdir) && 993 | (rose_mkdir(opts->dstdir) != 0)) { 994 | printf ("Cannot create directory %s\n", opts->dstdir); 995 | return 2; 996 | } 997 | } 998 | 999 | if (opts->dstfile) 1000 | { 1001 | xmlout = rose_fopen(opts->dstfile, "w"); 1002 | if (!xmlout) { 1003 | printf ("Could not open output file\n"); 1004 | return 2; 1005 | } 1006 | } 1007 | 1008 | if (xmlout == 0) { 1009 | xmlout = stdout; 1010 | } 1011 | 1012 | // The XML writer class is a simple class that handles tag and 1013 | // attribute writing. The RoseOutputFile class is a data stream 1014 | // class that the XML file writes to. 1015 | // 1016 | RoseOutputFile xmlfile(xmlout, opts->dstfile? opts->dstfile: "xml file"); 1017 | RoseXMLWriter xml(&xmlfile); 1018 | xml.escape_dots = ROSE_FALSE; 1019 | xml.writeHeader(); 1020 | xml.beginElement("step-assembly"); 1021 | 1022 | xml.beginAttribute("root"); 1023 | for (i=0, sz=opts->root_prods.size(); iroot_prods[i]; 1026 | if (i > 0) xml.text(" "); 1027 | append_ref(&xml, pd); 1028 | } 1029 | xml.endAttribute(); 1030 | 1031 | rose_mark_begin(); 1032 | for (i=0, sz=opts->root_prods.size(); iroot_prods[i]); 1035 | } 1036 | 1037 | // Schedule each solid for faceting, which will happen in child 1038 | // threads and then write each shell as it becomes available. 1039 | StixMeshStpAsyncMaker mesher; 1040 | StixMeshStp * mesh; 1041 | 1042 | for (i=0, sz=opts->root_prods.size(); iroot_prods[i] 1047 | ); 1048 | 1049 | for (j=0, szz=mgr->shapes.size(); jshapes[j]); 1051 | } 1052 | } 1053 | 1054 | while ((mesh = mesher.getResult(1)) != 0) 1055 | { 1056 | export_shell(opts, &xml, mesh); 1057 | delete mesh; 1058 | } 1059 | 1060 | xml.endElement("step-assembly"); 1061 | xml.close(); 1062 | xmlfile.flush(); 1063 | rose_mark_end(); 1064 | 1065 | return 0; 1066 | } 1067 | 1068 | --------------------------------------------------------------------------------