├── targetver.h ├── Resource.h ├── ap238export.sln ├── stdafx.cpp ├── stdafx.h ├── README.md ├── ap238export.vcxproj.filters ├── CONTRIBUTING.md ├── ap238export.rc ├── LICENSE.txt ├── ap238export.vcxproj └── ap238export.cpp /targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /Resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by ap238export.rc 4 | // 5 | 6 | // Next default values for new objects 7 | // 8 | #ifdef APSTUDIO_INVOKED 9 | #ifndef APSTUDIO_READONLY_SYMBOLS 10 | 11 | #define _APS_NEXT_RESOURCE_VALUE 1000 12 | #define _APS_NEXT_CONTROL_VALUE 1000 13 | #define _APS_NEXT_SYMED_VALUE 1000 14 | #define _APS_NEXT_COMMAND_VALUE 32771 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /ap238export.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ap238export", "ap238export.vcxproj", "{576D0DE8-28EC-47C3-A65C-B9DC390684A6}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|x64 = Debug|x64 9 | Release|x64 = Release|x64 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {576D0DE8-28EC-47C3-A65C-B9DC390684A6}.Debug|x64.ActiveCfg = Debug|x64 13 | {576D0DE8-28EC-47C3-A65C-B9DC390684A6}.Debug|x64.Build.0 = Debug|x64 14 | {576D0DE8-28EC-47C3-A65C-B9DC390684A6}.Release|x64.ActiveCfg = Release|x64 15 | {576D0DE8-28EC-47C3-A65C-B9DC390684A6}.Release|x64.Build.0 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ap238export.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | 8 | // DLL stuff for Mastercam to STEP-NC translator 9 | // 10 | #include "stdafx.h" 11 | #include "m_core.h" 12 | #include "m_mastercam.h" 13 | 14 | #ifdef _DEBUG 15 | #define new DEBUG_NEW 16 | #undef THIS_FILE 17 | static char THIS_FILE[] = __FILE__; 18 | #endif 19 | 20 | 21 | extern "C" __declspec(dllexport) int m_version (int version) 22 | { 23 | int ret = C_H_VERSION; 24 | 25 | // Allow chook to run in any version of mastercam that has 26 | // the same major version 27 | if ( (version / 100) == (C_H_VERSION / 100) ) 28 | ret = version; 29 | 30 | return ret; 31 | } 32 | 33 | void ap238export(); 34 | 35 | extern "C" __declspec(dllexport) int m_main (int not_used) 36 | { 37 | // MessageBox (0, "Big Hello from Mastercam!", "", MB_OK); 38 | // SetDllDirectory("C:\\Program Files (x86)\\STEP Tools\\STEP-NC Machine"); 39 | ap238export(); 40 | // SetDllDirectory(NULL); 41 | 42 | return MC_NOERROR; 43 | } -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | 5 | #pragma once 6 | 7 | #ifndef VC_EXTRALEAN 8 | #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers 9 | #endif 10 | 11 | #include "targetver.h" 12 | 13 | #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit 14 | 15 | #include // MFC core and standard components 16 | #include // MFC extensions 17 | 18 | #ifndef _AFX_NO_OLE_SUPPORT 19 | #include // MFC OLE classes 20 | #include // MFC OLE dialog classes 21 | #include // MFC Automation classes 22 | #endif // _AFX_NO_OLE_SUPPORT 23 | 24 | #ifndef _AFX_NO_DB_SUPPORT 25 | #include // MFC ODBC database classes 26 | #endif // _AFX_NO_DB_SUPPORT 27 | 28 | #ifndef _AFX_NO_DAO_SUPPORT 29 | #include // MFC DAO database classes 30 | #endif // _AFX_NO_DAO_SUPPORT 31 | 32 | #ifndef _AFX_NO_OLE_SUPPORT 33 | #include // MFC support for Internet Explorer 4 Common Controls 34 | #endif 35 | #ifndef _AFX_NO_AFXCMN_SUPPORT 36 | #include // MFC support for Windows Common Controls 37 | #endif // _AFX_NO_AFXCMN_SUPPORT 38 | 39 | 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mastercam-stepnc 2 | ======= 3 | 4 | STEP-NC Export Chook for Mastercam 5 | -- 6 | 7 | This project build a plugin for [Mastercam](http://www.mastercam.com) 8 | that exports a machining program as STEP-NC. The program uses the 9 | "Chooks" plugin API to access Mastercam data and the STEP-NC Machine 10 | API to create the STEP-NC data. 11 | 12 | ## Building 13 | 14 | This package contains a Visual Studio 2012 project file for building. 15 | Mastercam X8 and X9 requires x64 code, so the project only has platforms 16 | for "Release x64" and "Debug x64". The master branch of this package 17 | supports the latest version of Mastercam (X9) and earlier code can be 18 | found on the mcx8 branch. 19 | 20 | The package requires a Mastercam installation with the Mastercam X8 21 | SDK installed. You also need the STEP-NC Machine DLL to create the 22 | STEP-NC data. A downloadable version that is free for personal use 23 | can be found at: 24 | 25 | STEP-NC Machine (which contains the STEP-NC DLL) 26 | 27 | - Download - http://www.steptools.com/products/stepncmachine/download/ 28 | - API Docs - http://www.steptools.com/support/stepnc_docs/stepncdll/ 29 | 30 | The project will build a DLL called `ap238export.dll` and will output 31 | it to the `C:\Program Files\mcamx8\chooks\` directory. Then you can 32 | call the plugin by starting Mastercam, opening your file, clicking 33 | `Alt-C` and selecting the ap238.export.dll in the chooks dialog box. 34 | 35 | ## Extending 36 | 37 | See [CONTRIBUTING.md](CONTRIBUTING.md) if you would like to send a 38 | pull request with your changes. 39 | -------------------------------------------------------------------------------- /ap238export.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Resource Files 20 | 21 | 22 | Resource Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | 34 | 35 | Header Files 36 | 37 | 38 | Header Files 39 | 40 | 41 | Header Files 42 | 43 | 44 | 45 | 46 | Resource Files 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ap238export.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #ifndef APSTUDIO_INVOKED 11 | #include "targetver.h" 12 | #endif 13 | #include "afxres.h" 14 | #include "verrsrc.h" 15 | 16 | ///////////////////////////////////////////////////////////////////////////// 17 | #undef APSTUDIO_READONLY_SYMBOLS 18 | 19 | #ifdef APSTUDIO_INVOKED 20 | ///////////////////////////////////////////////////////////////////////////// 21 | // 22 | // TEXTINCLUDE 23 | // 24 | 25 | 1 TEXTINCLUDE 26 | BEGIN 27 | "resource.h\0" 28 | END 29 | 30 | 2 TEXTINCLUDE 31 | BEGIN 32 | "#ifndef APSTUDIO_INVOKED\r\n" 33 | "#include ""targetver.h""\r\n" 34 | "#endif\r\n" 35 | "#include ""afxres.h""\r\n" 36 | "#include ""verrsrc.h""\r\n" 37 | "\0" 38 | END 39 | 40 | 3 TEXTINCLUDE 41 | BEGIN 42 | "#define _AFX_NO_SPLITTER_RESOURCES\r\n" 43 | "#define _AFX_NO_OLE_RESOURCES\r\n" 44 | "#define _AFX_NO_TRACKER_RESOURCES\r\n" 45 | "#define _AFX_NO_PROPERTY_RESOURCES\r\n" 46 | "\r\n" 47 | "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" 48 | "LANGUAGE 9, 1\r\n" 49 | #ifndef _AFXDLL 50 | "#include ""afxres.rc"" // Standard components\r\n" 51 | #endif 52 | "#endif\r\n" 53 | "\0" 54 | END 55 | 56 | ///////////////////////////////////////////////////////////////////////////// 57 | #endif // APSTUDIO_INVOKED 58 | 59 | 60 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 61 | LANGUAGE 9, 1 62 | 63 | ///////////////////////////////////////////////////////////////////////////// 64 | // 65 | // Version 66 | // 67 | 68 | VS_VERSION_INFO VERSIONINFO 69 | FILEVERSION 1,0,0,1 70 | PRODUCTVERSION 1,0,0,1 71 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK 72 | #ifdef _DEBUG 73 | FILEFLAGS VS_FF_DEBUG 74 | #else 75 | FILEFLAGS 0x0L 76 | #endif 77 | FILEOS VOS_NT_WINDOWS32 78 | FILETYPE VFT_DLL 79 | FILESUBTYPE VFT2_UNKNOWN 80 | BEGIN 81 | BLOCK "StringFileInfo" 82 | BEGIN 83 | BLOCK "040904B0" 84 | BEGIN 85 | VALUE "CompanyName", "TODO: " 86 | VALUE "FileDescription", "TODO: " 87 | VALUE "FileVersion", "1.0.0.1" 88 | VALUE "InternalName", "ap238export.dll" 89 | VALUE "LegalCopyright", "TODO: (c) . All rights reserved." 90 | VALUE "OriginalFilename","ap238export.dll" 91 | VALUE "ProductName", "TODO: " 92 | VALUE "ProductVersion", "1.0.0.1" 93 | END 94 | END 95 | BLOCK "VarFileInfo" 96 | BEGIN 97 | VALUE "Translation", 0x0409, 1200 98 | END 99 | END 100 | 101 | #endif 102 | #ifndef APSTUDIO_INVOKED 103 | 104 | ///////////////////////////////////////////////////////////////////////////// 105 | // 106 | // Generated from the TEXTINCLUDE 3 resource. 107 | // 108 | #define _AFX_NO_SPLITTER_RESOURCES 109 | #define _AFX_NO_OLE_RESOURCES 110 | #define _AFX_NO_TRACKER_RESOURCES 111 | #define _AFX_NO_PROPERTY_RESOURCES 112 | 113 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) 114 | LANGUAGE 9, 1 115 | #ifndef _AFXDLL 116 | #include "afxres.rc" // Standard components 117 | #endif 118 | #endif 119 | 120 | ///////////////////////////////////////////////////////////////////////////// 121 | #endif // not APSTUDIO_INVOKED 122 | 123 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ap238export.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 | 22 | {576D0DE8-28EC-47C3-A65C-B9DC390684A6} 23 | ap238export 24 | MFCDLLProj 25 | 26 | 27 | 28 | DynamicLibrary 29 | true 30 | Unicode 31 | Dynamic 32 | v120 33 | false 34 | false 35 | 36 | 37 | DynamicLibrary 38 | true 39 | Unicode 40 | Dynamic 41 | v120 42 | false 43 | false 44 | 45 | 46 | DynamicLibrary 47 | false 48 | true 49 | Unicode 50 | Dynamic 51 | v120 52 | false 53 | false 54 | 55 | 56 | DynamicLibrary 57 | false 58 | true 59 | MultiByte 60 | Dynamic 61 | v120 62 | false 63 | false 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | true 83 | 84 | 85 | true 86 | C:\Program Files\mcamx8\chooks\ 87 | 88 | 89 | false 90 | 91 | 92 | false 93 | C:\Program Files\mcamx9\chooks\ 94 | 95 | 96 | 97 | Use 98 | Level3 99 | Disabled 100 | WIN32;_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) 101 | 102 | 103 | Windows 104 | true 105 | .\ap238export.def 106 | 107 | 108 | false 109 | _DEBUG;%(PreprocessorDefinitions) 110 | 111 | 112 | 0x0409 113 | _DEBUG;%(PreprocessorDefinitions) 114 | $(IntDir);%(AdditionalIncludeDirectories) 115 | 116 | 117 | 118 | 119 | Use 120 | Level3 121 | Disabled 122 | WIN32;_WINDOWS;_DEBUG;_USRDLL;%(PreprocessorDefinitions) 123 | C:\Program Files (x86)\mcamx8\sdk;C:\Program Files (x86)\mcamx8\sdk\interfaces\GUI;C:\Program Files (x86)\mcamx8\sdk\interfaces\Core;C:\Program Files (x86)\mcamx8\sdk\interfaces\Control;C:\Program Files (x86)\mcamx8\sdk\interfaces\GeomSld;C:\Program Files (x86)\mcamx8\sdk\interfaces\Lathe;C:\Program Files (x86)\mcamx8\sdk\interfaces\MachineDef;C:\Program Files (x86)\mcamx8\sdk\interfaces\Matss;C:\Program Files (x86)\mcamx8\sdk\interfaces\Mill;C:\Program Files (x86)\mcamx8\sdk\interfaces\Post;C:\Program Files (x86)\mcamx8\sdk\interfaces\MSurf;C:\Program Files (x86)\mcamx8\sdk\interfaces\TlCore;C:\Program Files (x86)\mcamx8\sdk\interfaces\systypes;C:\Program Files (x86)\mcamx8\sdk\interfaces\UICtrls;C:\Program Files (x86)\mcamx8\sdk\interfaces\Verify;C:\Program Files (x86)\mcamx8\sdk\interfaces\Wire;C:\Program Files (x86)\mcamx8\sdk\interfaces\Observable;C:\Program Files (x86)\mcamx8\sdk\3rdParty\BCGCBPro\h;%(AdditionalIncludeDirectories) 124 | 125 | 126 | Windows 127 | true 128 | 129 | 130 | C:\Program Files (x86)\mcamx8\sdk\x64\release;C:\Program Files (x86)\mcamX8\sdk\3rdParty\BCGCBPro\libx64 131 | mastercam.lib;mccore.lib;UICtrls.lib;MCMill.lib;BCGCBPRO2310d120.lib 132 | 133 | 134 | false 135 | _DEBUG;%(PreprocessorDefinitions) 136 | 137 | 138 | 0x0409 139 | _DEBUG;%(PreprocessorDefinitions) 140 | $(IntDir);%(AdditionalIncludeDirectories) 141 | 142 | 143 | 144 | 145 | Level3 146 | Use 147 | MaxSpeed 148 | true 149 | true 150 | WIN32;_WINDOWS;NDEBUG;_USRDLL;%(PreprocessorDefinitions) 151 | 152 | 153 | Windows 154 | true 155 | true 156 | true 157 | .\ap238export.def 158 | 159 | 160 | false 161 | NDEBUG;%(PreprocessorDefinitions) 162 | 163 | 164 | 0x0409 165 | NDEBUG;%(PreprocessorDefinitions) 166 | $(IntDir);%(AdditionalIncludeDirectories) 167 | 168 | 169 | 170 | 171 | Level3 172 | NotUsing 173 | MaxSpeed 174 | true 175 | true 176 | WIN32;_WINDOWS;NDEBUG;_USRDLL;MASTERCAM_AFX;%(PreprocessorDefinitions) 177 | C:\Program Files (x86)\mcamx9\sdk;C:\Program Files (x86)\mcamx9\sdk\interfaces\GUI;C:\Program Files (x86)\mcamx9\sdk\interfaces\Core;C:\Program Files (x86)\mcamx9\sdk\interfaces\Control;C:\Program Files (x86)\mcamx9\sdk\interfaces\GeomSld;C:\Program Files (x86)\mcamx9\sdk\interfaces\Lathe;C:\Program Files (x86)\mcamx9\sdk\interfaces\MachineDef;C:\Program Files (x86)\mcamx9\sdk\interfaces\Matss;C:\Program Files (x86)\mcamx9\sdk\interfaces\Mill;C:\Program Files (x86)\mcamx9\sdk\interfaces\Post;C:\Program Files (x86)\mcamx9\sdk\interfaces\MSurf;C:\Program Files (x86)\mcamx9\sdk\interfaces\TlCore;C:\Program Files (x86)\mcamx9\sdk\interfaces\systypes;C:\Program Files (x86)\mcamx9\sdk\interfaces\UICtrls;C:\Program Files (x86)\mcamx9\sdk\interfaces\Verify;C:\Program Files (x86)\mcamx9\sdk\interfaces\Wire;C:\Program Files (x86)\mcamx9\sdk\interfaces\Observable;C:\Program Files (x86)\mcamx9\sdk\3rdParty\BCGCBPro\h;%(AdditionalIncludeDirectories) 178 | 179 | 180 | Windows 181 | false 182 | true 183 | true 184 | 185 | 186 | C:\Program Files (x86)\mcamx9\sdk\x64\release;C:\Program Files (x86)\mcamx9\sdk\3rdParty\BCGCBPro\libx64 187 | mastercam.lib;mccore.lib;UICtrls.lib;MCMill.lib;BCGCBPRO2310120.lib 188 | 189 | 190 | false 191 | 192 | 193 | false 194 | NDEBUG;%(PreprocessorDefinitions) 195 | 196 | 197 | 0x0409 198 | NDEBUG;%(PreprocessorDefinitions) 199 | $(IntDir);%(AdditionalIncludeDirectories) 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | Create 210 | Create 211 | Create 212 | Create 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | ..\..\..\Program Files (x86)\STEP Tools\STEP-NC Machine\stepnc_x64.dll 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /ap238export.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1991-2015 by STEP Tools Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // main routine for AP-238 export 18 | 19 | #include "stdafx.h" 20 | #include 21 | #include 22 | 23 | #include "m_core.h" 24 | #include "m_mastercam.h" 25 | #include "m_mill.h" 26 | 27 | #import 28 | #import 29 | 30 | #import "C:\\Program Files (x86)\\STEP Tools\\STEP-NC Machine\\stepnc_x64.tlb" 31 | using namespace std; 32 | 33 | 34 | // COM Smart pointer for the move checker. You can also do it the 35 | // old-school way using CoCreateInstance 36 | stepnc_x64::_AptStepMakerPtr apt; 37 | stepnc_x64::_ProcessPtr process; 38 | stepnc_x64::_FeaturePtr feature; 39 | 40 | #ifdef _DEBUG 41 | #define new DEBUG_NEW 42 | #endif 43 | 44 | //#define MY_DEBUG 1 45 | 46 | #ifdef MY_DEBUG 47 | FILE* pfLog; 48 | #define MY_TRACE fprintf 49 | #else 50 | #define MY_TRACE(...) void(0) 51 | #endif 52 | 53 | bool cc1 = true; 54 | bool cc3 = false; 55 | bool use_tp_orientation = true; 56 | bool compound = false; // this flag not fully implemented 57 | bool pattern = false; 58 | 59 | double hole_bot; 60 | 61 | #define EPSILON 0.01 62 | 63 | BOOL VEq(p_3d v1, p_3d v2) 64 | { 65 | return (v1[0] == v2[0] && 66 | v1[1] == v2[1] && 67 | v1[2] == v2[2]); 68 | } 69 | 70 | // database of chains converted to pockets 71 | // eptr_type pChain_db[1024]; 72 | int feature_id_db[1024]; 73 | int ws_id_db[1024]; 74 | int chain_db_count = 0; 75 | 76 | // used to store tool direction and compute CCW vs CW 77 | BOOL tool_direction[1024]; 78 | 79 | // main functions 80 | void LoadAllTools(); 81 | void MakePlanarFace(operation op, p_3d ptCenter, double dLength, double dWidth, _int64 ws_id); 82 | void MakeGeneralOutsideProfile(operation op, CHAIN* pChain, _int64 ws_id); 83 | void MakeGeneralPocket(operation op, CHAIN* pChain, _int64 ws_id, int nChains); 84 | void MakeRoundHole(operation op, p_3d ptCenter, _int64 ws_id); 85 | void MakeRoundPocket(operation op, p_3d ptCenter, double dDiameter, double dDepth, _int64 ws_id); 86 | 87 | 88 | // helper functions 89 | void MakeChainProfile( 90 | CHAIN* pChain, 91 | double z_value, 92 | BOOL closed, 93 | BOOL reverse_contour_direction 94 | ); 95 | 96 | void MakeProfileGeometry ( 97 | ent seg1, ent seg2, 98 | BOOL first, 99 | BOOL boss_or_open, 100 | double z_value, 101 | BOOL last_in_open, 102 | BOOL reverse_contour_direction 103 | ); 104 | 105 | BOOL counter_clockwise (p_2d p1, p_2d p2, p_2d center); 106 | void GetChainBBox( 107 | CHAIN* pChain, int nView, double& dLength, double& dWidth, p_3d center 108 | ); 109 | 110 | 111 | 112 | // code given to us by Mastercam 113 | // Retrieve the 'tree branches' of items above the Operation 114 | // Used to make nested workplans 115 | void GetOpParents(operation *opl, CStringArray *names); 116 | 117 | extern void ap238export() 118 | { 119 | MC_BOOL bResult, bChainResult; 120 | CString strMessage; 121 | nci_bin n; 122 | long ltcode = 0; // lathe tool number 123 | long fpos; 124 | p_3d ptStart, ptEnd, ptBot; 125 | p_3d vecDir, vecRef, vecOldDir = { 0, 0, 1 }; 126 | x_matrix mXform1; // wcs change (for origin) apply first 127 | x_matrix mXform2; // tool plane change (for axis) apply second 128 | unsigned nOldOpID = -1; 129 | int nOldGcode = -1; 130 | double nOldRPM = 0; 131 | double dOldFeed = 0.0; 132 | BOOL bAxisChgd = FALSE; 133 | double dRad; 134 | CString strLabel; 135 | BOOL bFirstMove = TRUE; 136 | BOOL bInRapidMode = FALSE; 137 | short nPrevCComp = 0; 138 | p_3d vecSurfNorm; 139 | BOOL bNewOpCheckCComp = FALSE; 140 | chain_manager_info cmi; 141 | int nChains; 142 | short nPock; // decode pocket and island chains 143 | pock_bound* pPB; 144 | CString cmnt; // current comment 145 | long main_q; // question each export or not 146 | 147 | double hole_z1, hole_z2, hole_z3; // depth for holes when hole pattern 148 | double hole_speed, hole_feed, hole_plunge, hole_retract; 149 | 150 | 151 | CString fnme = "export.stpnc"; 152 | 153 | CFileDialog dlgSave( 154 | FALSE, ".stpnc", fnme, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, 155 | "STEP-NC Files (*.stpnc)|*.stpnc|STEP Files (*.stp;*.step;*.p21)|*.stp;*.step;*.p21|All Files (*.*)|*.*||", NULL 156 | ); 157 | try 158 | { 159 | if (IDOK != dlgSave.DoModal()) 160 | { 161 | return; 162 | } 163 | 164 | #ifdef MY_DEBUG 165 | pfLog = fopen("C:\\mcamap238exportlog.txt", "w+t"); 166 | #endif 167 | // Initialize COM. 168 | HRESULT hr = CoInitialize(NULL); 169 | if (!SUCCEEDED (hr)) 170 | { 171 | #ifdef MY_DEBUG 172 | MY_TRACE(pfLog, "COM initialization failed - call STEP Tools \n"); 173 | fflush(pfLog); 174 | #endif 175 | MessageBox (0, "COM initialization failed - call STEP Tools", "", MB_OK); 176 | return; 177 | } 178 | hr = apt.CreateInstance(__uuidof(stepnc_x64::AptStepMaker)); 179 | if (!SUCCEEDED (hr)) 180 | { 181 | #ifdef MY_DEBUG 182 | MY_TRACE(pfLog, "APT initialization failed - call STEP Tools \n"); 183 | fflush(pfLog); 184 | #endif 185 | MessageBox (0, "APT initialization failed - call STEP Tools", "", MB_OK); 186 | return; 187 | } 188 | hr = feature.CreateInstance(__uuidof(stepnc_x64::Feature)); 189 | if (!SUCCEEDED (hr)) 190 | { 191 | #ifdef MY_DEBUG 192 | MY_TRACE(pfLog, "Feature initialization failed - call STEP Tools \n"); 193 | fflush(pfLog); 194 | #endif 195 | MessageBox (0, "Feature initialization failed - call STEP Tools", "", MB_OK); 196 | return; 197 | } 198 | hr = process.CreateInstance(__uuidof(stepnc_x64::Process)); 199 | if (!SUCCEEDED (hr)) 200 | { 201 | #ifdef MY_DEBUG 202 | MY_TRACE(pfLog, "Process initialization failed - call STEP Tools \n"); 203 | fflush(pfLog); 204 | #endif 205 | MessageBox (0, "Process initialization failed - call STEP Tools", "", MB_OK); 206 | return; 207 | } 208 | 209 | chain_db_count = 0; // database of pocket chains 210 | 211 | 212 | // get name of the machine group 213 | operation *op0 = TpMainOpMgr.GetMainOpList()[0]; 214 | op_group *op_parent = TpMainGrpMgr.GetMainGrpList().GroupByID(op0->cmn.grp_idn); 215 | op_group *op_mach = TpMainGrpMgr.GetMainGrpList().RetrieveRootMachineGroup(op_parent->grp_idn); 216 | 217 | CString main_name = op_mach->name; 218 | 219 | apt->PartNo("Mastercam Export"); 220 | feature->OpenNewWorkpiece ("Mastercam Export"); 221 | 222 | // if on then use bounded curve geometry 223 | // apt->SetDefineArcUsingViaOff (); 224 | // apt->SetDebuggingNamesOn(); 225 | 226 | if (IsEnglish()) 227 | { 228 | MY_TRACE(pfLog, "Setting units to Inches\n"); 229 | apt->Inches(); 230 | } 231 | else 232 | { 233 | MY_TRACE(pfLog, "Setting units to Millimeters\n"); 234 | apt->Millimeters(); 235 | } 236 | 237 | apt->CamModeOn (); 238 | apt->MultaxOn(); 239 | 240 | INT_PTR GrpListSize = TpMainGrpMgr.GetMainGrpList().GetSize (); 241 | CString tmsg; 242 | /* op_group* group0 = TpMainGrpMgr.m_MainGrpList[0]; 243 | op_group* group1 = TpMainGrpMgr.m_MainGrpList[1]; 244 | tmsg.Format ("List size is %d contains %s and %s", GrpListSize, group0->name, group1->name); 245 | AfxMessageBox(tmsg, MB_YESNO | MB_ICONINFORMATION);*/ 246 | 247 | op_group* group = NULL; 248 | if (GrpListSize > 0) 249 | { 250 | op_group* group = TpMainGrpMgr.GetMainGrpList()[0]; 251 | MY_TRACE(pfLog, "Job setup material = %s at (%f, %f, %f) \n\tlength = %f, width = %f, height = %f\n", 252 | group->ogi.pg2.matl_name, 253 | group->ogi.pg3.cpt[X], group->ogi.pg3.cpt[Y], group->ogi.pg3.cpt[Z], 254 | group->ogi.pg3.x, group->ogi.pg3.y, group->ogi.pg3.z); 255 | 256 | if (group->ogi.pg3.x != 0 && group->ogi.pg3.y != 0) 257 | { 258 | process->BlockRawpiece ( 259 | "Mastercam block", 260 | group->ogi.pg3.cpt[X], 261 | group->ogi.pg3.cpt[Y], 262 | group->ogi.pg3.cpt[Z] - group->ogi.pg3.z, 263 | group->ogi.pg3.z, group->ogi.pg3.x, group->ogi.pg3.y 264 | ); 265 | } 266 | } 267 | 268 | LoadAllTools (); 269 | 270 | INT_PTR OpListSize = TpMainOpMgr.GetMainOpList().GetSize(); 271 | if (OpListSize == 0) 272 | MY_TRACE(pfLog, "Empty Operation list\n"); 273 | else 274 | { 275 | operation *opl = NULL; 276 | op_information info; 277 | opl = TpMainOpMgr.GetMainOpList()[0]; 278 | op_info (opl->op_idn, TpMainOpMgr.GetMainOpList(), &info); 279 | 280 | if (info.is_lathe) 281 | { 282 | MY_TRACE(pfLog, "LATHE\n"); 283 | apt->SetModeTurn (); 284 | } 285 | else if (info.is_mill) 286 | { 287 | MY_TRACE(pfLog, "MILL\n"); 288 | apt->SetModeMill (); 289 | } 290 | 291 | CString message; 292 | CString caption = "STEP-NC Export"; 293 | message.Format ("Export all data with no more questions"); 294 | main_q = AfxMessageBox(message, MB_YESNO | MB_ICONINFORMATION); 295 | if (main_q == IDYES) 296 | { 297 | MY_TRACE(pfLog, "Exporting all data with no questions asked\n"); 298 | } 299 | 300 | memset(&mXform1, 0, sizeof(x_matrix)); 301 | memset(&mXform2, 0, sizeof(x_matrix)); 302 | 303 | memset(&ptStart, 0, 3 * sizeof(double)); 304 | memset(&vecSurfNorm, 0, 3 * sizeof(double)); 305 | 306 | // Rewind to the beginning of the NCI file 307 | nci_manager(opl->op_idn, NCIMGR_FSTART, &n, &fpos, &bResult); 308 | 309 | // for (INT_PTR OpCount = 3; OpCount < 4; ++OpCount) 310 | CStringArray old_names, new_names; 311 | for (INT_PTR OpCount = 0; OpCount < OpListSize; ++OpCount) 312 | { 313 | MY_TRACE (pfLog, "TOP OF THE LOOP OPCount = %d, OpListSize = %d\n", OpCount, OpListSize); 314 | opl = TpMainOpMgr.GetMainOpList()[OpCount]; 315 | char opDescription[80] = ""; 316 | op_make_description (opl, FALSE, opDescription, 80); 317 | 318 | // workplan hierarchy for the next operation 319 | GetOpParents(opl, &new_names); // Get the "parents" of this operation 320 | if (OpCount == 0) 321 | { 322 | INT_PTR NamesSize = new_names.GetSize (); 323 | MY_TRACE(pfLog, "Mastercam operation stack has height %d\n", NamesSize); 324 | old_names.Add (new_names[0]); 325 | // Edited on July 2 2012 to eliminate "Toolpath Group" nested workplan - was NameSize - 2 now NameSize - 3 326 | // ON Jan 15 2014 changed back to NameSize -2 to get workplan names for Sandvik process data 327 | for (INT_PTR i = NamesSize - 2; i >= 0; i--) 328 | { 329 | MY_TRACE(pfLog, "Making nested workplan called %s\n", new_names[i]); 330 | apt->NestWorkplan (new_names[i].AllocSysString()); 331 | } 332 | } 333 | else 334 | { 335 | INT_PTR i, j; 336 | INT_PTR NamesSize = new_names.GetSize (); 337 | INT_PTR OldNamesSize = old_names.GetSize (); 338 | MY_TRACE(pfLog, "Mastercam operation stack: new height %d old height %d\n", NamesSize, OldNamesSize); 339 | // stacks are in reverse order 340 | // Number changed on July 2 2012 to try to be consistent with above - NO TESTING - was -1 now - 2 341 | INT_PTR ii = NamesSize - 2; 342 | INT_PTR jj = OldNamesSize - 2; 343 | // start at end of each and look for first difference 344 | while (ii >= 0 && jj >= 0 && new_names[ii] == old_names[jj]) 345 | { 346 | ii--; jj--; 347 | } 348 | // pop off remainder of previous 349 | for (j = 0; j <= jj && j < OldNamesSize - 1; j++) 350 | { 351 | MY_TRACE(pfLog, "Ending workplan called %s\n", old_names[j]); 352 | apt->EndWorkplan (); 353 | } 354 | // ALSO CHANGED DO NOT FEEL GOOD ABOUT THIS ONE 355 | if (ii == NamesSize - 2) i--; 356 | // push new - last is machine group and is ignored 357 | for (i = ii; i >= 0; i--) 358 | { 359 | MY_TRACE(pfLog, "Making nested workplan called %s\n", new_names[i]); 360 | apt->NestWorkplan (new_names[i].AllocSysString()); 361 | } 362 | } 363 | old_names.RemoveAll(); 364 | INT_PTR NamesSize = new_names.GetSize (); 365 | for (INT_PTR i = 0; i < NamesSize; i++) 366 | { 367 | old_names.Add (new_names[i]); 368 | } 369 | 370 | if (main_q == IDNO) 371 | { 372 | CString message; 373 | CString caption = "STEP-NC Export"; 374 | message.Format ("Export Operation '%s' (%d of %d)", opDescription, OpCount + 1, OpListSize); 375 | long res = AfxMessageBox(message, MB_YESNO | MB_ICONINFORMATION); 376 | if (res == IDNO) 377 | { 378 | MY_TRACE(pfLog, "Skipping operation %d of %d at user request\n", OpCount + 1, OpListSize); 379 | apt->Workingstep(_com_util::ConvertStringToBSTR (opDescription)); 380 | char buf[100]; 381 | sprintf (buf, "mc%d.stpnc", OpCount); 382 | apt->ExternalOperation (_com_util::ConvertStringToBSTR (buf)); 383 | continue; 384 | } 385 | } 386 | 387 | // Create new workingstep (MCAM OP ==> STEP WS) 388 | MY_TRACE(pfLog, "Making new workingstep called %s with comment %s\n", opDescription, opl->comment); 389 | if (strlen (opDescription) > 0) 390 | apt->Workingstep(_com_util::ConvertStringToBSTR (opDescription)); 391 | else if (opl->opcode == TP_DRILL) 392 | apt->Workingstep("drill"); 393 | else 394 | apt->Workingstep("mill"); 395 | 396 | 397 | // Move to the beginning of the operation stream 398 | nci_manager(opl->op_idn, NCIMGR_RD_SOS, &n, &fpos, &bResult); 399 | 400 | // -------------------------------------------------------- 401 | // BEGIN reading operations in a loop from NCI data 402 | // -------------------------------------------------------- 403 | while (bResult) 404 | { 405 | 406 | // Read from the operation stream 407 | nci_manager(opl->op_idn, NCIMGR_RD, &n, &fpos, &bResult); 408 | MY_TRACE(pfLog, "HERE IS THE CURRENT GCODE: %d\n", n.gcode); 409 | if (!bResult || n.op_idn != opl->op_idn) 410 | { 411 | MY_TRACE(pfLog, "Breaking loop\n"); 412 | break; 413 | } 414 | 415 | cmnt = opl->comment; 416 | 417 | if (n.gcode == 20100) 418 | { 419 | ltcode = n.u.l20100.lToolNum; 420 | MY_TRACE(pfLog, "LATHE TOOL SLOT: %d Number %d\n", n.u.l20100.uSlot, ltcode); 421 | } 422 | 423 | // dlgProg.m_ctrlProgress.SetPos(opo.slot); 424 | 425 | // tp_get_all(n.op_idn, &op, &toolpaths, &ntoolpaths, &bIgnore); 426 | if (n.op_idn != nOldOpID) 427 | { 428 | CString msg; 429 | // msg.Format ("Exporting operation %d (%d:%d)) - %s.", n.op_idn, op.u.op.op_idn, op.u.op.slot, op.u.op.comment); 430 | // AfxMessageBox(msg); 431 | MY_TRACE (pfLog, "Exporting operation %d\n", n.op_idn); 432 | } 433 | 434 | /*******************************************************************/ 435 | /* Workingstep stuff */ 436 | /*******************************************************************/ 437 | // Make new workingstep 438 | if (n.op_idn != nOldOpID) 439 | { 440 | int fe_id = 0; 441 | if (ltcode == 0) 442 | { 443 | apt->LoadTool(opl->tl.tlno); // changed from slot to tlno for KTH then back for UTA - KTH almost definitely better 444 | MY_TRACE(pfLog, "Loading tool %d\n", opl->tl.tlno); 445 | bFirstMove = TRUE; 446 | } 447 | else // assume lathe tool 448 | { 449 | apt->LoadTool(ltcode); 450 | MY_TRACE(pfLog, "Lathe Loading tool %d\n", ltcode); 451 | bFirstMove = TRUE; 452 | } 453 | 454 | // -------------------------------------------------------- 455 | // BEGIN feature extraction 456 | // -------------------------------------------------------- 457 | 458 | // Now write feature information 459 | MY_TRACE(pfLog, "New op id = %d old op id = %d\n", n.op_idn, nOldOpID); 460 | if (n.op_idn != nOldOpID) 461 | { 462 | // Extract chain 463 | cmi.op_idn = n.op_idn; 464 | cmi.mode = CHNMGR_GET; 465 | cmi.bnd_n_start = 1; 466 | cmi.bnd_n_end = 2; 467 | cmi.chns = NULL; 468 | nChains = 0; 469 | 470 | chain_manager(&cmi, -1, &bChainResult); 471 | 472 | if (!bChainResult) 473 | { 474 | chain_manager(&cmi, 0, &bChainResult); 475 | nChains = number_of_chains(cmi.chns); 476 | } 477 | 478 | if (opl->opcode == TP_POCKET && cc3) 479 | { 480 | 481 | // Call after calling "chain_manager" with "CHNMGR_GET" 482 | // This call yields a linked list of "pock_bound", 483 | // which (I believe) parallels the list of chains in "cmi.chns" 484 | // Unfortunately it does not set the "p_b" member in each CHAIN. 485 | // The list contains all pocket bounds, but no island/pocket flags yet. 486 | // chains_to_pock_bounds(cmi.chns, FALSE, FALSE, FALSE, 1.0, &pPB); 487 | 488 | // To find out which is apocket and which is an island -- 489 | // sort_pock_bounds(NULL, FALSE, FALSE, 1.0, &pPB, &nPock); 490 | MY_TRACE(pfLog, "Number of Pockets %d pb = %x\n", nPock, pPB); 491 | 492 | nPock = 1; 493 | if (bChainResult && (nPock == 1 || nPock == 0)) 494 | { 495 | MakeGeneralPocket(*opl, cmi.chns, apt->GetCurrentWorkingstep(), nChains); 496 | } 497 | else if (bChainResult) 498 | { 499 | // nFeatureID = MakeCompoundPocket (op.u.op, cmi.chns, apt->GetCurrentWorkingstep(), nPock, pPB); 500 | } 501 | } 502 | else if (opl->opcode == TP_CONTOUR && cc3) 503 | { 504 | if (bChainResult) 505 | { 506 | MakeGeneralOutsideProfile(*opl, cmi.chns, apt->GetCurrentWorkingstep()); 507 | } 508 | } 509 | else if (opl->opcode == TP_FACE && cc3) 510 | { 511 | double dLength, dWidth; 512 | p_3d ptCenter; 513 | 514 | if (bChainResult) // Chain boundary -- use bounding box 515 | { 516 | GetChainBBox(cmi.chns, opl->cpln.view_n, dLength, dWidth, ptCenter); 517 | } 518 | else if (group != NULL) // Stock boundary (ASSUMED the face is on the top of the stock) 519 | { 520 | MY_TRACE(pfLog, "WARNING: Making planar face using stock dimensions\n"); 521 | dLength = group->ogi.pg3.x; 522 | dWidth = group->ogi.pg3.y; 523 | 524 | ptCenter[0] = group->ogi.pg3.cpt[X]; 525 | ptCenter[1] = group->ogi.pg3.cpt[Y]; 526 | ptCenter[2] = group->ogi.pg3.cpt[Z]; 527 | } 528 | else 529 | { 530 | dLength = dWidth = ptCenter[0]= ptCenter[1] = ptCenter[2] = 0; 531 | } 532 | 533 | MakePlanarFace(*opl, ptCenter, dLength, dWidth, apt->GetCurrentWorkingstep()); 534 | if (nChains > 1) 535 | { 536 | // ChainsToBosses(/*nFeatureID,*/ cmi.chns->next); // starting at the second chain in the CMI 537 | } 538 | } 539 | } 540 | } 541 | 542 | // -------------------------------------------------------- 543 | // END feature extraction 544 | // -------------------------------------------------------- 545 | 546 | #ifdef MY_DEBUG 547 | fflush(pfLog); 548 | #endif 549 | // should not be doing the below every time 550 | /* if (op.u.op.tl.coolant == 1) { 551 | apt->CoolantOn(); 552 | } 553 | else { 554 | apt->CoolantOff(); 555 | } 556 | 557 | if (tool_direction[op.u.op.tl.slot]) 558 | apt->SpindleSpeed(op.u.op.tl.rpm); 559 | else 560 | apt->SpindleSpeed(-op.u.op.tl.rpm);*/ 561 | 562 | bNewOpCheckCComp = TRUE; 563 | // add operation to instantiate drill cycle 564 | // this used to key off gcode == 0 which lead to issues 565 | if (opl->opcode == TP_DRILL && cc1 && n.gcode == 81) 566 | { 567 | MakeRoundHole(*opl, n.u.m0.ep1, apt->GetCurrentWorkingstep()); 568 | 569 | // ptStart is probably redundant and currently wrong (not used) 570 | // When switched to code = 81 was found to be at bottom 571 | memcpy(ptStart, n.u.m0.ep1, 3 * sizeof(double)); 572 | memcpy(ptEnd, n.u.m0.ep1, 3 * sizeof(double)); 573 | memcpy(ptBot, ptEnd, 3 * sizeof(double)); 574 | if (opl->cmn.clearance_on) 575 | ptEnd[Z] = ptEnd[Z] - opl->cmn.clearance_pln; 576 | else if (opl->cmn.retract_on) // seems to be same as clearance_plane and not the value called retract in the UI 577 | { 578 | if (opl->cmn.retract_inc) 579 | ptEnd[Z] = ptEnd[Z] - opl->cmn.retract_pln; 580 | else 581 | ptEnd[Z] = ptEnd[Z]; 582 | } 583 | 584 | memcpy(ptBot, ptEnd, 3 * sizeof(double)); 585 | double depth = fabs(opl->cmn.top_stock - opl->cmn.depth); 586 | MY_TRACE(pfLog, "Drilling Depth = %lf, break through = %lf\n", depth, opl->u.prm_drl.brk_thru); 587 | MY_TRACE(pfLog, "z = %lf Clearance = %lf, Retract = %lf feed_pln = %f\n", ptEnd[Z], opl->cmn.clearance_pln, 588 | opl->cmn.retract_pln, opl->cmn.feed_pln); 589 | // depth = depth + op.u.op.u.prm_drl.brk_thru; // KTH magnus says ignore 590 | if (opl->cmn.depth_inc) 591 | ptBot[Z] = ptBot[Z] - depth; 592 | else 593 | ptBot[Z] = opl->cmn.depth; 594 | 595 | // As per magnus feed/speed must change at the feed plane point 596 | if (opl->cmn.feed_inc) 597 | ptEnd[Z] = ptEnd[Z] + opl->cmn.feed_pln; // this is the value called retract 598 | else 599 | ptEnd[Z] = opl->cmn.feed_pln; // this is the value called retract 600 | 601 | // remember values for other points in pattern 602 | hole_z1 = ptStart[Z]; 603 | hole_z2 = ptEnd[Z]; 604 | hole_z3 = ptBot[Z]; 605 | if (tool_direction[opl->tl.tlno]) 606 | hole_speed = opl->tl.rpm; 607 | else 608 | hole_speed = -opl->tl.rpm; 609 | hole_feed = opl->tl.feed; 610 | hole_plunge = opl->tl.plunge; 611 | hole_retract = opl->tl.retract; 612 | 613 | // calculate the orientation 614 | if (!use_tp_orientation) 615 | { 616 | xform_pt(ptStart, &mXform1); 617 | xform_pt(ptEnd, &mXform1); 618 | xform_pt(ptBot, &mXform1); 619 | 620 | xform_pt(ptStart, &mXform2); 621 | xform_pt(ptEnd, &mXform2); 622 | xform_pt(ptBot, &mXform2); 623 | } 624 | 625 | if (nOldRPM != hole_speed) 626 | { 627 | apt->SpindleSpeed (hole_speed); // as per KTH 628 | nOldRPM = hole_speed; 629 | } 630 | 631 | MY_TRACE(pfLog, "Retract point at (%lf, %lf, %lf)\n", ptEnd[X], ptEnd[Y], ptEnd[Z]); 632 | // should already be here for first point 633 | // apt->GoToXYZ(cmnt, ptEnd[X], ptEnd[Y], ptEnd[Z]); 634 | 635 | apt->Feedrate(hole_feed); 636 | bInRapidMode = FALSE; 637 | apt->GoToXYZ(_com_util::ConvertStringToBSTR (cmnt), ptBot[X], ptBot[Y], ptBot[Z]); 638 | MY_TRACE(pfLog, "Bottom point at (%lf, %lf, %lf)\n", ptBot[X], ptBot[Y], ptBot[Z]); 639 | 640 | apt->Feedrate(hole_retract); 641 | apt->GoToXYZ(_com_util::ConvertStringToBSTR (cmnt), ptEnd[X], ptEnd[Y], ptEnd[Z]); 642 | MY_TRACE(pfLog, "Retract point at (%lf, %lf, %lf)\n", ptEnd[X], ptEnd[Y], ptEnd[Z]); 643 | 644 | MY_TRACE(pfLog, "Depth = %f, spindle = %f feed = %f, plunge = %f, retract = %f\n", 645 | depth, hole_speed, hole_feed, hole_plunge, hole_retract); 646 | 647 | } 648 | else if (opl->opcode == TP_CIRCMILL && cc3 && n.gcode == 0) 649 | { 650 | // this code worked much better here than up above with other features 651 | // consider moving them all to this logic PLEASE 652 | p_3d ptCenter; 653 | double dDiameter = opl->u.circmill.diameter; 654 | memcpy(ptCenter, n.u.m0.ep1, 3 * sizeof(double)); 655 | 656 | double dDepth; 657 | if (opl->cmn.depth_inc) 658 | { 659 | dDepth = fabs (opl->cmn.depth); 660 | ptCenter[Z] = opl->cmn.top_stock -dDepth; 661 | } 662 | else 663 | { 664 | dDepth = fabs(opl->cmn.top_stock - opl->cmn.depth); 665 | ptCenter[Z] = opl->cmn.depth; 666 | } 667 | 668 | MY_TRACE(pfLog, "Circular milling found diameter = %f, depth = %f\n", dDiameter, dDepth); 669 | MY_TRACE(pfLog, "Center = (%f, %f, %f)\n", ptCenter[0], ptCenter[1], ptCenter[2]); 670 | MakeRoundPocket (*opl, ptCenter, dDiameter, dDepth, apt->GetCurrentWorkingstep()); 671 | } 672 | 673 | 674 | // Data now gathered for new operation 675 | if (n.op_idn != nOldOpID && n.gcode < 1000) 676 | nOldOpID = n.op_idn; 677 | 678 | // -------------------------------------------------------- 679 | // BEGIN toolpath extraction 680 | // -------------------------------------------------------- 681 | 682 | if (n.gcode == 1027) 683 | { 684 | MY_TRACE(pfLog, "Origin found (%f, %f, %f)\n", n.u.m1027.wcs_origin[0], n.u.m1027.wcs_origin[1], n.u.m1027.wcs_origin[2]); 685 | MY_TRACE(pfLog, "X found (%f, %f, %f)\n", n.u.m1027.wcs_m[0][0], n.u.m1027.wcs_m[0][1], n.u.m1027.wcs_m[0][2]); 686 | MY_TRACE(pfLog, "Y found (%f, %f, %f)\n", n.u.m1027.wcs_m[1][0], n.u.m1027.wcs_m[1][1], n.u.m1027.wcs_m[1][2]); 687 | MY_TRACE(pfLog, "Z found (%f, %f, %f)\n", n.u.m1027.wcs_m[2][0], n.u.m1027.wcs_m[2][1], n.u.m1027.wcs_m[2][2]); 688 | } 689 | 690 | // Now act based on the operaton type (G-code) 691 | if (n.gcode == 0 && cc1) // rapid 692 | { 693 | 694 | if (nOldRPM != opl->tl.rpm) // as per KTH need to set spindle speed even for rapid 695 | { 696 | if (tool_direction[opl->tl.tlno]) 697 | apt->SpindleSpeed(opl->tl.rpm); 698 | else 699 | apt->SpindleSpeed(-opl->tl.rpm); 700 | nOldRPM = opl->tl.rpm; 701 | } 702 | 703 | if (n.u.m0.ccomp > 0) 704 | { 705 | bNewOpCheckCComp = FALSE; 706 | 707 | if (n.u.m0.ccomp != 0 && cc1) 708 | { 709 | if (n.u.m0.ccomp == 41) 710 | { 711 | MY_TRACE(pfLog, "Left Cutter Contact\n"); 712 | apt->Left(); 713 | } 714 | else if (n.u.m0.ccomp == 42) 715 | { 716 | MY_TRACE(pfLog, "Right Cutter Contact\n"); 717 | apt->Right(); 718 | } 719 | else if (n.u.m0.ccomp == COMP_CANCEL) 720 | { 721 | MY_TRACE(pfLog, "Cutter Contact Off\n"); 722 | apt->CenterOn(); 723 | } 724 | else 725 | MY_TRACE(pfLog, "Cutter Contact type unknown\n"); 726 | 727 | MY_TRACE(pfLog, "Cutter compensation contact G%d (in control)\n", n.u.m0.ccomp); 728 | } 729 | else if (cc1) 730 | { 731 | apt->CenterOn(); 732 | MY_TRACE(pfLog, "Cutter compensation center (in computer)\n"); 733 | } 734 | 735 | nPrevCComp = n.u.m0.ccomp; 736 | } 737 | 738 | if (opl->opcode == TP_POINT) // Assume it's probing (NIST used this type of op) 739 | { 740 | MY_TRACE(pfLog, "Warning TP Point found and ignored\n"); 741 | } 742 | else // used to guard this with code to stop if drilling 743 | { 744 | 745 | if (!bInRapidMode) 746 | { 747 | apt->MultaxOff(); 748 | 749 | MY_TRACE(pfLog, "OP %d, Rapid, multax_off, oldcode = %d, newcode = %d\n", n.op_idn, nOldGcode, n.gcode); 750 | 751 | apt->Rapid(); 752 | bInRapidMode = TRUE; 753 | } 754 | // Geometry 755 | // calculate the orientation of use the toolpath orientation defined in STEP-NC? 756 | if (!use_tp_orientation) 757 | { 758 | xform_pt(n.u.m0.ep1, &mXform1); 759 | xform_pt(n.u.m0.ep1, &mXform2); 760 | } 761 | 762 | if (VEq(vecDir, vecOldDir)) 763 | { 764 | if (bFirstMove) 765 | { 766 | apt->FirstPathStartPoint (n.u.m0.ep1[0], n.u.m0.ep1[1], n.u.m0.ep1[2]); 767 | bFirstMove = FALSE; 768 | } 769 | // need to generate a G0 code to the first point 770 | apt->GoToXYZ(_com_util::ConvertStringToBSTR (cmnt), n.u.m0.ep1[0], n.u.m0.ep1[1], n.u.m0.ep1[2]); 771 | } 772 | else 773 | { 774 | apt->MultaxOn(); 775 | if (bFirstMove) 776 | { 777 | apt->FirstPathStartPoint (n.u.m0.ep1[0], n.u.m0.ep1[1], n.u.m0.ep1[2]); 778 | apt->FirstPathStartAxis (vecDir[0], vecDir[1], vecDir[2]); 779 | bFirstMove = FALSE; 780 | } 781 | apt->GoToXYZ_IJK(_com_util::ConvertStringToBSTR (cmnt), n.u.m0.ep1[0], n.u.m0.ep1[1], n.u.m0.ep1[2], 782 | vecDir[0], vecDir[1], vecDir[2]); 783 | apt->MultaxOff(); 784 | // memcpy(vecOldDir, vecDir, 3 * sizeof(double)); 785 | } 786 | 787 | MY_TRACE(pfLog, "S%d, F%f\n", opl->tl.rpm, n.u.m0.feed); 788 | MY_TRACE(pfLog, "G0 X%f Y%f Z%f I%f J%f K%f\n", n.u.m0.ep1[0], n.u.m0.ep1[1], n.u.m0.ep1[2], vecDir[0], vecDir[1], vecDir[2]); 789 | dOldFeed = fabs(n.u.m0.feed); 790 | } 791 | 792 | memcpy(ptStart, n.u.m0.ep1, 3 * sizeof(double)); 793 | } 794 | else if (n.gcode == 1 && cc1) // line feed 795 | { 796 | bInRapidMode = FALSE; 797 | 798 | if (n.gcode != nOldGcode) 799 | { 800 | MY_TRACE(pfLog, "Old code %d, new code %d multax_off\n", nOldGcode, n.gcode); 801 | apt->MultaxOff(); 802 | } 803 | 804 | if (nOldRPM != opl->tl.rpm) 805 | { 806 | if (tool_direction[opl->tl.tlno]) 807 | apt->SpindleSpeed(opl->tl.rpm); 808 | else 809 | apt->SpindleSpeed(-opl->tl.rpm); 810 | nOldRPM = opl->tl.rpm; 811 | } 812 | 813 | if (dOldFeed != n.u.m1.feed) 814 | { 815 | if (opl->tl.use_css) 816 | { 817 | apt->FeedrateCSS (fabs (n.u.m1.feed), opl->tl.max_ss); 818 | MY_TRACE(pfLog, "apt - css feed %f max %d\n", fabs(n.u.m1.feed), opl->tl.max_ss); 819 | } 820 | else 821 | { 822 | apt->Feedrate(fabs (n.u.m1.feed)); 823 | MY_TRACE(pfLog, "apt - feed %f\n", fabs(n.u.m1.feed)); 824 | } 825 | dOldFeed = n.u.m1.feed; 826 | } 827 | 828 | // Cutter compensation (0 => control) 829 | if (n.u.m1.ccomp > 0) 830 | { 831 | bNewOpCheckCComp = FALSE; 832 | 833 | if (n.u.m1.ccomp != 0) 834 | { 835 | if (n.u.m1.ccomp == 41) 836 | { 837 | MY_TRACE(pfLog, "Cutter Contact Left\n"); 838 | apt->Left(); 839 | } 840 | else if (n.u.m1.ccomp == 42) 841 | { 842 | MY_TRACE(pfLog, "Cutter Contact Right\n"); 843 | apt->Right(); 844 | } 845 | else if (n.u.m1.ccomp == COMP_CANCEL) 846 | { 847 | MY_TRACE(pfLog, "Cutter Contact Off\n"); 848 | apt->CenterOn(); 849 | } 850 | else 851 | MY_TRACE(pfLog, "Cutter Contact unknown\n"); 852 | 853 | MY_TRACE(pfLog, "Cutter compensation contact G%d (in control)\n", n.u.m1.ccomp); 854 | } 855 | else 856 | { 857 | apt->CenterOn(); 858 | MY_TRACE(pfLog, "Cutter compensation center (in computer)\n"); 859 | } 860 | 861 | nPrevCComp = n.u.m1.ccomp; 862 | } 863 | 864 | // Geometry 865 | // calculate the orientation of use the toolpath orientation defined in STEP-NC? 866 | if (!use_tp_orientation) 867 | { 868 | xform_pt(n.u.m1.ep1, &mXform1); 869 | xform_pt(n.u.m1.ep1, &mXform2); 870 | } 871 | 872 | if (VEq(vecDir, vecOldDir)) 873 | { 874 | if (bFirstMove) 875 | { 876 | apt->FirstPathStartPoint (n.u.m0.ep1[0], n.u.m0.ep1[1], n.u.m0.ep1[2]); 877 | bFirstMove = FALSE; 878 | } 879 | apt->GoToXYZ(_com_util::ConvertStringToBSTR (cmnt), n.u.m1.ep1[0], n.u.m1.ep1[1], n.u.m1.ep1[2]); 880 | } 881 | else 882 | { 883 | apt->MultaxOn(); 884 | if (bFirstMove) 885 | { 886 | apt->FirstPathStartPoint (n.u.m0.ep1[0], n.u.m0.ep1[1], n.u.m0.ep1[2]); 887 | apt->FirstPathStartAxis (vecDir[0], vecDir[1], vecDir[2]); 888 | bFirstMove = FALSE; 889 | } 890 | 891 | apt->GoToXYZ_IJK(_com_util::ConvertStringToBSTR (cmnt), n.u.m1.ep1[0], n.u.m1.ep1[1], n.u.m1.ep1[2], 892 | vecDir[0], vecDir[1], vecDir[2]); 893 | apt->MultaxOff(); 894 | // memcpy(vecOldDir, vecDir, 3 * sizeof(double)); 895 | } 896 | 897 | MY_TRACE(pfLog, "Comp = %d\n", n.u.m1.ccomp); 898 | MY_TRACE(pfLog, "S%d, F%f\n", opl->tl.rpm, n.u.m1.feed); 899 | MY_TRACE(pfLog, "G1 X%f Y%f Z%f I%f J%f K%f\n", n.u.m1.ep1[0], n.u.m1.ep1[1], n.u.m1.ep1[2], vecDir[0], vecDir[1], vecDir[2]); 900 | memcpy(ptStart, n.u.m1.ep1, 3 * sizeof(double)); 901 | } 902 | else if ((n.gcode == 2 || n.gcode == 3) && cc1) // CW/CCW arc 903 | { 904 | bInRapidMode = FALSE; 905 | 906 | if (n.gcode != nOldGcode) 907 | { 908 | MY_TRACE(pfLog, "Old code %d, new code %d multax_off\n", nOldGcode, n.gcode); 909 | apt->MultaxOff(); 910 | } 911 | 912 | if (nOldRPM != opl->tl.rpm) 913 | { 914 | if (tool_direction[opl->tl.tlno]) 915 | apt->SpindleSpeed(opl->tl.rpm); 916 | else 917 | apt->SpindleSpeed(-opl->tl.rpm); 918 | nOldRPM = opl->tl.rpm; 919 | } 920 | 921 | if (dOldFeed != n.u.m2.feed) 922 | { 923 | if (opl->tl.use_css) 924 | { 925 | apt->FeedrateCSS (fabs (n.u.m2.feed), opl->tl.max_ss); 926 | MY_TRACE(pfLog, "apt - css feed %f max %d\n", fabs(n.u.m2.feed), opl->tl.max_ss); 927 | } 928 | else 929 | { 930 | apt->Feedrate(fabs (n.u.m2.feed)); 931 | MY_TRACE(pfLog, "apt - feed %f\n", fabs(n.u.m2.feed)); 932 | } 933 | dOldFeed = n.u.m2.feed; 934 | } 935 | 936 | // Cutter compensation (change only if it's new operation or "CANCEL" 937 | if (n.u.m2.ccomp > 0) //bNewOpCheckCComp || (n.u.m2.ccomp == COMP_CANCEL)) 938 | { 939 | bNewOpCheckCComp = FALSE; 940 | 941 | if (n.u.m2.ccomp != COMP_OFF) 942 | { 943 | if (n.u.m2.ccomp == COMP_LEFT) 944 | { 945 | MY_TRACE(pfLog, "Cutter contact left\n"); 946 | apt->Left(); 947 | } 948 | else if (n.u.m2.ccomp == COMP_RIGHT) 949 | { 950 | MY_TRACE(pfLog, "Cutter contact right\n"); 951 | apt->Right(); 952 | } 953 | else if (n.u.m2.ccomp == COMP_CANCEL) 954 | { 955 | MY_TRACE(pfLog, "Cutter contact off\n"); 956 | apt->CenterOn(); 957 | } 958 | else 959 | MY_TRACE(pfLog, "Cutter Contact unknown\n"); 960 | 961 | MY_TRACE(pfLog, "Cutter compensation contact G%d (in control)\n", n.u.m2.ccomp); 962 | } 963 | else 964 | { 965 | apt->CenterOn(); 966 | MY_TRACE(pfLog, "Cutter compensation center (in computer)\n"); 967 | } 968 | 969 | nPrevCComp = n.u.m2.ccomp; 970 | } 971 | 972 | // Geometry 973 | // calculate the orientation of use the toolpath orientation defined in STEP-NC? 974 | if (!use_tp_orientation) 975 | { 976 | xform_pt(n.u.m2.ep1, &mXform1); 977 | xform_pt(n.u.m2.ep1, &mXform2); 978 | xform_pt(n.u.m2.cpt, &mXform1); 979 | xform_pt(n.u.m2.cpt, &mXform2); 980 | } 981 | 982 | dRad = sqrt(pow(n.u.m2.ep1[0] - n.u.m2.cpt[0], 2) + 983 | pow(n.u.m2.ep1[1] - n.u.m2.cpt[1], 2) + 984 | pow(n.u.m2.ep1[2] - n.u.m2.cpt[2], 2)); 985 | 986 | MY_TRACE(pfLog, "Comp = %d Plane = %d circle = %d position = %d\n", n.u.m2.ccomp, n.u.m2.pln, n.u.m2.circle, n.u.m2.position); 987 | MY_TRACE(pfLog, "S%d, F%f\n", opl->tl.rpm, n.u.m2.feed); 988 | MY_TRACE(pfLog, "%s X%f Y%f Z%f CENTER(X%f Y%f Z%f) R%f\n", n.gcode == 2 ? "G2" : "G3", n.u.m2.ep1[0], n.u.m2.ep1[1], n.u.m2.ep1[2], n.u.m2.cpt[0], n.u.m2.cpt[1], n.u.m2.cpt[2], dRad); 989 | 990 | // if (n.u.m2.circle) 991 | // AfxMessageBox("Mastercam FULL CIRCLE found", MB_YESNO | MB_ICONINFORMATION); 992 | 993 | if (n.u.m2.pln == 0) 994 | { 995 | int ccw; 996 | // if arc is in plane then simple calculation 997 | if (use_tp_orientation) 998 | { 999 | if (n.gcode == 3) 1000 | ccw = 1; 1001 | else 1002 | ccw = 0; 1003 | } 1004 | else // else need to worry about current normal 1005 | { 1006 | if (n.gcode == 3 && vecDir[2] == 1) 1007 | ccw = 1; 1008 | else if (n.gcode == 2 && vecDir[2] == -1) 1009 | ccw = 1; 1010 | else 1011 | ccw = 0; 1012 | } 1013 | 1014 | apt->ArcXYPlane(_com_util::ConvertStringToBSTR (cmnt), n.u.m2.ep1[0], n.u.m2.ep1[1], n.u.m2.ep1[2], 1015 | n.u.m2.cpt[0], n.u.m2.cpt[1], n.u.m2.cpt[2], 1016 | dRad, ccw); 1017 | MY_TRACE(pfLog, "(XY) CENTER AXIS \n"); 1018 | } 1019 | else if (n.u.m2.pln == 1) 1020 | { 1021 | int ccw; 1022 | if (use_tp_orientation) 1023 | { 1024 | if (n.gcode == 3) 1025 | ccw = 1; 1026 | else 1027 | ccw = 0; 1028 | } 1029 | else 1030 | { 1031 | if (n.gcode == 3 && vecDir[0] == 1) 1032 | ccw = 1; 1033 | else if (n.gcode == 2 && vecDir[0] == -1) 1034 | ccw = 1; 1035 | else 1036 | ccw = 0; 1037 | } 1038 | 1039 | apt->ArcYZPlane(_com_util::ConvertStringToBSTR (cmnt), n.u.m2.cpt[2], n.u.m2.ep1[0], n.u.m2.ep1[1], 1040 | n.u.m2.cpt[2], n.u.m2.cpt[0], n.u.m2.cpt[1], 1041 | dRad, ccw); 1042 | /* apt->ArcYZPlane(cmnt, n.u.m2.ep1[0], n.u.m2.ep1[1], n.u.m2.ep1[2], 1043 | n.u.m2.cpt[0], n.u.m2.cpt[1], n.u.m2.cpt[2], 1044 | dRad, n.gcode == 3);*/ 1045 | MY_TRACE(pfLog, "(YZ) CENTER AXIS\n"); 1046 | } 1047 | else if (n.u.m2.pln == 2) 1048 | { 1049 | int ccw; 1050 | if (use_tp_orientation) 1051 | { 1052 | if (n.gcode == 3) 1053 | ccw = 1; 1054 | else 1055 | ccw = 0; 1056 | } 1057 | else 1058 | { 1059 | if (n.gcode == 3 && vecDir[1] == 1) 1060 | ccw = 1; 1061 | else if (n.gcode == 2 && vecDir[1] == -1) 1062 | ccw = 1; 1063 | else 1064 | ccw = 0; 1065 | } 1066 | 1067 | apt->ArcZXPlane(_com_util::ConvertStringToBSTR (cmnt), n.u.m2.ep1[0], -n.u.m2.cpt[2], n.u.m2.ep1[1], 1068 | n.u.m2.cpt[0], -n.u.m2.cpt[2], n.u.m2.cpt[1], 1069 | dRad, ccw); 1070 | /* apt->ArcZXPlane(cmnt, n.u.m2.ep1[0], n.u.m2.ep1[1], n.u.m2.ep1[2], 1071 | n.u.m2.cpt[0], n.u.m2.cpt[1], n.u.m2.cpt[2], 1072 | dRad, n.gcode == 3);*/ 1073 | MY_TRACE(pfLog, "(ZX) CENTER AXIS\n"); 1074 | } 1075 | else 1076 | { 1077 | CString msg; 1078 | msg.Format ("Unknown arc plane value = %d", n.u.m2.pln); 1079 | AfxMessageBox(msg, MB_YESNO | MB_ICONINFORMATION);// 1080 | } 1081 | 1082 | dOldFeed = n.u.m2.feed; 1083 | } 1084 | else if (n.gcode == 11 && cc1) // 5-axis move 1085 | { 1086 | bInRapidMode = FALSE; 1087 | 1088 | if (nOldGcode != n.gcode) 1089 | { 1090 | MY_TRACE(pfLog, "Old code %d, new code %d\n", nOldGcode, n.gcode); 1091 | apt->MultaxOn(); 1092 | } 1093 | 1094 | if (nOldRPM != opl->tl.rpm) 1095 | { 1096 | if (tool_direction[opl->tl.tlno]) 1097 | apt->SpindleSpeed(opl->tl.rpm); 1098 | else 1099 | apt->SpindleSpeed(-opl->tl.rpm); 1100 | nOldRPM = opl->tl.rpm; 1101 | } 1102 | 1103 | if (dOldFeed != fabs(n.u.m11.feed)) 1104 | { 1105 | if (opl->tl.use_css) 1106 | { 1107 | apt->FeedrateCSS (fabs (n.u.m11.feed), opl->tl.max_ss); 1108 | MY_TRACE(pfLog, "apt - css feed %f max %d\n", fabs(n.u.m11.feed), opl->tl.max_ss); 1109 | } 1110 | else 1111 | { 1112 | apt->Feedrate(fabs (n.u.m11.feed)); 1113 | MY_TRACE(pfLog, "apt - feed %f\n", fabs(n.u.m11.feed)); 1114 | } 1115 | dOldFeed = fabs(n.u.m11.feed); 1116 | } 1117 | 1118 | // Geometry 1119 | apt->GoToXYZ_IJK(_com_util::ConvertStringToBSTR (cmnt), n.u.m11.ep1[0], n.u.m11.ep1[1], n.u.m11.ep1[2], 1120 | n.u.m11.snvec[0], n.u.m11.snvec[1], n.u.m11.snvec[2]); 1121 | 1122 | MY_TRACE(pfLog, "S%d, F%f\n", opl->tl.rpm, n.u.m11.feed); 1123 | MY_TRACE(pfLog, "G11 X%f Y%f Z%f I%f J%f K%f\n", n.u.m11.ep1[0], n.u.m11.ep1[1], n.u.m11.ep1[2],n.u.m11.snvec[0], n.u.m11.snvec[1], n.u.m11.snvec[2]); 1124 | 1125 | dOldFeed = fabs(n.u.m11.feed); 1126 | } 1127 | else if ((n.gcode == 81 || n.gcode == 82 || n.gcode == 83) && cc3) // Drilling canned cycle 1128 | { 1129 | // implement as TP_DRILL operation 1130 | MY_TRACE(pfLog, "G%d not implemented S%d, F%f\n", n.gcode, opl->tl.rpm, n.u.m11.feed); 1131 | ;// Not implemented yet 1132 | } 1133 | else if (n.gcode == 100) // Drilling position 1134 | { 1135 | if (cc1) // Add goto code for Drill to bottom 1136 | { 1137 | ptStart[X] = n.u.m100.x; ptStart[Y] = n.u.m100.y; ptStart[Z] = hole_z1; 1138 | ptEnd[X] = n.u.m100.x; ptEnd[Y] = n.u.m100.y; ptEnd[Z] = hole_z2; 1139 | ptBot[X] = n.u.m100.x; ptBot[Y] = n.u.m100.y; ptBot[Z] = hole_z3; 1140 | 1141 | // calculate the orientation of use the toolpath orientation defined in STEP-NC? 1142 | if (!use_tp_orientation) 1143 | { 1144 | xform_pt(ptStart, &mXform1); 1145 | xform_pt(ptEnd, &mXform1); 1146 | xform_pt(ptBot, &mXform1); 1147 | 1148 | xform_pt(ptStart, &mXform2); 1149 | xform_pt(ptEnd, &mXform2); 1150 | xform_pt(ptBot, &mXform2); 1151 | } 1152 | 1153 | if (hole_speed != nOldRPM) 1154 | { 1155 | apt->SpindleSpeed (hole_speed); 1156 | nOldRPM = hole_speed; 1157 | } 1158 | 1159 | if (!bInRapidMode) 1160 | { 1161 | apt->Rapid(); 1162 | bInRapidMode = TRUE; 1163 | } 1164 | 1165 | MY_TRACE(pfLog, "GOTO Drilling Next point at (%lf, %lf, %lf)\n", ptEnd[X], ptEnd[Y], ptEnd[Z]); 1166 | 1167 | // need this for second and subsequent but not first 1168 | apt->GoToXYZ(_com_util::ConvertStringToBSTR (cmnt), ptEnd[X], ptEnd[Y], ptEnd[Z]); 1169 | 1170 | apt->Feedrate(hole_feed); 1171 | apt->GoToXYZ(_com_util::ConvertStringToBSTR (cmnt), ptBot[X], ptBot[Y], ptBot[Z]); 1172 | MY_TRACE(pfLog, "Bot point at (%lf, %lf, %lf)\n", ptBot[X], ptBot[Y], ptBot[Z]); 1173 | 1174 | apt->Feedrate(hole_retract); 1175 | apt->GoToXYZ(_com_util::ConvertStringToBSTR (cmnt), ptEnd[X], ptEnd[Y], ptEnd[Z]); 1176 | 1177 | bInRapidMode = FALSE; 1178 | MY_TRACE(pfLog, "spindle = %f feed = %f, plunge = %f, retract = %f\n", 1179 | hole_speed, hole_feed, hole_plunge, hole_retract); 1180 | } 1181 | if (cc3) 1182 | { 1183 | if (pattern || !pattern) 1184 | { 1185 | MY_TRACE(pfLog, "New pattern drilling point at (%lf, %lf, %lf)\n", ptBot[X], ptBot[Y], ptBot[Z]); 1186 | process->DrillPointAdd (apt->GetCurrentWorkingstep(), ptBot[X], ptBot[Y], ptBot[Z]); 1187 | MY_TRACE(pfLog, "New pattern drilling Made it\n"); 1188 | } 1189 | else 1190 | { 1191 | MY_TRACE(pfLog, "New drilling Workingstep at (%lf, %lf, %lf)\n", ptBot[X], ptBot[Y], ptBot[Z]); 1192 | process->DrillWorkingstepAdd (apt->GetCurrentWorkingstep(), ptBot[X], ptBot[Y], ptBot[Z]); 1193 | MY_TRACE(pfLog, "New drilling Made it\n"); 1194 | } 1195 | } 1196 | 1197 | } 1198 | else if (n.gcode == 1014) // Toolplane change (axis rotation) 1199 | { 1200 | memcpy(mXform2.r, n.u.m1014.tpln_33, 9 * sizeof(double)); 1201 | memcpy(vecDir, n.u.m1014.tpln_33[2], 3 * sizeof(double)); 1202 | memcpy(vecRef, n.u.m1014.tpln_33[0], 3 * sizeof(double)); 1203 | MY_TRACE(pfLog, "tool plane (%lf, %lf, %lf) ref (%lf, %lf, %lf)\n", vecDir[X], vecDir[Y], vecDir[Z], 1204 | vecRef[X], vecRef[Y], vecRef[Z]); 1205 | // Define orientation in STEP-NC 1206 | if (use_tp_orientation) 1207 | { 1208 | MY_TRACE(pfLog, "setting ws_toolpath_orientation to (0, 0, 0) dir (%lf, %lf, %lf) ref (%lf, %lf, %lf)\n", vecDir[X], vecDir[Y], vecDir[Z], 1209 | vecRef[X], vecRef[Y], vecRef[Z]); 1210 | apt->WorkingstepToolpathOrientation (0, 0, 0, vecDir[X], vecDir[Y], vecDir[Z], vecRef[X], vecRef[Y], vecRef[Z]); 1211 | 1212 | // tool plane change is not a reason to go to 5 axis machining 1213 | memcpy(vecOldDir, vecDir, 3 * sizeof(double)); 1214 | } 1215 | else 1216 | bAxisChgd = TRUE; 1217 | 1218 | } 1219 | else if (n.gcode == 1027) // WCS change (axis rotation) 1220 | { 1221 | memcpy(mXform1.t, n.u.m1027.wcs_origin, 3 * sizeof(double)); 1222 | mXform1.r[0][0] = mXform1.r[1][1] = mXform1.r[2][2] = 1; 1223 | 1224 | MY_TRACE(pfLog, "wcs move (%lf, %lf, %lf)\n", mXform1.t[0], mXform1.t[1], mXform1.t[2]); 1225 | if (use_tp_orientation) 1226 | { 1227 | p_3d pt_origin; 1228 | memcpy (pt_origin, n.u.m1027.wcs_origin, 3 * sizeof(double)); 1229 | xform_pt(pt_origin, &mXform2); 1230 | MY_TRACE(pfLog, "setting ws_toolpath_orientation to (%lf, %lf, %lf) dir (%lf, %lf, %lf) ref (%lf, %lf, %lf)\n", 1231 | pt_origin[X], pt_origin[Y], pt_origin[Z], 1232 | vecDir[X], vecDir[Y], vecDir[Z], 1233 | vecRef[X], vecRef[Y], vecRef[Z]); 1234 | apt->WorkingstepToolpathOrientation (pt_origin[X], pt_origin[Y], pt_origin[Z], vecDir[X], vecDir[Y], vecDir[Z], vecRef[X], vecRef[Y], vecRef[Z]); 1235 | } 1236 | } 1237 | 1238 | // -------------------------------------------------------- 1239 | // END toolpath extraction 1240 | // -------------------------------------------------------- 1241 | nOldOpID = n.op_idn; 1242 | } 1243 | 1244 | nOldGcode = n.gcode; 1245 | #ifdef MY_DEBUG 1246 | fflush(pfLog); 1247 | #endif 1248 | 1249 | // Move to the next op 1250 | // operation_manager(&opo, OPMGR_GET_NEXT_LIST, &dop, &bResult); 1251 | 1252 | } 1253 | #ifdef MY_DEBUG 1254 | fflush(pfLog); 1255 | #endif 1256 | } 1257 | 1258 | #ifdef MY_DEBUG 1259 | fflush(pfLog); 1260 | #endif 1261 | 1262 | // dlgProg.DestroyWindow(); 1263 | apt->CoolantOff(); 1264 | 1265 | // long res = AfxMessageBox("Export complete. Run Configuration File?", MB_YESNO | MB_ICONINFORMATION); 1266 | 1267 | MY_TRACE(pfLog, "Saving data in %s\n", dlgSave.GetPathName()); 1268 | apt->SaveAsModules(_com_util::ConvertStringToBSTR (dlgSave.GetPathName())); 1269 | // apt->SaveFastAsModules(dlgSave.GetPathName()); 1270 | 1271 | AfxMessageBox("Mastercam STEP-NC export complete", MB_OK); 1272 | MY_TRACE(pfLog, "Mastercam STEP-NC E\export complete\n"); 1273 | 1274 | MY_TRACE(pfLog, "Shutting down\n"); 1275 | feature->Reset(); 1276 | process->Reset(); 1277 | apt->Reset(); 1278 | 1279 | } 1280 | /* else 1281 | { 1282 | AfxMessageBox("Nothing to export.", MB_OK | MB_ICONINFORMATION); 1283 | }*/ 1284 | catch (...) 1285 | { 1286 | // dlgProg.DestroyWindow(); 1287 | feature->Reset(); 1288 | process->Reset(); 1289 | apt->Shutdown(); 1290 | // ShowMessage("Can't export toolpaths.", MSG_ERROR); 1291 | AfxMessageBox("Can't export toolpaths.", MB_OK | MB_ICONSTOP); 1292 | } 1293 | 1294 | #ifdef MY_DEBUG 1295 | fclose(pfLog); 1296 | #endif 1297 | 1298 | return; 1299 | } 1300 | 1301 | // load all the tools 1302 | void LoadAllTools() 1303 | { 1304 | tp_tool tl; 1305 | MC_BOOL bResult = true; 1306 | boolean foundOne = false; // used to decide if need to search lathe tools 1307 | DB_LIST_ENT_PTR ptrTool; 1308 | // db_ptr_type ptrTool; 1309 | int i; 1310 | CString strToolName; 1311 | CString a; // eliminate leading ' ' 1312 | 1313 | // Enumerate tools 1314 | for (i = 1; i < 256; i++) 1315 | { 1316 | memset(&tl, 0, sizeof(tp_tool)); 1317 | 1318 | tl.op.slot = i; 1319 | tool_manager(&tl, TLMGR_GET, &ptrTool, &bResult); 1320 | 1321 | if (!bResult) 1322 | { 1323 | continue; 1324 | } 1325 | else 1326 | { 1327 | foundOne = TRUE; 1328 | } 1329 | 1330 | tool_direction[i] = tl.spindle_rot; 1331 | 1332 | /* if (tl.op.comment[0] == ' ') 1333 | a = tl.op.comment+1; 1334 | else 1335 | a = tl.op.comment;*/ 1336 | 1337 | if (tl.op.type == 10 || tl.op.type == 19 || tl.op.type == 11 ) // end mill flat | bullnose | ball 1338 | { 1339 | apt->DefineToolEndmill (tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length, tl.op.n_flutes, 0); 1340 | apt->SELCTLTool(tl.op.tlno); 1341 | MY_TRACE(pfLog, "\nSaved Endmill Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1342 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1343 | MY_TRACE(pfLog, "Num flutes = %d Taper angle (saved as 0) = %f\n", tl.op.n_flutes, tl.op.tip_angle); 1344 | char buf[30]; 1345 | char buf2[30]; 1346 | sprintf (buf, "%d", tl.op.tlno); 1347 | if (tl.op.type == 10) 1348 | { 1349 | sprintf (buf2, "Endmill-%d", tl.op.tlno); 1350 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1351 | } 1352 | else if (tl.op.type == 19) 1353 | { 1354 | sprintf (buf2, "Bullnose-%d", tl.op.tlno); 1355 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1356 | } 1357 | else 1358 | { 1359 | sprintf (buf2, "Ball-%d", tl.op.tlno); 1360 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1361 | } 1362 | } 1363 | else if (tl.op.type == 12) // chamfer tool (tool tip angle not 0) 1364 | { 1365 | apt->DefineToolEndmill (tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length, tl.op.n_flutes, tl.op.tip_angle); 1366 | apt->SELCTLTool(tl.op.tlno); 1367 | MY_TRACE(pfLog, "\nSaved Chamfer Endmill Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1368 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1369 | MY_TRACE(pfLog, "Num flutes = %d Taper angle = %f\n", tl.op.n_flutes, tl.op.tip_angle); 1370 | char buf[30]; 1371 | char buf2[30]; 1372 | sprintf (buf, "%d", tl.op.tlno); 1373 | sprintf (buf2, "Chamfer-%d", tl.op.tlno); 1374 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1375 | } 1376 | else if (tl.op.type == 13) 1377 | { 1378 | apt->DefineToolFacemill (tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length, tl.op.n_flutes, tl.op.tip_angle); 1379 | apt->SELCTLTool(tl.op.tlno); 1380 | MY_TRACE(pfLog, "\nSaved Facemill Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1381 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1382 | MY_TRACE(pfLog, "Num flutes = %d Taper angle = %f\n", tl.op.n_flutes, tl.op.tip_angle); 1383 | char buf[30]; 1384 | char buf2[30]; 1385 | sprintf (buf, "%d", tl.op.tlno); 1386 | sprintf (buf2, "Facemill-%d", tl.op.tlno); 1387 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1388 | } 1389 | else if (tl.op.type == 2) 1390 | { 1391 | apt->DefineToolSpotDrill(tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length, tl.op.tip_angle); 1392 | apt->SELCTLTool(tl.op.tlno); 1393 | MY_TRACE(pfLog, "\nSaved Spot Drill Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1394 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1395 | MY_TRACE(pfLog, "tip angle = %f\n", tl.op.tip_angle); 1396 | char buf[30]; 1397 | char buf2[30]; 1398 | sprintf (buf, "%d", tl.op.tlno); 1399 | sprintf (buf2, "Spotdrill-%d", tl.op.tlno); 1400 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1401 | } 1402 | else if (tl.op.type == 3) 1403 | { 1404 | apt->DefineToolDrill(tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length, tl.op.tip_angle); 1405 | apt->SELCTLTool(tl.op.tlno); 1406 | MY_TRACE(pfLog, "\nSaved (Twist) Drill Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1407 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1408 | MY_TRACE(pfLog, "tip angle = %f\n", tl.op.tip_angle); 1409 | char buf[30]; 1410 | char buf2[30]; 1411 | sprintf (buf, "%d", tl.op.tlno); 1412 | sprintf (buf2, "Drill-%d", tl.op.tlno); 1413 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1414 | } 1415 | else if (tl.op.type == 4) 1416 | { 1417 | apt->DefineToolTapping(tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length, "metric", tl.op.thds, tl.op.dia -tl.op.thds); 1418 | apt->DefineToolHandOfCut ("right"); 1419 | apt->SELCTLTool(tl.op.tlno); 1420 | MY_TRACE(pfLog, "\nSaved Tapping RH Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1421 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1422 | MY_TRACE(pfLog, "thread_pitch = %f\n", tl.op.thds); 1423 | char buf[30]; 1424 | char buf2[30]; 1425 | sprintf (buf, "%d", tl.op.tlno); 1426 | sprintf (buf2, "Right_tap-%d", tl.op.tlno); 1427 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1428 | } 1429 | else if (tl.op.type == 5) 1430 | { 1431 | apt->DefineToolTapping(tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length, "metric", tl.op.thds, tl.op.dia -tl.op.thds); 1432 | apt->DefineToolHandOfCut ("left"); 1433 | apt->SELCTLTool(tl.op.tlno); 1434 | MY_TRACE(pfLog, "\nSaved Tapping LH Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1435 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1436 | MY_TRACE(pfLog, "thread_pitch = %f\n", tl.op.thds); 1437 | char buf[30]; 1438 | char buf2[30]; 1439 | sprintf (buf, "%d", tl.op.tlno); 1440 | sprintf (buf2, "Left_tap-%d", tl.op.tlno); 1441 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1442 | } 1443 | else if (tl.op.type == 7) 1444 | { 1445 | apt->DefineToolRotatingBoringCuttingTool(tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1446 | apt->SELCTLTool(tl.op.tlno); 1447 | MY_TRACE(pfLog, "\nSaved Bore Tool %d MCAM id = %d with identifier %s and type = %d\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type); 1448 | MY_TRACE(pfLog, "Diameter = %f, Overall length = %f, functional length = %f, flute length = %f\n", tl.op.dia, tl.holder_length + tl.oa_length, tl.oa_length, tl.flute_length); 1449 | char buf[30]; 1450 | char buf2[30]; 1451 | sprintf (buf, "%d", tl.op.tlno); 1452 | sprintf (buf2, "Boring-%d", tl.op.tlno); 1453 | apt->SetToolIdentifier (_com_util::ConvertStringToBSTR (buf), buf2); 1454 | } 1455 | else 1456 | { 1457 | // as per note from magnus overall assembly length in MCam is holder length + oa_length 1458 | apt->DefineTool(tl.op.dia, tl.op.crad, 0, 0, 0, 0, tl.holder_length + tl.oa_length); 1459 | MY_TRACE(pfLog, "\nSaved APT Tool %d MCAM id = %d with identifier %s and type = %d and tip = %f\n", tl.op.slot, tl.op.tlno, tl.op.comment, tl.op.type, tl.op.tip_angle); 1460 | } 1461 | 1462 | if (tl.op.rad_type && (tl.op.type == 10 || tl.op.type == 13 || tl.op.type == 19 || tl.op.type == 11)) 1463 | { 1464 | apt->DefineToolRadius (tl.op.crad); 1465 | MY_TRACE(pfLog, "\nCorner radius = %f, rad_type = %d\n", tl.op.crad, tl.op.rad_type); 1466 | } 1467 | if (tl.op.matl == 1) 1468 | { 1469 | apt->DefineToolMaterial ("Mastercam X4", "HSS"); 1470 | MY_TRACE(pfLog, "Material code = %d value = HSS ", tl.op.matl); 1471 | } 1472 | else if (tl.op.matl == 2) 1473 | { 1474 | apt->DefineToolMaterial ("Mastercam X4", "Carbide"); 1475 | MY_TRACE(pfLog, "Material code = %d value = Carbide ", tl.op.matl); 1476 | } 1477 | else if (tl.op.matl == 3) 1478 | { 1479 | apt->DefineToolMaterial ("Mastercam X4", "TiCoated"); 1480 | MY_TRACE(pfLog, "Material code = %d value = TiCoated ", tl.op.matl); 1481 | } 1482 | else if (tl.op.matl == 3) 1483 | { 1484 | apt->DefineToolMaterial ("Mastercam X4", "Ceramic"); 1485 | MY_TRACE(pfLog, "Material code = %d value = Ceramic ", tl.op.matl); 1486 | } 1487 | else 1488 | MY_TRACE(pfLog, "Material code = %d value = Unknown ", tl.op.matl); 1489 | 1490 | if (tl.op.feed != 0 || tl.op.rpm != 0) 1491 | { 1492 | apt->DefineToolFeedAndSpeed (tl.op.feed, tl.op.rpm); 1493 | MY_TRACE(pfLog, "Feed = %f Speed = %d\n", tl.op.feed, tl.op.rpm); 1494 | } 1495 | else 1496 | MY_TRACE(pfLog, "No feed/speed recommendations set (Feed = %f Speed = %d)\n", tl.op.feed, tl.op.rpm); 1497 | 1498 | // long tool_id = apt->GetCurrentTool (); 1499 | // process->SetToolLength (tool_id, tl.oa_length); 1500 | if (tool_direction[i]) 1501 | MY_TRACE(pfLog, "Tool is CCW\n"); 1502 | else 1503 | MY_TRACE(pfLog, "Tool is CW\n"); 1504 | 1505 | } 1506 | 1507 | if (foundOne) 1508 | return; 1509 | 1510 | // try lathe tools 1511 | MY_TRACE(pfLog, "Trying lathe tools\n"); 1512 | 1513 | LATHETOOL ltl; 1514 | 1515 | // Enumerate tools 1516 | for (i = 1; i < 256; i++) 1517 | { 1518 | memset(<l, 0, sizeof(tp_tool)); 1519 | 1520 | // ltl.op.slot = i; 1521 | ltl.uSlot = i; 1522 | 1523 | ltool_manager(<l, TLMGR_GET, &ptrTool, &bResult); 1524 | 1525 | if (!bResult) 1526 | { 1527 | continue; 1528 | } 1529 | else 1530 | { 1531 | foundOne = TRUE; 1532 | } 1533 | 1534 | tool_direction[i] = ltl.fCCW; 1535 | 1536 | apt->DefineTool(0, 0, 0, 0, 0, 0, 0); 1537 | apt->SELCTLTool(ltl.lToolNum); 1538 | MY_TRACE(pfLog, "Found lathe tool in slot %d toolnum = %d\n", i, ltl.lToolNum); 1539 | if (tool_direction[i]) 1540 | MY_TRACE(pfLog, "Tool is CCW\n"); 1541 | else 1542 | MY_TRACE(pfLog, "Tool is CW\n"); 1543 | } 1544 | 1545 | if (foundOne) 1546 | return; 1547 | 1548 | MY_TRACE(pfLog, "NO lathe tools\n"); 1549 | 1550 | } 1551 | 1552 | // code given to use by Mastercam 1553 | // Retrieve the 'tree branches' of items above the Operation 1554 | void GetOpParents(operation *opl, CStringArray *names) 1555 | { 1556 | names->RemoveAll(); 1557 | 1558 | //Get the immediate parent (a Toolpath Group) of this Operation 1559 | op_group *op_parent = TpMainGrpMgr.GetMainGrpList().GroupByID(opl->cmn.grp_idn); 1560 | CString parent(op_parent->name); 1561 | names->Add(op_parent->name); // Add the name of the Toolpath Group 1562 | 1563 | // Get the Machine Group that contains this Toolpath Group 1564 | op_group *op_mach = TpMainGrpMgr.GetMainGrpList().RetrieveRootMachineGroup(op_parent->grp_idn); 1565 | 1566 | int subLevel = 0; 1567 | CString parentSub[6]; 1568 | long nextParent = op_parent->parent_grp_idn; 1569 | while (nextParent != op_mach->grp_idn) 1570 | { 1571 | op_parent = TpMainGrpMgr.GetMainGrpList().GroupByID(nextParent); 1572 | names->Add(op_parent->name); // Add the name(s) of any Toolpath Groups that we're nested under 1573 | parentSub[subLevel++] = op_parent->name; 1574 | nextParent = op_parent->parent_grp_idn; 1575 | } 1576 | names->Add(op_mach->name); // Add the Mchine Group name 1577 | } 1578 | 1579 | 1580 | void MakeRoundHole(operation op, p_3d ptCenter, _int64 ws_id) 1581 | { 1582 | short cycle = op.u.prm_drl.cycle; 1583 | double peck1 = op.u.prm_drl.peck1; 1584 | double peck2 = op.u.prm_drl.peck2; 1585 | double breakthrough_amount = op.u.prm_drl.brk_thru; 1586 | unsigned char through = op.u.prm_drl.drill_tip; 1587 | double retract_pln = op.cmn.retract_pln; 1588 | int retract_on = op.cmn.retract_on; 1589 | 1590 | // feed plane not used for drilling in MCAM 1591 | 1592 | double dwell = op.u.prm_drl.dwell; 1593 | double retract_feed; 1594 | if (op.tl.feed != 0) 1595 | retract_feed = op.tl.retract / op.tl.feed; 1596 | else 1597 | retract_feed = 1; 1598 | 1599 | double retract_distance = op.u.prm_drl.peck_clr; 1600 | double dwell_step = dwell; // NO VALUE IN MASTERCAM? 1601 | 1602 | if (peck2 == 0 && peck1 != 0) 1603 | peck2 = peck1; 1604 | 1605 | double tip_angle = op.tl.tip_angle; 1606 | double tip_radius = op.tl.crad; 1607 | 1608 | CString cmnt; 1609 | cmnt.Format ("%s", op.comment); 1610 | 1611 | _int64 hole_id; 1612 | double hole_depth, drill_depth; 1613 | 1614 | ws_id = apt->GetCurrentWorkingstep(); 1615 | 1616 | MY_TRACE(pfLog, "MakeFeature: Round Hole for %s ws_id = %d retract = %f retract_on = %d retract_inc = %d\n", op.comment, ws_id, retract_pln, retract_on, op.cmn.retract_inc); 1617 | MY_TRACE(pfLog, "Breakthrough = %f Tool tip angle = %f Tool tip radius = %f\n", breakthrough_amount, tip_angle, tip_radius); 1618 | 1619 | feature->SetDirection(-op.tpln.m[2][0], -op.tpln.m[2][1], -op.tpln.m[2][2], 1620 | op.tpln.m[0][0], op.tpln.m[0][1], op.tpln.m[0][2]); 1621 | 1622 | if (op.cmn.top_stock_inc == TRUE) 1623 | { 1624 | MY_TRACE(pfLog, "MakeFeature: Round Hole WARNING top of stock incremental\n"); 1625 | // AfxMessageBox("Incremental Top of Stock."); 1626 | } 1627 | 1628 | if (op.cmn.depth_inc == TRUE) 1629 | hole_depth = fabs (op.cmn.depth); 1630 | else 1631 | hole_depth = fabs (op.cmn.depth - op.cmn.top_stock); 1632 | 1633 | if (op.cmn.retract_inc == FALSE) 1634 | retract_pln = fabs (op.cmn.top_stock - retract_pln); 1635 | 1636 | if (op.cmn.depth_inc == FALSE) 1637 | hole_bot = op.cmn.depth; 1638 | else 1639 | hole_bot = op.cmn.top_stock - op.cmn.depth; 1640 | 1641 | feature->SetLocation(ptCenter[0], ptCenter[1], hole_bot); 1642 | 1643 | if (through) 1644 | { 1645 | hole_id = feature->RoundHole(ws_id, _com_util::ConvertStringToBSTR (cmnt), hole_depth, op.tl.dia); // Hole diameter is the drill diameter 1646 | drill_depth = hole_depth + fabs(breakthrough_amount); 1647 | } 1648 | else 1649 | { 1650 | hole_id = feature->RoundHole(ws_id, _com_util::ConvertStringToBSTR (cmnt), hole_depth, op.tl.dia); // Hole diameter is the drill diameter 1651 | drill_depth = hole_depth; 1652 | feature->HoleConicalBottom(hole_id, tip_angle, tip_radius); 1653 | } 1654 | 1655 | MY_TRACE(pfLog, "Round Hole depth = %f, dia = %f at (%f, %f, %f)\n", hole_depth, op.tl.dia, ptCenter[0], ptCenter[1], hole_bot); 1656 | // MY_TRACE(pfLog, "Round Hole depth = %f, dia = %f at (%f, %f, %f)\n", hole_depth, op.tl.dia, ptCenter[0], ptCenter[1], ptCenter[2] - retract_pln); 1657 | 1658 | if (cycle == 0) 1659 | { 1660 | MY_TRACE(pfLog, "Drilling dwell = %f, depth = %f retract feed = %f\n", dwell, drill_depth, retract_feed); 1661 | process->Drilling (ws_id, drill_depth, dwell, retract_feed, 0); 1662 | } 1663 | else if (cycle == 1) 1664 | { 1665 | MY_TRACE(pfLog, "Multistep Drilling dwell = %f, depth = %f retract feed = %f\n", dwell, drill_depth, retract_feed); 1666 | MY_TRACE(pfLog, "Multistep Drilling peck1 = %f peck2 = %f retract distance = %f, dwell step = %f\n", peck1, peck2, retract_distance, dwell_step); 1667 | process->MultistepDrilling (ws_id, drill_depth, peck2, peck1, retract_distance, dwell, retract_feed, dwell_step, 0); 1668 | } 1669 | else if (cycle == 3) 1670 | { 1671 | MY_TRACE(pfLog, "Tapping dwell = %f, depth = %f retract feed = %f\n", dwell, drill_depth, retract_feed); 1672 | process->Tapping (ws_id, drill_depth, 0, dwell, retract_feed, 0); 1673 | } 1674 | else // 4 is common what is it? 1675 | { 1676 | MY_TRACE(pfLog, "Unprocessed Drilling cycle = %d dwell = %f, depth = %f\n", cycle, dwell, op.cmn.top_stock - op.cmn.depth); 1677 | process->Drilling (ws_id, drill_depth, dwell, retract_feed, 0); 1678 | } 1679 | 1680 | if (retract_pln != 0) 1681 | { 1682 | process->RetractPlane (ws_id, retract_pln); 1683 | } 1684 | 1685 | apt->Rapid (); // next move is rapid unless otherwise defined 1686 | return; 1687 | } 1688 | 1689 | 1690 | void MakePlanarFace(operation op, p_3d ptCenter, double dLength, double dWidth, _int64 ws_id) 1691 | { 1692 | MY_TRACE(pfLog, "Making planar face for workingstep at %d with sizes (%f, %f)\n", ws_id, dLength, dWidth); 1693 | feature->SetDirection(-op.tpln.m[2][0], -op.tpln.m[2][1], -op.tpln.m[2][2], 1694 | op.tpln.m[0][0], op.tpln.m[0][1], op.tpln.m[0][2]); 1695 | feature->SetLocation(ptCenter[0] - dLength / 2, ptCenter[1] - dWidth/2, ptCenter[2]); 1696 | feature->PlanarFace(ws_id, "planar face", op.cmn.top_stock - op.cmn.depth, dLength, dWidth); 1697 | process->PlaneRoughMilling (ws_id, op.dcuts.fin_amt, op.dcuts.rgh_amt); 1698 | return; 1699 | } 1700 | 1701 | void MakeRoundPocket(operation op, p_3d ptCenter, double dDiameter, double dDepth, _int64 ws_id) 1702 | { 1703 | MY_TRACE(pfLog, "Making circular pocket for workingstep at %d with diameter = %f and depth = %f\n", ws_id, dDiameter, dDepth); 1704 | feature->SetDirection(op.tpln.m[2][0], op.tpln.m[2][1], op.tpln.m[2][2], 1705 | -op.tpln.m[0][0], -op.tpln.m[0][1], -op.tpln.m[0][2]); 1706 | feature->SetLocation(ptCenter[0], ptCenter[1], ptCenter[2]); 1707 | feature->ClosedCircularPocket (ws_id, "circular pocket", dDepth, dDiameter); 1708 | // parameters need to be fixed 1709 | process->BottomSideRoughMilling (ws_id, op.dcuts.fin_amt, op.dcuts.rgh_amt, op.dcuts.fin_amt, op.dcuts.rgh_amt); 1710 | return; 1711 | } 1712 | 1713 | 1714 | void MakeGeneralOutsideProfile(operation op, CHAIN* pChain, _int64 ws_id) 1715 | { 1716 | double xy_allow = op.cmn.stk_remain; 1717 | double z_allow = op.dcuts.fin_amt * op.dcuts.fin_n; 1718 | 1719 | int nFeatureID = 0; 1720 | int old_feature_id = 0; 1721 | 1722 | MC_BOOL ok; 1723 | double depth, cdepth, abs_depth, abs_top_of_stock; 1724 | 1725 | cdepth = -999; 1726 | // in incremental mode pocket depth and top of stock are relative to chain 1727 | if (op.cmn.depth_inc || op.cmn.top_stock_inc) 1728 | get_chain_depth (pChain, &cdepth, &ok); 1729 | 1730 | if (op.cmn.top_stock_inc) 1731 | abs_top_of_stock = cdepth + op.cmn.top_stock; 1732 | else 1733 | abs_top_of_stock = op.cmn.top_stock; 1734 | 1735 | if (op.cmn.depth_inc) 1736 | abs_depth = cdepth; 1737 | else 1738 | abs_depth = op.cmn.depth; 1739 | 1740 | depth = fabs (abs_depth - abs_top_of_stock); 1741 | 1742 | MY_TRACE(pfLog, "Chain depth = %f, abs_depth = %f, abs_top_of_stock = %d\n", cdepth, abs_depth, abs_top_of_stock); 1743 | MY_TRACE(pfLog, "cmn.top_stock = %f, cmn.top_stock_inc = %d\n", op.cmn.top_stock, op.cmn.top_stock_inc); 1744 | MY_TRACE(pfLog, "cmn.depth = %f, cmn.dpeth_inc = %d\n", op.cmn.depth, op.cmn.depth_inc); 1745 | 1746 | // in incremental mode clearance, retract and feed are relative to top of stock 1747 | double abs_clear = 0; 1748 | if (op.cmn.clearance_on) 1749 | { 1750 | if (op.cmn.clearance_inc) 1751 | abs_clear = op.cmn.clearance_pln + abs_top_of_stock; 1752 | else 1753 | abs_clear = op.cmn.clearance_pln; 1754 | } 1755 | 1756 | // need process clearance plane 1757 | if (abs_clear > 0) 1758 | apt->ClearancePlane (abs_clear); 1759 | 1760 | double abs_retract = 0; 1761 | double abs_feed = 0; 1762 | // STEP-NC only has a retract plane, MCAM has retract and feed 1763 | if (op.cmn.retract_on) 1764 | { 1765 | if (op.cmn.retract_inc) 1766 | abs_retract = op.cmn.retract_pln + abs_top_of_stock; 1767 | else 1768 | abs_retract = op.cmn.retract_pln; 1769 | } 1770 | 1771 | // feed plane is not optional in MCAM 1772 | if (op.cmn.feed_inc) 1773 | abs_feed = op.cmn.feed_pln + abs_top_of_stock; 1774 | else 1775 | abs_feed = op.cmn.feed_pln; 1776 | 1777 | // pick the largest 1778 | if (abs_feed > abs_retract) 1779 | abs_retract = abs_feed; 1780 | 1781 | if (abs_retract > 0) 1782 | apt->RetractPlane (abs_retract); 1783 | 1784 | MY_TRACE(pfLog, "Retract = %f, feed = %f, clearance = %f\n", abs_retract, abs_feed, abs_clear); 1785 | 1786 | // do we need to define a profile for this chain? 1787 | // find_id_for_chain (pChain, old_feature_id, ws_id); 1788 | 1789 | // define new workingstep with new feature 1790 | if (old_feature_id == 0) 1791 | { 1792 | MY_TRACE(pfLog, "Operation needs new feature\n"); 1793 | 1794 | ws_id = apt->GetCurrentWorkingstep(); 1795 | feature->SetLocation (0, 0, 0); 1796 | feature->SetDirection(-op.cpln.m[2][0], -op.cpln.m[2][1], -op.cpln.m[2][2], 1797 | op.cpln.m[0][0], op.cpln.m[0][1], op.cpln.m[0][2]); 1798 | 1799 | 1800 | // check for clockwise or anit-clockwise chain 1801 | short direction; 1802 | MC_BOOL succf; 1803 | MC_BOOL view_match; 1804 | long n_pts; 1805 | ctour_rec ctour[500]; 1806 | double l_tol = 0; // linearization tolerance? 1807 | short nView = 0; // chain view? 1808 | double rel_depth; 1809 | chain_to_ctour_array (pChain, ctour, &rel_depth, nView, 500, 0, &n_pts, &view_match, 1, 1810 | l_tol, 1, &succf); 1811 | 1812 | find_direction (ctour, n_pts, &direction, &succf); 1813 | 1814 | if (pChain->closed) 1815 | { 1816 | MY_TRACE(pfLog, "Contour Chain is closed\n"); 1817 | MY_TRACE(pfLog, "Contour Chain direction is %s num points is %d\n", direction?"true":"false", n_pts); 1818 | MakeChainProfile(pChain, abs_depth, TRUE, direction); 1819 | } 1820 | else 1821 | { 1822 | MY_TRACE(pfLog, "Contour Chain is open\n"); 1823 | MY_TRACE(pfLog, "Contour Chain direction is %s num points is %d\n", direction?"true":"false", n_pts); 1824 | MakeChainProfile(pChain, abs_depth, FALSE, direction); 1825 | } 1826 | } 1827 | else // reuse old feature 1828 | { 1829 | MY_TRACE(pfLog, "Operation reusing old feature id = %d\n", old_feature_id); 1830 | ws_id = process->SecondWorkingstep (ws_id); 1831 | } 1832 | 1833 | // create process data 1834 | double rgh_side_allow = 0; 1835 | double rgh_radial = 0; 1836 | double axial_depth = 0; 1837 | int rgh_passes = 1; 1838 | 1839 | if (op.mcuts.on) 1840 | { 1841 | rgh_radial = op.mcuts.rgh_amt; 1842 | rgh_side_allow = op.mcuts.fin_amt * op.mcuts.fin_n; 1843 | rgh_passes = op.mcuts.rgh_n; 1844 | } 1845 | 1846 | if (op.dcuts.on) 1847 | { 1848 | axial_depth = op.dcuts.rgh_amt; 1849 | if (op.dcuts.fin_n != 0) 1850 | MY_TRACE(pfLog, "WARNING finish depth cuts for contour\n"); 1851 | } 1852 | else 1853 | axial_depth = depth; 1854 | 1855 | if (old_feature_id == 0 && pChain->closed) 1856 | { 1857 | MY_TRACE(pfLog, "Closed general outside profile\n"); 1858 | feature->ClosedGeneralOutsideProfile (ws_id, "closed contour", depth); 1859 | // add_to_chain_db (pChain, nFeatureID, ws_id); 1860 | } 1861 | else if (old_feature_id == 0) 1862 | { 1863 | MY_TRACE(pfLog, "Open general outside profile\n"); 1864 | feature->OpenGeneralOutsideProfile (ws_id, "open contour", depth); 1865 | // add_to_chain_db (pChain, nFeatureID, ws_id); 1866 | } 1867 | else 1868 | nFeatureID = old_feature_id; 1869 | 1870 | MY_TRACE(pfLog, "S Rough Milling ws_id = %d side_allow = %f, radial = %f number = &d\n", 1871 | ws_id, rgh_side_allow, rgh_radial, rgh_passes); 1872 | process->SideRoughMilling (ws_id, rgh_side_allow, rgh_radial, axial_depth); 1873 | 1874 | // set number using new number_of_passes attribute 1875 | 1876 | if (op.mcuts.on && op.mcuts.fin_amt > 0 && op.mcuts.fin_n > 0) 1877 | { 1878 | MY_TRACE(pfLog, "S Finish Milling passes = %d fin step = %f\n", op.mcuts.fin_n, op.mcuts.fin_amt); 1879 | ws_id = process->SecondWorkingstep (ws_id); 1880 | // make axial_depth conditional on if finishing at every depth 1881 | process->SideFinishMilling (ws_id, op.cmn.stk_remain, op.mcuts.fin_amt, axial_depth); 1882 | } 1883 | 1884 | return; 1885 | } 1886 | 1887 | void MakeChainProfile(CHAIN* pChain, double z_value, BOOL closed, BOOL reverse_contour_direction) 1888 | { 1889 | ent seg1, seg2; 1890 | CHAIN_ENT *ce1, *ce2; 1891 | 1892 | p_3d ptCenView = { 0, 0, 0 }; 1893 | p_3d ptCen3d = { 0, 0, 0 }; 1894 | BOOL first = true; 1895 | 1896 | // changed for Boxy - added code to process single line outside profiles 1897 | for (ce1 = first_chain_curve(pChain); ce1 != NULL; ce1 = next_chain_curve(pChain, ce1, FALSE)) 1898 | { 1899 | get_ent_from_eptr(ce1->e_ptr, &seg1); 1900 | ce2 = next_chain_curve(pChain, ce1, FALSE); 1901 | if (ce2 != NULL) 1902 | { 1903 | MY_TRACE(pfLog, "ce1 = %x ce2 = %x\n", ce1, ce2); 1904 | get_ent_from_eptr(ce2->e_ptr, &seg2); 1905 | MakeProfileGeometry (seg1, seg2, first, !closed, 1906 | z_value, FALSE, reverse_contour_direction); 1907 | } 1908 | else if (closed == TRUE) 1909 | { 1910 | ce2 = first_chain_curve(pChain); 1911 | MY_TRACE(pfLog, "closing: ce2 = %x\n", ce2); 1912 | get_ent_from_eptr(ce2->e_ptr, &seg2); 1913 | MakeProfileGeometry (seg1, seg2, first, FALSE, 1914 | z_value, FALSE, reverse_contour_direction); 1915 | break; 1916 | } 1917 | else if (first) // one line open profile? 1918 | { 1919 | ce2 = first_chain_curve(pChain); 1920 | MY_TRACE(pfLog, "One line open profile: ce1 = %x ce2 = %x\n", ce1, ce2); 1921 | get_ent_from_eptr(ce2->e_ptr, &seg2); 1922 | MakeProfileGeometry (seg1, seg2, first, FALSE, 1923 | z_value, FALSE, reverse_contour_direction); 1924 | break; 1925 | } 1926 | 1927 | first = false; 1928 | } 1929 | } 1930 | 1931 | void MakeGeneralPocket(operation op, CHAIN* pChain, _int64 ws_id, int nChains) 1932 | { 1933 | double xy_allow = op.cmn.stk_remain; 1934 | double z_allow = op.dcuts.fin_amt * op.dcuts.fin_n; 1935 | 1936 | _int64 nFeatureID = 0; 1937 | _int64 old_feature_id; 1938 | 1939 | MC_BOOL ok; 1940 | double depth, cdepth, abs_depth, abs_top_of_stock; 1941 | 1942 | if (op.u.prm_pkt.pock_type != POCK_OPEN) 1943 | sort_outside_to_inside (&pChain); // make sure pocket is first chain 1944 | 1945 | cdepth = -999; 1946 | // in incremental mode pocket depth and top of stock are relative to chain 1947 | if (op.cmn.depth_inc || op.cmn.top_stock_inc) 1948 | get_chain_depth (pChain, &cdepth, &ok); 1949 | 1950 | if (op.cmn.top_stock_inc) 1951 | abs_top_of_stock = cdepth + op.cmn.top_stock; 1952 | else 1953 | abs_top_of_stock = op.cmn.top_stock; 1954 | 1955 | if (op.cmn.depth_inc) 1956 | abs_depth = cdepth; 1957 | else 1958 | abs_depth = op.cmn.depth; 1959 | 1960 | depth = fabs (abs_depth - abs_top_of_stock); 1961 | 1962 | MY_TRACE(pfLog, "Chain depth = %f, abs_depth = %f, abs_top_of_stock = %d\n", cdepth, abs_depth, abs_top_of_stock); 1963 | MY_TRACE(pfLog, "cmn.top_stock = %f, cmn.top_stock_inc = %d\n", op.cmn.top_stock, op.cmn.top_stock_inc); 1964 | MY_TRACE(pfLog, "cmn.depth = %f, cmn.dpeth_inc = %d\n", op.cmn.depth, op.cmn.depth_inc); 1965 | 1966 | // in incremental mode clearance, retract and feed are relative to top of stock 1967 | double abs_clear = 0; 1968 | if (op.cmn.clearance_on) 1969 | { 1970 | if (op.cmn.clearance_inc) 1971 | abs_clear = op.cmn.clearance_pln + abs_top_of_stock; 1972 | else 1973 | abs_clear = op.cmn.clearance_pln; 1974 | } 1975 | 1976 | // need process clearance plane 1977 | if (abs_clear > 0) 1978 | apt->ClearancePlane (abs_clear); 1979 | 1980 | double abs_retract = 0; 1981 | double abs_feed = 0; 1982 | // STEP-NC only has a retract plane, MCAM has retract and feed 1983 | if (op.cmn.retract_on) 1984 | { 1985 | if (op.cmn.retract_inc) 1986 | abs_retract = op.cmn.retract_pln + abs_top_of_stock; 1987 | else 1988 | abs_retract = op.cmn.retract_pln; 1989 | } 1990 | 1991 | // feed plane is not optional in MCAM 1992 | if (op.cmn.feed_inc) 1993 | abs_feed = op.cmn.feed_pln + abs_top_of_stock; 1994 | else 1995 | abs_feed = op.cmn.feed_pln; 1996 | 1997 | // pick the largest 1998 | if (abs_feed > abs_retract) 1999 | abs_retract = abs_feed; 2000 | 2001 | if (abs_retract > 0) 2002 | apt->RetractPlane (abs_retract); 2003 | 2004 | MY_TRACE(pfLog, "Retract = %f, feed = %f, clearance = %f\n", abs_retract, abs_feed, abs_clear); 2005 | 2006 | // do we need to define a profile for this chain? 2007 | // find_id_for_chain (pChain, old_feature_id, ws_id); 2008 | 2009 | old_feature_id = 0; 2010 | // define new workingstep with new feature 2011 | if (old_feature_id == 0) 2012 | { 2013 | MY_TRACE(pfLog, "Operation needs new feature\n"); 2014 | ws_id = apt->GetCurrentWorkingstep(); 2015 | feature->SetLocation (0, 0, 0); 2016 | feature->SetDirection(-op.cpln.m[2][0], -op.cpln.m[2][1], -op.cpln.m[2][2], 2017 | op.cpln.m[0][0], op.cpln.m[0][1], op.cpln.m[0][2]); 2018 | 2019 | if (op.u.prm_pkt.pock_type != POCK_OPEN) 2020 | MakeChainProfile(pChain, abs_depth, TRUE, FALSE); 2021 | else 2022 | MakeChainProfile(pChain, abs_depth, FALSE, FALSE); 2023 | } 2024 | else // reuse old feature 2025 | { 2026 | MY_TRACE(pfLog, "Operation reusing old feature id = %d\n", old_feature_id); 2027 | ws_id = process->SecondWorkingstep (ws_id); 2028 | } 2029 | 2030 | // create process data 2031 | double fin_radial = 0; 2032 | double axial_depth = 0; 2033 | double radial_depth = 0; 2034 | 2035 | if (op.u.prm_pkt.finish) 2036 | { 2037 | fin_radial = op.u.prm_pkt.fin_n * op.u.prm_pkt.fin_step; 2038 | } 2039 | 2040 | if (op.u.prm_pkt.pock_type == POCK_OPEN) 2041 | { 2042 | if (old_feature_id == 0) 2043 | { 2044 | nFeatureID = feature->OpenGeneralPocket(ws_id, "open pocket", depth); 2045 | // add_to_chain_db (pChain, nFeatureID, ws_id); 2046 | } 2047 | else 2048 | nFeatureID = old_feature_id; 2049 | 2050 | if (op.u.prm_pkt.rough == TRUE) 2051 | { 2052 | if (op.dcuts.on) 2053 | axial_depth = op.dcuts.rgh_amt; 2054 | else 2055 | axial_depth = depth; 2056 | 2057 | MY_TRACE(pfLog, "B&S Rough Milling ws_id = %d side_allow = %f, bott_allow = %f, radial = %f, axial = %f fin_radial = %f\n", 2058 | ws_id, op.cmn.stk_remain, op.dcuts.stock_t_l, axial_depth, radial_depth, fin_radial); 2059 | process->BottomSideRoughMilling (ws_id, op.cmn.stk_remain, op.dcuts.stock_t_l, radial_depth, axial_depth); 2060 | // values before KTH 2061 | // process->BottomSideRoughMilling (ws_id, op.cmn.stk_remain + fin_radial, op.dcuts.stock_t_l, radial_depth, axial_depth); 2062 | } 2063 | MY_TRACE(pfLog, "MakeFeature: Open Pocket\n"); 2064 | } 2065 | else // all others assumed to be closed // if (op.u.prm_pkt.pock_type == POCK_STD) { 2066 | { 2067 | if (old_feature_id == 0) 2068 | { 2069 | nFeatureID = feature->ClosedGeneralPocket(ws_id, "closed pocket", depth); 2070 | // add_to_chain_db (pChain, nFeatureID, ws_id); 2071 | } 2072 | else 2073 | nFeatureID = old_feature_id; 2074 | 2075 | if (op.u.prm_pkt.rough == TRUE) 2076 | { 2077 | radial_depth = op.u.prm_pkt.rgh_step; 2078 | if (op.dcuts.on) 2079 | axial_depth = op.dcuts.rgh_amt; 2080 | else 2081 | axial_depth = depth; 2082 | 2083 | MY_TRACE(pfLog, "B&S Rough Milling ws_id = %d side_allow = %f, bott_allow = %f, radial = %f, axial = %f fin_radial = %f\n", 2084 | ws_id, op.cmn.stk_remain, op.dcuts.stock_t_l, axial_depth, radial_depth, fin_radial); 2085 | process->BottomSideRoughMilling (ws_id, op.cmn.stk_remain, op.dcuts.stock_t_l, radial_depth, axial_depth); 2086 | // Before KTH 2087 | // process->BottomSideRoughMilling (ws_id, op.cmn.stk_remain + fin_radial, op.dcuts.stock_t_l, radial_depth, axial_depth); 2088 | } 2089 | MY_TRACE(pfLog, "MakeFeature: Closed Pocket\n"); 2090 | } 2091 | // else { 2092 | // MY_TRACE(pfLog, "Unsupported pocket type (neither open nor closed)\n"); 2093 | // } 2094 | 2095 | // if (nChains > 1 && old_feature_id == 0) 2096 | // ChainsToBosses(nFeatureID, pChain->next, abs_depth, depth, op.dcuts.island_depths); // starting at the second chain in the CMI 2097 | 2098 | /* Taken out because looks stupid for Boxy 2099 | if (op.u.prm_pkt.finish) { 2100 | MY_TRACE(pfLog, "B&S Finish Milling passes = %d fin step = %f\n", op.u.prm_pkt.fin_n, op.u.prm_pkt.fin_step); 2101 | if (op.u.prm_pkt.fr_override_on) 2102 | apt->Feedrate (op.u.prm_pkt.fr_override); 2103 | if (op.u.prm_pkt.ss_override_on) 2104 | apt->SpindleSpeed (op.u.prm_pkt.ss_override); 2105 | 2106 | ws_id = process->SecondWorkingstep (ws_id); 2107 | 2108 | if (op.u.prm_pkt.cp.finish_all) 2109 | process->SideFinishMilling (ws_id, op.cmn.stk_remain, op.u.prm_pkt.fin_step, axial_depth); 2110 | else 2111 | process->SideFinishMilling (ws_id, op.cmn.stk_remain, op.u.prm_pkt.fin_step, depth); 2112 | 2113 | // add one side mill op for each spring back with radial_depth = 0 2114 | int count = op.u.prm_pkt.n_spring_cuts; 2115 | for (int j = 0; j < count; j++) { 2116 | ws_id = process->SecondWorkingstep (ws_id); 2117 | process->SideFinishMilling (ws_id, op.cmn.stk_remain, 0, 0); 2118 | } 2119 | } 2120 | */ 2121 | 2122 | return; 2123 | } 2124 | 2125 | 2126 | int arc_count = 0; 2127 | // seg1 is the current segement, seg2 is the next segment 2128 | // use seg2 to determine order for points in seg1 2129 | void MakeProfileGeometry (ent seg1, ent seg2, BOOL first, BOOL boss_or_open, double z_value, 2130 | BOOL last_in_open, BOOL reverse_contour_direction) 2131 | { 2132 | p_3d pt1End = { 0, 0, 0 }; 2133 | p_3d pt1Strt = { 0, 0, 0 }; 2134 | p_3d pt2End = { 0, 0, 0 }; 2135 | p_3d pt2Strt = { 0, 0, 0 }; 2136 | p_3d ptCenView = { 0, 0, 0 }; 2137 | p_3d ptCen3d = { 0, 0, 0 }; 2138 | 2139 | // make a line 2140 | if (seg1.id == L_ID) 2141 | { 2142 | copy_p_3d(pt1Strt, seg1.u.li.e1); 2143 | copy_p_3d(pt1End, seg1.u.li.e2); 2144 | 2145 | if (seg2.id == L_ID) 2146 | { 2147 | copy_p_3d(pt2Strt, seg2.u.li.e1); 2148 | copy_p_3d(pt2End, seg2.u.li.e2); 2149 | } 2150 | else if (seg2.id == A_ID) 2151 | { 2152 | copy_p_3d(pt2Strt, seg2.u.ar.ep1); 2153 | copy_p_3d(pt2End, seg2.u.ar.ep2); 2154 | } 2155 | else 2156 | { 2157 | MY_TRACE(pfLog, "Unknown type of profile chain segment = %d\n", seg1.id); 2158 | return; 2159 | } 2160 | 2161 | // determine if need to swap 2162 | if (dist_pp_3d (pt1Strt, pt2End) < EPSILON || dist_pp_3d (pt1Strt, pt2Strt) < EPSILON) 2163 | { 2164 | MY_TRACE(pfLog, "Swapping line point order\n"); 2165 | copy_p_3d(pt1Strt, seg1.u.li.e2); 2166 | copy_p_3d(pt1End, seg1.u.li.e1); 2167 | } 2168 | 2169 | if (first) 2170 | { 2171 | feature->LineTo("First point", pt1Strt[X], pt1Strt[Y], z_value); 2172 | MY_TRACE(pfLog, "First point in chain for line\n"); 2173 | } 2174 | 2175 | feature->LineTo("Line point", pt1End[X], pt1End[Y], z_value); 2176 | MY_TRACE(pfLog, "Line: (%f, %f, %f)->(%f, %f, %f)\n", pt1Strt[X], pt1Strt[Y], z_value, 2177 | pt1End[X], pt1End[Y], z_value); 2178 | } 2179 | 2180 | else if (seg1.id == A_ID) 2181 | { 2182 | copy_p_3d(pt1Strt, seg1.u.ar.ep1); 2183 | copy_p_3d(pt1End, seg1.u.ar.ep2); 2184 | 2185 | if (seg2.id == L_ID) 2186 | { 2187 | copy_p_3d(pt2Strt, seg2.u.li.e1); 2188 | copy_p_3d(pt2End, seg2.u.li.e2); 2189 | } 2190 | else if (seg2.id == A_ID) 2191 | { 2192 | copy_p_3d(pt2Strt, seg2.u.ar.ep1); 2193 | copy_p_3d(pt2End, seg2.u.ar.ep2); 2194 | } 2195 | else 2196 | { 2197 | MY_TRACE(pfLog, "Unknown type of profile chain segment = %d\n", seg1.id); 2198 | return; 2199 | } 2200 | 2201 | BOOL ccw = TRUE; 2202 | // determine if need to swap 2203 | if (dist_pp_3d (pt1Strt, pt2End) < EPSILON || dist_pp_3d (pt1Strt, pt2Strt) < EPSILON) 2204 | { 2205 | MY_TRACE(pfLog, "Swapping arc point order\n"); 2206 | copy_p_3d(pt1Strt, seg1.u.ar.ep2); 2207 | copy_p_3d(pt1End, seg1.u.ar.ep1); 2208 | ccw = FALSE; 2209 | } 2210 | 2211 | if (first) 2212 | { 2213 | feature->LineTo("First point", pt1Strt[X], pt1Strt[Y], z_value); 2214 | MY_TRACE(pfLog, "First point in chain for arc\n"); 2215 | } 2216 | 2217 | copy_p_3d (ptCenView, seg1.u.ar.c); 2218 | view_to_world (ptCenView, seg1.u.ar.view, ptCen3d); 2219 | if (boss_or_open) 2220 | { 2221 | p_2d p1, p2, cen; 2222 | copy_pt (p1, pt1Strt); // points may be swapped for open chain 2223 | copy_pt (p2, pt1End); 2224 | copy_pt (cen, ptCen3d); 2225 | // Function assumes all BOSS arcs are less than 180 2226 | ccw = counter_clockwise (p1, p2, cen); 2227 | } 2228 | 2229 | 2230 | // negative sweep means reverse direction? 2231 | // tested with several pockets including one with bosses 2232 | if (seg1.u.ar.sw < 0) 2233 | ccw = !ccw; 2234 | 2235 | // Otherwise arcs are CCW in MCAM, and start/end points control the actual shape 2236 | feature->Arc("arc", pt1End[X], pt1End[Y], z_value, 2237 | ptCen3d[X], ptCen3d[Y], z_value, seg1.u.ar.r, ccw); 2238 | 2239 | MY_TRACE(pfLog, "Arc %d: C(%f, %f, %f), \n\t(%f, %f, %f)->(%f, %f, %f), \n\tr=%f, %s\n", 2240 | arc_count++, ptCen3d[X], ptCen3d[Y], z_value, 2241 | pt1Strt[X], pt1Strt[Y], z_value, 2242 | pt1End[X], pt1End[Y], z_value, seg1.u.ar.r, ccw?"ccw":"cw"); 2243 | 2244 | MY_TRACE(pfLog, "Arc %d: start angle = %f, sweep angle = %f\n", 2245 | arc_count - 1, seg1.u.ar.sa, seg1.u.ar.sw); 2246 | 2247 | } 2248 | else 2249 | { 2250 | MY_TRACE(pfLog, "Unknown type of profile chain segment = %d\n", seg1.id); 2251 | return; 2252 | } 2253 | 2254 | if (last_in_open) 2255 | { 2256 | if (seg2.id == L_ID) 2257 | { 2258 | if (dist_pp_3d (pt2End, seg2.u.li.e1) < EPSILON) 2259 | { 2260 | feature->LineTo("Last Open Line point", seg2.u.li.e2[X], seg2.u.li.e2[Y], z_value); 2261 | MY_TRACE(pfLog, "Last Open Line point: (%f, %f, %f)->(%f, %f, %f)\n", pt1End[X], pt1End[Y], z_value, 2262 | seg2.u.li.e2[X], seg2.u.li.e2[Y], z_value); 2263 | } 2264 | else if (dist_pp_3d (pt2End, seg2.u.li.e2) < EPSILON) 2265 | { 2266 | feature->LineTo("Last Open Line point", seg2.u.li.e1[X], seg2.u.li.e1[Y], z_value); 2267 | MY_TRACE(pfLog, "Last Open Line point: (%f, %f, %f)->(%f, %f, %f)\n", 2268 | pt1End[X], pt1End[Y], z_value, 2269 | seg2.u.li.e1[X], seg2.u.li.e1[Y], z_value); 2270 | } 2271 | } 2272 | if (seg2.id == A_ID) 2273 | { 2274 | copy_p_3d (ptCenView, seg2.u.ar.c); 2275 | view_to_world (ptCenView, seg2.u.ar.view, ptCen3d); 2276 | 2277 | if (dist_pp_3d (pt2End, seg2.u.ar.ep1) < EPSILON) 2278 | { 2279 | feature->Arc("arc", seg2.u.ar.ep2[X], seg2.u.ar.ep2[Y], z_value, 2280 | ptCen3d[X], ptCen3d[Y], z_value, seg2.u.ar.r, TRUE); 2281 | 2282 | MY_TRACE(pfLog, "Arc %d: C(%f, %f, %f), \n\t(%f, %f, %f)->(%f, %f, %f), \n\tr=%f, %s\n", 2283 | arc_count++, ptCen3d[X], ptCen3d[Y], z_value, 2284 | pt1End[X], pt1End[Y], z_value, 2285 | seg2.u.ar.ep2[X], seg2.u.ar.ep2[Y], z_value, seg1.u.ar.r, TRUE?"ccw":"cw"); 2286 | } 2287 | 2288 | else if (dist_pp_3d (pt2End, seg2.u.ar.ep2) < EPSILON) 2289 | { 2290 | feature->Arc("arc", seg2.u.ar.ep1[X], seg2.u.ar.ep1[Y], z_value, 2291 | ptCen3d[X], ptCen3d[Y], z_value, seg2.u.ar.r, FALSE); 2292 | 2293 | MY_TRACE(pfLog, "Arc %d: C(%f, %f, %f), \n\t(%f, %f, %f)->(%f, %f, %f), \n\tr=%f, %s\n", 2294 | arc_count++, ptCen3d[X], ptCen3d[Y], z_value, 2295 | pt1End[X], pt1End[Y], z_value, 2296 | seg2.u.ar.ep1[X], seg2.u.ar.ep1[Y], z_value, seg1.u.ar.r, FALSE?"ccw":"cw"); 2297 | } 2298 | } 2299 | } 2300 | return; 2301 | } 2302 | // used to calculate the arc direction for BOSS arcs 2303 | // assumes all BOSS arcs are less than 180 2304 | 2305 | // could not find anything in Mastercam to indicate BOSS arc direction 2306 | // possible clues might be large start_angles or sweeps 2307 | // also some of the functions seem to make coordinates go negative sometimes 2308 | 2309 | // Mastercam arc's in boundary chains are always clockwise so do not use this 2310 | // algorithm except for bosses 2311 | 2312 | // This algorithm is strong on the case where arc's are 90 degrees vertical or 2313 | // horizontal because that seems to happen a lot in practice for Bosses 2314 | BOOL counter_clockwise (p_2d p1, p_2d p2, p_2d center) 2315 | { 2316 | double dx1, dy1, dx2, dy2; 2317 | dx1 = center[X] - p1[X]; 2318 | dy1 = center[Y] - p1[Y]; 2319 | dx2 = p2[X] - center[X]; 2320 | dy2 = p2[Y] - center[Y]; 2321 | 2322 | BOOL ccw; 2323 | if (fabs (dx1) > EPSILON && fabs (dy2) > EPSILON && fabs (dy1) > EPSILON && fabs (dx2) > EPSILON) 2324 | { 2325 | if (dy2 * dx1 - dy1 * dx2 > 0) 2326 | ccw = FALSE; 2327 | else if (dy2 * dx1 - dy1 * dx2 < 0) 2328 | ccw = TRUE; 2329 | MY_TRACE (pfLog, "FORMULA 1 ccw = %d\n", ccw); 2330 | } 2331 | else if (fabs (dy1) > EPSILON && fabs (dx2) > EPSILON) 2332 | { 2333 | if (dx2 * dy1 < 0) 2334 | ccw = FALSE; 2335 | else 2336 | ccw = TRUE; 2337 | MY_TRACE (pfLog, "FORMULA 2 dy1 = %f dx2 = %f ccw = %d\n", dy1, dx2, ccw); 2338 | } 2339 | else if (fabs (dy2) > EPSILON && fabs (dx1) > EPSILON) 2340 | { 2341 | if (dx1 * dy2 < 0) 2342 | ccw = TRUE; 2343 | else 2344 | ccw = FALSE; 2345 | MY_TRACE (pfLog, "FORMULA 3 dx1 = %f dy2 = %f ccw=%d\n", dx1, dy2, ccw); 2346 | } 2347 | else 2348 | MY_TRACE (pfLog, "FORMULA TROUBLE\n"); 2349 | 2350 | MY_TRACE(pfLog, "BOSS Arc calculation: C(%f, %f),\n (%f, %f)->(%f, %f),\n %s\n", 2351 | center[X], center[Y], p1[X], p1[Y], p2[X], p2[Y], ccw? "counter-clockwise" : "clockwise"); 2352 | 2353 | return ccw; 2354 | } 2355 | 2356 | 2357 | 2358 | ///////////////////////////////////////////////////////////////////////////// 2359 | // 2360 | // FUNCTION: GetChainBBox 2361 | // 2362 | // PURPOSE: Compute the bounding box of a chain. 2363 | // 2364 | // ARGUMENTS: CHAIN* pChain - MCAM chain entity 2365 | // int nView - MCAM view (coordinate system) 2366 | // double& dLength - Length of the bbox [out] 2367 | // double& dWitdth - Width of the bbox [out] 2368 | // p3_d center - Center point of the box [out] 2369 | // 2370 | // RETURN VALUE: void 2371 | // 2372 | ///////////////////////////////////////////////////////////////////////////// 2373 | void GetChainBBox(CHAIN* pChain, int nView, double& dLength, double& dWidth, p_3d center) 2374 | { 2375 | double ME_DBL_MAX = 100000; 2376 | double dXMin = ME_DBL_MAX; 2377 | double dXMax = -ME_DBL_MAX; 2378 | double dYMin = ME_DBL_MAX; 2379 | double dYMax = -ME_DBL_MAX; 2380 | 2381 | gt ent2D; 2382 | p_2d bbox[2]; 2383 | 2384 | for (CHAIN_ENT* ce = first_chain_curve(pChain); ce != NULL; ce = next_chain_curve(pChain, ce, FALSE)) 2385 | { 2386 | ent seg; 2387 | get_ent_from_eptr(ce->e_ptr, &seg); 2388 | ent_to_gt(&ent2D, nView, &seg); 2389 | bbox_gt(&ent2D, bbox); 2390 | 2391 | dXMin = min(dXMin, bbox[0][0]); 2392 | dXMax = max(dXMax, bbox[1][0]); 2393 | 2394 | dYMin = min(dYMin, bbox[0][1]); 2395 | dYMax = max(dYMax, bbox[1][1]); 2396 | } 2397 | 2398 | dLength = dXMax - dXMin; 2399 | dWidth = dYMax - dYMin; 2400 | 2401 | center[0] = dXMin + dLength / 2; 2402 | center[1] = dYMin + dWidth / 2; 2403 | center[2] = 0; // Don't set it here 2404 | 2405 | dLength = fabs(dLength); 2406 | dWidth = fabs(dWidth); 2407 | } 2408 | 2409 | 2410 | --------------------------------------------------------------------------------