Compare commits
911 Commits
main
...
ObliqueNesting
| Author | SHA1 | Date | |
|---|---|---|---|
| b8299df247 | |||
| 4a99f2bdf6 | |||
| 1e86180723 | |||
| f6d6043c0e | |||
| b048e2ebe2 | |||
| fc47bca0f1 | |||
| 0274096f57 | |||
| 983609397e | |||
| 05a8d23f6a | |||
| 40580cdc69 | |||
| f6b2477f2b | |||
| 69db74e30e | |||
| f58004dfeb | |||
| 7c485360de | |||
| 967117cc23 | |||
| 64b2e86a2d | |||
| 89b342a564 | |||
| 117e475de5 | |||
| a7b817b211 | |||
| d8c6a8ad55 | |||
| 9026acd9ca | |||
| 204346326f | |||
| 5d6e4c397d | |||
| 64bde8924d | |||
| cb6115d23f | |||
| 771c1367b1 | |||
| 6092063daa | |||
| 44650c303c | |||
| 69fa0d741d | |||
| 8e55ddda1f | |||
| 7a8fb04ebe | |||
| 77c27d911c | |||
| 3a29f273c9 | |||
| bab5b07bd1 | |||
| 683ae78c65 | |||
| 06d9529b7b | |||
| 922a7ac846 | |||
| a21a3979f1 | |||
| fcbed252e1 | |||
| b68bbb2c48 | |||
| 6fe6b41e87 | |||
| 78189631c1 | |||
| 1a6433d5f8 | |||
| 28026358b9 | |||
| b73fb86be9 | |||
| 1032557782 | |||
| 0ca5f92b96 | |||
| 0f58c026d0 | |||
| 70d170b2a3 | |||
| 06bc0f77df | |||
| a40cc026c9 | |||
| 34fb38ac00 | |||
| aaa06c1af5 | |||
| 98a48522ee | |||
| 6fd356f757 | |||
| 83895cc3bf | |||
| d001273704 | |||
| 621c9149b5 | |||
| f6f625c7cc | |||
| 9d8985093d | |||
| fe8275f05a | |||
| d32403f546 | |||
| 63d4ca7176 | |||
| 0889ae5c7a | |||
| 0fc9e1dd09 | |||
| 63308c0349 | |||
| 7e5ab8ecd3 | |||
| bddaf91fb7 | |||
| 2c77277c85 | |||
| 38a6ac237e | |||
| ed4d97ba51 | |||
| 7b12eaf331 | |||
| 3e55af917e | |||
| 73b6d80510 | |||
| 65c2c244d6 | |||
| 2ae547a24e | |||
| aff61f1daa | |||
| 0db6a74f8c | |||
| f68533944c | |||
| 37e08e3f42 | |||
| c6ced91b14 | |||
| 8efb64810a | |||
| 02390c2e9b | |||
| 7f7d75c113 | |||
| ecd50c0fea | |||
| 6f195e7fac | |||
| 626183f310 | |||
| fe6c0bb31c | |||
| 1c24f1046d | |||
| 70cfdd056f | |||
| 9ebb9c77db | |||
| a54fbb1259 | |||
| 1345c5a5cb | |||
| 9add357cb6 | |||
| b1ae9db859 | |||
| 57d555fb0b | |||
| 28a6049c77 | |||
| c8848974a4 | |||
| 6591396009 | |||
| b0531f8df8 | |||
| 67a595e311 | |||
| 7a84f2c396 | |||
| 19f62cdc90 | |||
| 0f20358607 | |||
| 8875fc4c68 | |||
| ee4d443074 | |||
| 995917672c | |||
| d5b9612406 | |||
| 4521910c56 | |||
| 267fc9daa3 | |||
| c997cb4440 | |||
| b98b03adba | |||
| f2f57be09f | |||
| efe7f2e0f9 | |||
| 8f04694232 | |||
| c14377fb67 | |||
| c491d635e7 | |||
| 18fe9ceccb | |||
| 86c36512a0 | |||
| 4bdb1b32b1 | |||
| 0a073ead4c | |||
| 76c8f45284 | |||
| 5c463298da | |||
| 7b16ace7a4 | |||
| 66159b25a8 | |||
| 518ad5e10a | |||
| fc7432a97a | |||
| 583aa789c4 | |||
| 92036b09b4 | |||
| 6d2a1664ce | |||
| 5934b07947 | |||
| 85147dc34a | |||
| 465ffc7e37 | |||
| 31f1f50d04 | |||
| 7867317982 | |||
| ab9ea95b45 | |||
| c52a3f4af6 | |||
| 598d717dbc | |||
| ab606d759e | |||
| a6d9a36dab | |||
| 8c573d25b2 | |||
| 5554977011 | |||
| d3a9284944 | |||
| 90f06cb7ec | |||
| 8897f3f00b | |||
| 1e4e75115c | |||
| d3bf465923 | |||
| 9f6a89d5ae | |||
| 6f730dcaec | |||
| f1cdaa498d | |||
| 217a359ba0 | |||
| da23b96a9c | |||
| fe358e3ca4 | |||
| 6a7f32b5c1 | |||
| 9b9758fd2c | |||
| 667da4e3d1 | |||
| fe309e338b | |||
| 340a249948 | |||
| 0f5a1215f9 | |||
| 5d461bbc39 | |||
| 4986d3bf67 | |||
| d5243cda37 | |||
| e1e46445b0 | |||
| 570e41a40d | |||
| f3938ee0b6 | |||
| 309bae0265 | |||
| c068479ec1 | |||
| 608a9c63c8 | |||
| 38d432fd79 | |||
| 3b65f6233d | |||
| f1805625d3 | |||
| 568de09954 | |||
| 70025d1816 | |||
| fb74d28926 | |||
| 73acee6695 | |||
| c3a82a0804 | |||
| 6d1cae6ff3 | |||
| 2bcaeca91f | |||
| 3136604e14 | |||
| 82cd8f5d8c | |||
| e9493ead6b | |||
| e9417ba322 | |||
| 79417998a2 | |||
| c290254bae | |||
| 604a2676ce | |||
| 827a709af0 | |||
| 05f729df45 | |||
| 646e69e3af | |||
| ef155ad1fb | |||
| 6609c7ee16 | |||
| 5068d75362 | |||
| e646351f3f | |||
| 660cca04ca | |||
| 5d15189d59 | |||
| 50dee06493 | |||
| 3d3ae22f87 | |||
| 21b2e1cd0a | |||
| 7bd18a8fb4 | |||
| 1c4970fdb6 | |||
| 77d6d89e13 | |||
| eb3cf0d7ff | |||
| 5ad9e0bf4f | |||
| c3ea568d99 | |||
| 30f59b0175 | |||
| c18e80a70d | |||
| ae30cb5736 | |||
| cd586673c7 | |||
| f426311b28 | |||
| e2a2d0fd4e | |||
| 69c31e4c2b | |||
| 56ca5a74b9 | |||
| ad1ea741d0 | |||
| 322412a1f3 | |||
| c1a563351a | |||
| 327a5a960d | |||
| fdfefaba74 | |||
| c76eba6e74 | |||
| c6b3b5a003 | |||
| a4fbfcf2c9 | |||
| fa1a12b41c | |||
| d162b27493 | |||
| 68da716da1 | |||
| d6900a2c59 | |||
| 4bbadb8581 | |||
| cb60773216 | |||
| 1e327819c6 | |||
| d5b4edea14 | |||
| 530dce3d0d | |||
| dc8c5e8ba2 | |||
| a2ed6f5789 | |||
| 198fa3a546 | |||
| 1ad5a74a8b | |||
| a8c6424839 | |||
| 9ed315ab9b | |||
| 1c8049d9a9 | |||
| 155fd09ee5 | |||
| 86adb74131 | |||
| 74a12a4a42 | |||
| 06a73a069f | |||
| e6a2ce3702 | |||
| e3cd0d3033 | |||
| eb0a46d545 | |||
| f9b1a957f6 | |||
| 8f2a09e5c7 | |||
| 711ac3930d | |||
| 4ce77a4792 | |||
| 15db75dfad | |||
| 6d319d17b6 | |||
| d8a3f257d8 | |||
| 43b096f531 | |||
| d9d505fc44 | |||
| ddff655240 | |||
| 2536244f1b | |||
| 7b4673acef | |||
| 2d1abbb3cc | |||
| 25dbaed63b | |||
| ecd2147e83 | |||
| 84cd799565 | |||
| 9468e3d013 | |||
| e095806a7a | |||
| f21e1ea557 | |||
| 6ce4af9884 | |||
| fa36c51de0 | |||
| 21bb95c0e9 | |||
| dd0b39df71 | |||
| ee54c32918 | |||
| b8b71ff73a | |||
| 0afcd786d1 | |||
| 070ad50d73 | |||
| d6bdbab510 | |||
| 44273e15a7 | |||
| 746eb9efe9 | |||
| 711e0c82f7 | |||
| c62f1818c7 | |||
| 9fe22368cb | |||
| fac9fd8877 | |||
| 28696ff4e5 | |||
| befc942be8 | |||
| 334680d3d6 | |||
| a3a29dc5bf | |||
| 50336bfad6 | |||
| 9c4fab2d3c | |||
| 00eeb482dd | |||
| 83ab68b075 | |||
| 66b273354e | |||
| 5c41793b70 | |||
| bc40db6a6e | |||
| c0cab77689 | |||
| d7fac47297 | |||
| c8431a4584 | |||
| 232a112036 | |||
| 58a98231ad | |||
| b3bf317780 | |||
| f9b62f4026 | |||
| f304df4d5b | |||
| 2d2b492fd0 | |||
| 01d4ac1c27 | |||
| 69f9669a5c | |||
| 1ac003c57c | |||
| 3b59b8f37a | |||
| 415e539e71 | |||
| ac774c2e2f | |||
| 716ebf7046 | |||
| 677e11d1e2 | |||
| 911113e853 | |||
| f7462a47f4 | |||
| 810bf4f7ab | |||
| 20b9da785e | |||
| 738b2af502 | |||
| 0f4f245827 | |||
| ddbbc894fd | |||
| a508b4bb94 | |||
| 1a14d156cf | |||
| cbb6e11515 | |||
| 4cc0b6e2b3 | |||
| 6fc055de57 | |||
| 29c2c461ac | |||
| e6d9060b80 | |||
| 45bfcdbcfc | |||
| 5f663d3362 | |||
| b65a5b758b | |||
| 9ed6cf8c30 | |||
| ed1de946c1 | |||
| aa543fdf2d | |||
| a8f000fe75 | |||
| edeb99bdb9 | |||
| c9dd712e70 | |||
| b43eca9f27 | |||
| 4215b3f5b0 | |||
| e1bce72db5 | |||
| 0290547a93 | |||
| d7c3bd83de | |||
| cb81dc1d15 | |||
| 8f2e10fc22 | |||
| 9e2bef3192 | |||
| d48d392c58 | |||
| dcf61e0442 | |||
| 3634af8f29 | |||
| f84f0a6569 | |||
| 3836764c51 | |||
| 51dec026ec | |||
| 3a4b29070e | |||
| 1eb839fce4 | |||
| d642a5ebae | |||
| f459cf94b2 | |||
| 0e4aeb49b8 | |||
| dbe0a04434 | |||
| 7eff64d3bb | |||
| 8e960954ef | |||
| 70b4927fd2 | |||
| 5a02c08965 | |||
| c6353aadc1 | |||
| 8e49d0afcc | |||
| a0e595e58d | |||
| 43aa2f1b3b | |||
| fca9eff9a7 | |||
| af1a7b768d | |||
| 0be9defb0f | |||
| 814a0feefa | |||
| 8f7969d93f | |||
| acf53145b4 | |||
| caf8e5f144 | |||
| 967df73f43 | |||
| bba5d13084 | |||
| a15b5621c7 | |||
| 6b0714ca36 | |||
| f7a07e0cc1 | |||
| ae3a0ef148 | |||
| af971f70fc | |||
| ed0098efef | |||
| a0d44ed1e4 | |||
| 3c1925ed29 | |||
| fd4e761c36 | |||
| 232751fd5d | |||
| 69259e3f80 | |||
| d72517df6b | |||
| 719d3b61af | |||
| 5bbde3e60f | |||
| dc3d534cb4 | |||
| a4c20cee6c | |||
| fd070db4d0 | |||
| b27bb97e50 | |||
| c5c45a8dd0 | |||
| b298bd24e7 | |||
| b0ca47880f | |||
| 6d9e987bc7 | |||
| 698e7d1639 | |||
| 8585797cc0 | |||
| 4c5f620117 | |||
| 87d39d747e | |||
| eb551742d1 | |||
| 188ddce206 | |||
| 0825cc7a62 | |||
| 6b2c267dfe | |||
| d51f2bc7d5 | |||
| 3d25ba23cc | |||
| 48e449d85a | |||
| 2b634dbb96 | |||
| 91dc770f92 | |||
| 825d8596dd | |||
| e4b0955846 | |||
| 0d5d97a58a | |||
| 8211fbc4b0 | |||
| f0e56275b9 | |||
| 5af77cff10 | |||
| 1e4388c091 | |||
| 702d4617a0 | |||
| 6adb856b7a | |||
| e155fee802 | |||
| 792cb4feb4 | |||
| 0d981a3d4f | |||
| fdb4bd405e | |||
| 4edd45a355 | |||
| 4a9db5d986 | |||
| 5f06b160b9 | |||
| c7b3668418 | |||
| 05cc611dae | |||
| 56ad7bb04c | |||
| a772113107 | |||
| 97dfd6f2e1 | |||
| d580a0fe08 | |||
| bbd5c67f65 | |||
| cff6dbcd7b | |||
| ee39724618 | |||
| 85f14504aa | |||
| 564a17fb35 | |||
| 27e900c944 | |||
| 7a27212cb8 | |||
| 5b10e28f07 | |||
| eb05b74a44 | |||
| ff8a753d65 | |||
| af761c95bf | |||
| 970fb60d66 | |||
| 3aecde91b9 | |||
| 05dfa1da6c | |||
| e2532b29f6 | |||
| 9d961977b2 | |||
| 8c95d5d27e | |||
| b4a1df8110 | |||
| da7d3cc08f | |||
| 1739634c58 | |||
| fd4de3742f | |||
| cdfebf83fb | |||
| d3a4ff1cd3 | |||
| 861384b5bb | |||
| e1b4089bfc | |||
| 3198287dfe | |||
| f947f761f1 | |||
| 9eeccf67a0 | |||
| 0a1c658b20 | |||
| a1f8339724 | |||
| 13f73a5363 | |||
| dd40555bbe | |||
| d9e2bdb44a | |||
| 19ce519fa6 | |||
| edf030367e | |||
| 691fbc516e | |||
| cc066f9b4f | |||
| 7ee7b63224 | |||
| 927550f438 | |||
| 41e70ccbd4 | |||
| e0d1a2905d | |||
| cfc2260997 | |||
| e12fd6824e | |||
| 48aa1477f1 | |||
| 060b919f5b | |||
| dd7c98229c | |||
| 8d8f66fd77 | |||
| 8a127f39ee | |||
| d9665b4ca9 | |||
| d46b466f71 | |||
| 10aa2352ae | |||
| fb59349345 | |||
| 03e37702e6 | |||
| 957269abf1 | |||
| 4aae1dbb54 | |||
| 607a3e61af | |||
| 717dca1089 | |||
| 4b49ebad7f | |||
| ca95265ee9 | |||
| 53fb0bdf0d | |||
| 340345725f | |||
| 0c0f6cf73b | |||
| 24245e8bd6 | |||
| a1528576b9 | |||
| e584c90c71 | |||
| 3b785a0907 | |||
| 4cd1bf526a | |||
| 86bb2e6651 | |||
| 9dbee99eca | |||
| db231be6ed | |||
| f5638e522f | |||
| 1cce5ca69a | |||
| 037e07921c | |||
| 95fdb3a250 | |||
| 1ef1c22337 | |||
| bd3a5fd318 | |||
| fe51d2746c | |||
| b9310cdeb0 | |||
| edebdb26d3 | |||
| 335604b8f2 | |||
| 53bcb4c74d | |||
| f2f1317fdf | |||
| 40259ba8d7 | |||
| 444ba1cc6c | |||
| e1bc32c22f | |||
| 85734fb7a3 | |||
| 8be4a152b7 | |||
| 60ffe9da73 | |||
| d3f88c44a9 | |||
| 46bfae300f | |||
| 81d7794b6d | |||
| c234978cab | |||
| 390c2cd14e | |||
| 81ab09a122 | |||
| 6dbf203d4d | |||
| 3e2541bd87 | |||
| 8d4212c926 | |||
| 603043b9d2 | |||
| dca28cbe1b | |||
| d77cdd6c7d | |||
| 837969e0a7 | |||
| 3bc9ef4688 | |||
| 64c800ab3e | |||
| 1dae899c6e | |||
| 27a8e785fd | |||
| 4a5e7a2af8 | |||
| a25f1b18b9 | |||
| 88ee8759a3 | |||
| 0d3cc467a9 | |||
| c0eeb01321 | |||
| 16c74add6f | |||
| 011830fb59 | |||
| c9fd830dff | |||
| 74611f99c5 | |||
| e028c9cd01 | |||
| ef6981f1b5 | |||
| 3837354ab8 | |||
| 28c9df081a | |||
| ab19bbdb6a | |||
| b2917f8b37 | |||
| 8c2d9653d7 | |||
| 2e12b09eb2 | |||
| ad652e1cd8 | |||
| a532bbf481 | |||
| a0d79c4d0f | |||
| 652141fd1d | |||
| 824f89b43f | |||
| 9a436bfdcf | |||
| d9a081f95e | |||
| ce661864a7 | |||
| 165230374e | |||
| 9888bc7f4e | |||
| fed75861be | |||
| 0c0d52afcb | |||
| 05f1130e02 | |||
| 4b1c598141 | |||
| ad1f28d670 | |||
| 9b5bd46972 | |||
| bec6ef3ea3 | |||
| 36f1ae5513 | |||
| d17673e65d | |||
| ada7d5d870 | |||
| 0023706024 | |||
| 05326f30bb | |||
| e37b3d3c3e | |||
| fb68dd28a0 | |||
| 5443173068 | |||
| 6f7ed8961f | |||
| 1c1d0f7b96 | |||
| 68a6c7d897 | |||
| 63006b913a | |||
| ed9dde9bec | |||
| 943f4f7501 | |||
| 09200303b3 | |||
| edd00a7b8f | |||
| 3b9aee2ba3 | |||
| f23085c483 | |||
| 1dac802cc0 | |||
| f36ab53755 | |||
| e141a0f4a9 | |||
| 13c227ee0b | |||
| 7a2d6696b8 | |||
| 8ed49c5cd1 | |||
| e947fb9384 | |||
| f0f0187de5 | |||
| 0a419e9b3e | |||
| ae802c8afb | |||
| 2be6204725 | |||
| b82e40d8ff | |||
| 80e309721e | |||
| 62c384a171 | |||
| 589e32cf92 | |||
| e03359b4d1 | |||
| 603edc9417 | |||
| 5032edc79a | |||
| 4e9ab24192 | |||
| 848e8ecd2c | |||
| 5a0fb8ca86 | |||
| 02d12d7106 | |||
| 67ceda8599 | |||
| a89f09b572 | |||
| eff84f5f4d | |||
| c512def05d | |||
| c29d2beec6 | |||
| 81270c324f | |||
| e47d9ac6df | |||
| 76e00c211e | |||
| 6f215f9849 | |||
| c06c2378ce | |||
| e7a08b330b | |||
| a0140dae55 | |||
| 26dff39619 | |||
| 6e45be2538 | |||
| 9cc0121229 | |||
| 0d9381b6ae | |||
| d674eec6ff | |||
| 5977a4c6db | |||
| 5233d89a5b | |||
| 0c70d6f812 | |||
| 2b929974dc | |||
| 07236b51cf | |||
| a4ed9b5b5b | |||
| 5f930e2e21 | |||
| 1a455e66de | |||
| 89d92bdcb4 | |||
| 99cbeca5c9 | |||
| 62efd89018 | |||
| 38eaed18cf | |||
| dcefd35cc9 | |||
| a7759e3b37 | |||
| 45712e604b | |||
| 44628dfa13 | |||
| fe9aaf0439 | |||
| 703fefa973 | |||
| 35e8e921f3 | |||
| 4a948aa61a | |||
| 5894e98047 | |||
| 18a4529ed4 | |||
| 99c2950ab9 | |||
| 1cd85c85b6 | |||
| 1dc1aa5a7c | |||
| c34f3dccd8 | |||
| d47343aba9 | |||
| 8807760db7 | |||
| 0ccfb2bfe6 | |||
| 562a219ffd | |||
| 67d7ce2dd9 | |||
| ab2a381808 | |||
| 2c1b0c7c79 | |||
| 2c410008fd | |||
| d548cc1b43 | |||
| ac4b2ff262 | |||
| 0b6bb3fe71 | |||
| adab6ab342 | |||
| e37d29fae3 | |||
| eafc1bec3f | |||
| c2b30d8ed9 | |||
| 6b7d15e503 | |||
| 46cdaa494b | |||
| bbf28a2ed7 | |||
| 8f1f99a628 | |||
| 6251c070ee | |||
| 3e1c7e3698 | |||
| e14e196a35 | |||
| 8800369b1e | |||
| 8dd3485048 | |||
| b7fdf8531a | |||
| 117dfa097f | |||
| fa9625b65c | |||
| feda17bd17 | |||
| 7b37da048a | |||
| 42b7decc48 | |||
| 15eab9b508 | |||
| 2256c15015 | |||
| f7201c32ed | |||
| fbfef76c64 | |||
| 7ccf3f888f | |||
| 64145e62cf | |||
| cf037fb574 | |||
| 20c10f495d | |||
| cf4b504733 | |||
| b229b21e64 | |||
| 81c0acbde1 | |||
| 7eb83ccf79 | |||
| 2f1b56ddc6 | |||
| 1271205f2c | |||
| b8a694db60 | |||
| a7664d5743 | |||
| 665113929a | |||
| f1baaa9842 | |||
| 084b6758a3 | |||
| a8c2e2fe98 | |||
| e37486db1d | |||
| f9168e8380 | |||
| 9edd39305f | |||
| 0c5373700e | |||
| 098244b109 | |||
| e553197d61 | |||
| c64aaade13 | |||
| ffe2d07918 | |||
| 89c315cdd8 | |||
| e3ab0b8f35 | |||
| 40e76a23c9 | |||
| fc6b50b345 | |||
| 8d2a9955ba | |||
| 87aa2a7ce6 | |||
| 2be4a3fe0b | |||
| d76ecbc9f6 | |||
| cc8410b0c5 | |||
| 3835f6f6e0 | |||
| cf96eb7bc3 | |||
| 3287420f41 | |||
| d013e836a0 | |||
| 3a5cba1c15 | |||
| 0c8d5516e1 | |||
| e443bd5813 | |||
| 37f85bccec | |||
| 512b907aae | |||
| e9d71ab75e | |||
| ad112ca6c3 | |||
| ce7d87a5ac | |||
| 8238767f69 | |||
| ca4141515d | |||
| 6ca555efc8 | |||
| b882f23d3e | |||
| 8c39c6a94f | |||
| e126e3f389 | |||
| 3bce7b5fd6 | |||
| 99e0bd27d9 | |||
| 456d8e903a | |||
| 14f81da3df | |||
| eb4a5e521f | |||
| 233a928dcd | |||
| db88c7bb8d | |||
| 992a115f93 | |||
| 50753dda52 | |||
| 9fcd805ed5 | |||
| eccfb96c22 | |||
| cff250ca37 | |||
| 7309ebb6a3 | |||
| c649870518 | |||
| 3d8ec03c47 | |||
| 42329d7688 | |||
| a6ddaa8bbd | |||
| bb82dcb724 | |||
| d58be78868 | |||
| 1cb9104404 | |||
| 19a47115ea | |||
| 6da682dfed | |||
| 08d3f7ff6d | |||
| 229e98cf9d | |||
| d7096a8a68 | |||
| b0f26bdea2 | |||
| 2586407ec9 | |||
| a34a62d635 | |||
| 44215b3b4e | |||
| a2b49fdf3e | |||
| 21b73e0031 | |||
| 54c86774b7 | |||
| 80c5a5a393 | |||
| 13ae86b6a7 | |||
| 8119643221 | |||
| 941954825d | |||
| 8d1286dd71 | |||
| 4abc2c01af | |||
| 7e6d8f4172 | |||
| 5aa2b5ac4d | |||
| ae4c3f9156 | |||
| a4f6e10dc3 | |||
| fc047c2350 | |||
| 28946a0291 | |||
| 9375cd0868 | |||
| 8bd772c96d | |||
| 2fff4438c0 | |||
| a17c62c15f | |||
| 20c8518f1d | |||
| 730d37c917 | |||
| 184a78d34c | |||
| a33e794b1e | |||
| f212c0cede | |||
| 38fdaca7bf | |||
| 7b580b24bb | |||
| 23bbd938fc | |||
| 21dd75b4a6 | |||
| a8ec76f451 | |||
| 9b5bb25c76 | |||
| b9c492fe5a | |||
| fdcb428002 | |||
| 91c883b87c | |||
| 8e151758b1 | |||
| 1132369f1e | |||
| b9bb1aefdd | |||
| 2b9113347a | |||
| 7c80c4d3d8 | |||
| 69fc865452 | |||
| 88bc848966 | |||
| 81a274563f | |||
| 32fa372012 | |||
| 21da5f633d | |||
| c24fef22a7 | |||
| 35e8ef2482 | |||
| 23d5f82403 | |||
| ec734ca99d | |||
| 34c5ecc5ec | |||
| 362f3fd2b0 | |||
| 9acd52ea10 | |||
| 74279896e9 | |||
| b270e150c0 | |||
| d9a36c0c5f | |||
| e189c0d518 | |||
| 380eb9450b | |||
| 5bbebcbbde | |||
| 3319d8b271 | |||
| 86fd80ee61 | |||
| 67bb860185 | |||
| 0b172e2be2 | |||
| d66bb615c9 | |||
| e3d73e9805 | |||
| f5f362c318 | |||
| 81c9a40618 | |||
| e5e9e7b876 | |||
| f5cbd7bfee | |||
| 546a60d8a3 | |||
| 62ca7479c7 | |||
| 4127bb5eef | |||
| 9a6036dc4c | |||
| 13c6eb3e06 | |||
| 4facba3389 | |||
| cd1f892a6c | |||
| 67899a5835 | |||
| 5dec2dc821 | |||
| c21de95a47 | |||
| db5ec90fbf | |||
| 285f3bc78d | |||
| cb37a14305 | |||
| d80a780886 | |||
| 9a8c0386d9 | |||
| 435075014d | |||
| 2b3630ee3a | |||
| 6d2037e0c5 | |||
| 2df3069711 | |||
| 5fc2b80cc1 | |||
| 2edfd52628 | |||
| 342082bb82 | |||
| 7e0bee34cc | |||
| 21ec48bc2d | |||
| f67f9530f5 | |||
| 0e634c7f0d | |||
| b6049893de | |||
| 0cdee9cfcb | |||
| d8b8a79a78 | |||
| 26c6cc68c9 | |||
| 58c9630563 | |||
| 04f40edd16 | |||
| 52fb5100ff | |||
| c49e81bcc4 | |||
| 4160190886 | |||
| b20ab1013a | |||
| a5382e0847 | |||
| 60bac29b1e | |||
| cc597ce890 | |||
| e0b4a8b852 | |||
| a312f715c7 | |||
| d191825118 | |||
| 8eeb7fa6d8 | |||
| b2a8279eb5 | |||
| c7687419a6 | |||
| 8cff8827a0 | |||
| 404938a6be | |||
| 69f97362b9 | |||
| 01bf95c56c | |||
| 32a16f97f3 | |||
| 297dcba66b | |||
| c1c6e2a220 | |||
| 230b5f871d | |||
| d53fdca890 | |||
| 7165db47f6 | |||
| 7b09634461 | |||
| 5dcc75587d | |||
| c3069a962a | |||
| 1a82df39ad | |||
| 6a89e6e29d | |||
| 5f30714a56 | |||
| 30fa7c8cbd | |||
| 59bbf159e4 | |||
| d45fc8e89b | |||
| ecf89edf59 | |||
| 3c1814ebdc | |||
| 5ea5c78605 | |||
| fedfc92ef0 | |||
| 03e4b4457d | |||
| 80dcdb0003 | |||
| 385143fb00 | |||
| 7bcce7463b | |||
| 8cda36a838 | |||
| 10399347f0 | |||
| 38540c5685 | |||
| 69f172863b | |||
| 76ec20260e | |||
| 10c1cd55f3 | |||
| ea588844c5 | |||
| fb47b28173 | |||
| 4f90b0704d | |||
| ce156606e6 | |||
| e58cf7e398 | |||
| bdc7c45204 | |||
| 7193f2595d | |||
| 65fec1e05d | |||
| a8a0ac5875 | |||
| 904b15a4c9 |
@@ -0,0 +1,3 @@
|
||||
.vscode/settings.json
|
||||
Compile.bat.old
|
||||
/bin
|
||||
@@ -0,0 +1,947 @@
|
||||
-- BatchProcessNew.lua by Egalware s.r.l. 2025/04/24
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
-- Imposto direttorio strategie. N.B. Le strategie dovranno essere caricate con il nome del direttorio padre
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\Strategies\\Standard\\?.lua')
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\StrategyLibs\\?.lua')
|
||||
|
||||
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi e carico log txt
|
||||
local sMachine = BEAM.MACHINE
|
||||
local sTxtLogFile
|
||||
if ( BEAM.FLAG ~= 6) and ( BEAM.FLAG ~= 9) then
|
||||
EgtResetCurrMachGroup()
|
||||
if not EgtSetCurrMachine( sMachine) then
|
||||
BEAM.ERR = 11
|
||||
BEAM.MSG = 'Error selecting machine : ' .. sMachine
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
return
|
||||
end
|
||||
end
|
||||
if BEAM.FLAG ~= 9 then
|
||||
sTxtLogFile = EgtChangePathExtension( BEAM.FILE, '.txt')
|
||||
end
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not sMachDir then
|
||||
EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
EgtOutBox( 'La macchina corrente non è configurata per lavorare travi', 'Lavora Travi', 'ERROR')
|
||||
BEAM.ERR = 12
|
||||
BEAM.MSG = 'Error not configured for beams machine : ' .. sMachine
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Segnalazione avvio
|
||||
EgtOutLog( '*** Beam Process Start ***', 1)
|
||||
|
||||
-- Carico le librerie
|
||||
_G.package.loaded.BasicCustomerStrategies = nil
|
||||
_G.package.loaded.BeamExec = nil
|
||||
_G.package.loaded.BeamLib = nil
|
||||
_G.package.loaded.DiceCut = nil
|
||||
_G.package.loaded.FaceData = nil
|
||||
_G.package.loaded.FeatureLib = nil
|
||||
_G.package.loaded.Identity = nil
|
||||
_G.package.loaded.Logs = nil
|
||||
_G.package.loaded.MachiningLib = nil
|
||||
_G.package.loaded.PreSimulationLib = nil
|
||||
_G.package.loaded.LeadInOutLib = nil
|
||||
-- strategie di base sempre presenti
|
||||
_G.package.loaded['HEADCUT\\HEADCUT'] = nil
|
||||
_G.package.loaded['TAILCUT\\TAILCUT'] = nil
|
||||
-- libreria macchina
|
||||
_G.package.loaded.BeamDataNew = nil
|
||||
-- libreria calcolo tempo esecuzione
|
||||
_G.package.loaded.TimeLib = nil
|
||||
|
||||
-- TODO controllare se c'è un modo migliore per resettare librerie delle strategie caricate precedentemente
|
||||
-- Per ottimizzare potremmo anche ciclare solo fino al numero di strategie raggiunto per il momento.
|
||||
-- Infatti difficile ci siano 9999 strategie.
|
||||
-- reset strategie caricate come librerie
|
||||
for i = 1, 9999 do
|
||||
local idSTRTemp = EgtReplaceString( EgtNumToString( i/10000, -4), '0.', '')
|
||||
local sLibraryToReload = "STR" .. idSTRTemp .. "\\STR" .. idSTRTemp
|
||||
if _G.package.loaded[sLibraryToReload] then
|
||||
_G.package.loaded[sLibraryToReload] = nil
|
||||
end
|
||||
end
|
||||
local vtCoreStrategiesNames = EgtFindAllFiles( BEAM.BASEDIR .. '\\StrategyLibs\\*.lua')
|
||||
for i = 1, #vtCoreStrategiesNames do
|
||||
local sCurrentName = EgtSplitString( vtCoreStrategiesNames[i], '.')[1]
|
||||
if _G.package.loaded[sCurrentName] then
|
||||
_G.package.loaded[sCurrentName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Variabili globali
|
||||
PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
-- carico librerie
|
||||
local BeamExec = require( 'BeamExec')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local JSON = require( 'JSON')
|
||||
|
||||
-- Variabili di modulo
|
||||
local dRawW
|
||||
local dRawH
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- Funzioni di supporto
|
||||
|
||||
local function GetDataConfig()
|
||||
-- recupero utensili dal magazzino
|
||||
BeamExec.GetToolsFromDB()
|
||||
-- TODO da gestire eventuali errori bloccanti
|
||||
return true
|
||||
end
|
||||
|
||||
local function WriteErrToLogFile( nErr, sMsg, nRot, idCut, idTask)
|
||||
local hFile = io.open( sTxtLogFile, 'a')
|
||||
hFile:write( 'ERR=' .. tostring( nErr) .. '\n')
|
||||
hFile:write( sMsg .. '\n')
|
||||
hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n')
|
||||
hFile:write( 'CUTID=' .. tostring( idCut or 0) .. '\n')
|
||||
hFile:write( 'TASKID=' .. tostring( idTask or 0) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
local function WriteFallToLogFile( nErr, sMsg, idCut, nFall)
|
||||
local hFile = io.open( sTxtLogFile, 'a')
|
||||
hFile:write( 'ERR=' .. tostring( nErr) .. '\n')
|
||||
hFile:write( sMsg .. '\n')
|
||||
hFile:write( 'CUTID=' .. tostring( idCut or 0) .. '\n')
|
||||
hFile:write( 'FALL=' .. tostring( nFall or 0) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
local function WriteTimeToLogFile( dTime)
|
||||
local hFile = io.open( sTxtLogFile, 'a')
|
||||
hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
-- Funzioni per gestire visualizzazione dopo errore e dopo warning
|
||||
local function PostErrView( nErr, sMsg)
|
||||
if nErr ~= 0 and ( BEAM.FLAG == 1 or BEAM.FLAG == 2) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (err=' .. tostring( nErr) .. ')', 'ERRORS')
|
||||
end
|
||||
end
|
||||
|
||||
local function PostWarnView( nWarn, sMsg)
|
||||
if nWarn ~= 0 and ( BEAM.FLAG == 1 or BEAM.FLAG == 2) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (wrn=' .. tostring( nWarn) .. ')', 'WARNINGS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione di reset gruppo di lavoro in caso di impossibilità di inserire i pezzi
|
||||
local function ResetMachGroup( PARTS)
|
||||
for i = 1, #PARTS do
|
||||
EgtErase( PARTS[i].id)
|
||||
end
|
||||
EgtRemoveMachGroup( EgtGetCurrMachGroup() or GDB_ID.NULL)
|
||||
end
|
||||
|
||||
-- scrittura JSON risultati
|
||||
-- TODO da migliorare/completare
|
||||
local function WriteResultToJson( RESULT)
|
||||
local sData = JSON:encode_pretty( RESULT)
|
||||
|
||||
-- Salvataggio e visualizzazione tabella
|
||||
local sOutFile = EgtChangePathExtension( BEAM.FILE, '.json')
|
||||
local DestFh = io.open( sOutFile, 'w+')
|
||||
if not DestFh then
|
||||
EgtOutBox( 'Error opening ' .. sOutFile, 'TestJson', 'ERROR')
|
||||
return false
|
||||
end
|
||||
DestFh:write( sData)
|
||||
DestFh:close()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- calcolo tempo esecuzione
|
||||
TIMER:start()
|
||||
EgtOutLog( ' Execution timer started')
|
||||
|
||||
-- script principale
|
||||
|
||||
local sFlag = ''
|
||||
if BEAM.FLAG == 0 then
|
||||
sFlag = 'GENERATE'
|
||||
elseif BEAM.FLAG == 1 then
|
||||
sFlag = 'MODIFY'
|
||||
elseif BEAM.FLAG == 2 then
|
||||
sFlag = 'SIMULATE'
|
||||
elseif BEAM.FLAG == 3 then
|
||||
sFlag = 'CHECK'
|
||||
elseif BEAM.FLAG == 4 then
|
||||
sFlag = 'CHECK+GENERATE'
|
||||
elseif BEAM.FLAG == 6 then
|
||||
sFlag = 'CREATE_BAR'
|
||||
elseif BEAM.FLAG == 8 then
|
||||
sFlag = 'CHECK_NOSIM'
|
||||
elseif BEAM.FLAG == 9 then
|
||||
sFlag = 'GET_TOPOLOGY'
|
||||
elseif BEAM.FLAG == 10 then
|
||||
sFlag = 'FLIP_ROT'
|
||||
else
|
||||
sFlag = 'FLAG='..tostring( BEAM.FLAG)
|
||||
end
|
||||
local sLog = 'BatchProcess : ' .. BEAM.FILE .. ', ' .. ( BEAM.MACHINE or EgtGetCurrMachineName()) .. ', ' .. sFlag
|
||||
EgtOutLog( sLog)
|
||||
|
||||
-- Dati dei file
|
||||
-- TODO spostare a quando flag ~= 6 e 9
|
||||
local sDir, sTitle = EgtSplitPath( BEAM.FILE)
|
||||
local sOriFile = sDir..sTitle..'.ori.bwe'
|
||||
local sNgeFile = sDir..sTitle..'.bwe'
|
||||
|
||||
-- cancellazione file log txt precedente
|
||||
-- in caso sia richiesta generazione senza check, verifico prima che il file log specifico non contenga errori: se sì, forzo il check
|
||||
-- TODO serve ancora?? forzare sempre il check e simulazione?
|
||||
if BEAM.FLAG == 0 then
|
||||
local hLogFile = io.open( sTxtLogFile, 'r')
|
||||
if hLogFile then
|
||||
for line in hLogFile:lines() do
|
||||
if EgtStartsWith( line, 'ERR') and tonumber( EgtSplitString( line, '=')[2] or 0) > 0 then
|
||||
BEAM.FLAG = 4
|
||||
break
|
||||
end
|
||||
end
|
||||
hLogFile:close()
|
||||
end
|
||||
-- restituisce all'interfaccia il nome della topologia della feature di id passato
|
||||
-- TODO valutare se fare script separato
|
||||
elseif BEAM.FLAG == 9 then
|
||||
if type( BEAM.FEATUREID) == 'number' then
|
||||
-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella
|
||||
local idTempGroup = BeamLib.CreateTempGroup()
|
||||
|
||||
local Part = {}
|
||||
Part.id = EgtGetParent( EgtGetParent( BEAM.FEATUREID))
|
||||
Part.idBoxTm = EgtGetFirstInGroup( EgtGetFirstNameInGroup( Part.id, 'Box') or GDB_ID.NULL)
|
||||
Part.b3Part = EgtGetBBoxGlob( Part.idBoxTm, GDB_BB.STANDARD)
|
||||
Part.idTempGroup = idTempGroup
|
||||
|
||||
local Proc = FeatureLib.GetProcFromTrimesh( BEAM.FEATUREID, Part)
|
||||
Proc.nGrp = EgtGetInfo( Proc.id, 'GRP', 'i')
|
||||
Proc.nPrc = EgtGetInfo( Proc.id, 'PRC', 'i')
|
||||
Proc.nParts = EgtSurfTmPartCount( Proc.id) or 1
|
||||
|
||||
Proc.Topology = {}
|
||||
if FeatureLib.NeedTopologyFeature( Proc, Part) then
|
||||
Proc.Topology = FeatureLib.ClassifyTopology( Proc, Part)
|
||||
else
|
||||
Proc = FeatureLib.GetAdditionalInfo( Proc, Part)
|
||||
Proc.Topology = FeatureLib.GetTopologyFromFeature( Proc, Part)
|
||||
end
|
||||
|
||||
if Proc.Topology and Proc.Topology.sName then
|
||||
BEAM.TOPOLOGY = Proc.Topology.sName
|
||||
else
|
||||
BEAM.TOPOLOGY = 'NOT_IMPLEMENTED'
|
||||
end
|
||||
|
||||
-- si cancella gruppo temporaneo contenente entità da cancellare
|
||||
EgtErase( idTempGroup)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Cancello file di log specifico
|
||||
EgtEraseFile( sTxtLogFile)
|
||||
|
||||
-- In generale va completamente riprocessato
|
||||
local bToProcess = true
|
||||
local bToRecalc = false
|
||||
-- se BTL, barra ed esiste già il corrispondente progetto Nge
|
||||
if EgtExistsFile( sOriFile) then
|
||||
bToProcess = false
|
||||
EgtCopyFile( sOriFile, sNgeFile)
|
||||
-- se cambiata configurazione macchina da ultima elaborazione, devo aggiornare
|
||||
if EgtCompareFilesLastWriteTime( sOriFile, sMachDir .. '\\Beam\\TS3Data.lua') == -1 or
|
||||
EgtCompareFilesLastWriteTime( sOriFile, sMachDir .. '\\Tools\\Tools.data') == -1 or
|
||||
EgtCompareFilesLastWriteTime( sOriFile, sMachDir .. '\\' .. sMachine ..'.mlde') == -1 then
|
||||
bToRecalc = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Inizializzo contatori errori e avvisi
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
|
||||
-- Se da elaborare
|
||||
if bToProcess then
|
||||
EgtOutLog( ' +++ Processing Parts >>>')
|
||||
|
||||
-- Flag di barra da creare
|
||||
local bCreateBar
|
||||
-- Lunghezza della barra ed elenco travi
|
||||
local dBarLen
|
||||
|
||||
-- Se necessario, apro il file Bwe
|
||||
if BEAM.FLAG ~= 6 then
|
||||
if not EgtOpenFile( BEAM.FILE) then
|
||||
BEAM.ERR = 13
|
||||
BEAM.MSG = 'Error opening BWE file : ' .. BEAM.FILE
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
-- Faccio copia del file originale
|
||||
EgtCopyFile( BEAM.FILE, sOriFile)
|
||||
|
||||
-- Se già presente un gruppo di lavoro
|
||||
if EgtGetFirstMachGroup() then
|
||||
-- Barra già presente
|
||||
bCreateBar = false
|
||||
-- Rendo corrente il gruppo di lavoro
|
||||
EgtSetCurrMachGroup()
|
||||
-- Area tavola
|
||||
local b3Tab = EgtGetTableArea()
|
||||
-- Sezione del grezzo
|
||||
local nRawId = EgtGetFirstRawPart()
|
||||
if not nRawId then
|
||||
BEAM.ERR = 14
|
||||
BEAM.MSG = 'Error no Raw Parts in the file : ' .. BEAM.FILE
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
local b3Raw = EgtGetRawPartBBox( nRawId)
|
||||
-- Calcolo posizione estremo TR o BR della tavola rispetto a sua origine in BL
|
||||
local dPosY = EgtIf( BeamData.CENTER_BEAM, ( b3Tab:getDimY() + b3Raw:getDimY() * EgtIf( BeamData.RIGHT_LOAD, -1, 1)) / 2, EgtIf( BeamData.RIGHT_LOAD, 0, b3Tab:getDimY()))
|
||||
BeamData.ptOriXR = Point3d( b3Tab:getDimX(), dPosY, 0)
|
||||
BeamData.dPosXR = EgtIf( BeamData.RIGHT_LOAD, MCH_CR.BR, MCH_CR.TR)
|
||||
-- Calcolo minimo grezzo scaricabile
|
||||
BeamExec.CalcMinUnloadableRaw( b3Raw:getDimY(), b3Raw:getDimZ())
|
||||
-- altrimenti devo recuperare i pezzi per creare la barra
|
||||
else
|
||||
-- Barra da creare
|
||||
bCreateBar = true
|
||||
-- Recupero l'elenco ordinato delle travi
|
||||
local nPartId = EgtGetFirstPart()
|
||||
while nPartId do
|
||||
table.insert( PARTS, { id = nPartId, sName = ( EgtGetName( nPartId) or ( 'Id=' .. tonumber( nPartId)))})
|
||||
nPartId = EgtGetNextPart( nPartId)
|
||||
end
|
||||
if #PARTS == 0 then
|
||||
BEAM.ERR = 14
|
||||
BEAM.MSG = 'Error no beams in the file : ' .. BEAM.FILE
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
local sOut = ''
|
||||
for i = 1, #PARTS do
|
||||
sOut = sOut .. PARTS[i].sName .. ', '
|
||||
end
|
||||
sOut = sOut:sub( 1, -3)
|
||||
EgtOutLog( 'Travi trovate : ' .. sOut, 1)
|
||||
end
|
||||
-- Ne recupero le dimensioni
|
||||
for i = 1, #PARTS do
|
||||
local Ls = EgtGetFirstNameInGroup( PARTS[i].id, 'Box')
|
||||
local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
if not b3Solid then
|
||||
BEAM.ERR = 15
|
||||
BEAM.MSG = 'Box undefined for beam ' .. PARTS[i].sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
PARTS[i].b3PartOriginal = b3Solid
|
||||
end
|
||||
end
|
||||
-- Assegno lunghezza della barra
|
||||
dBarLen = PARTS[1].b3PartOriginal:getDimX() + 10
|
||||
if dBarLen < 2200 then
|
||||
dBarLen = dBarLen + 1800
|
||||
end
|
||||
-- Assegno posizione prima ed unica trave
|
||||
PARTS[1].dPosX = 10
|
||||
end
|
||||
|
||||
-- Altrimenti, opero sul progetto corrente
|
||||
else
|
||||
-- Recupero l'identificativo del gruppo di lavoro corrente
|
||||
local nMGrpId = EgtGetCurrMachGroup()
|
||||
-- Barra da creare
|
||||
bCreateBar = true
|
||||
-- Lunghezza della barra
|
||||
dBarLen = EgtGetInfo( nMGrpId, 'BARLEN', 'd')
|
||||
-- Recupero l'elenco ordinato delle travi da inserire nella barra
|
||||
for i = 1, 100 do
|
||||
local sKey = 'PART'..tostring( i)
|
||||
local sVal = EgtGetInfo( nMGrpId, sKey)
|
||||
local vVal = EgtSplitString( sVal or '')
|
||||
if not vVal or #vVal < 2 then break end
|
||||
local nPartId = tonumber( vVal[1])
|
||||
local dPosX = tonumber( vVal[2])
|
||||
table.insert( PARTS, { id = nPartId, dPosX = dPosX, sName = ( EgtGetName( nPartId) or ( 'Id=' .. tonumber( nPartId)))})
|
||||
end
|
||||
if #PARTS == 0 then
|
||||
BEAM.ERR = 14
|
||||
BEAM.MSG = 'Error : no beams in the project'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
local sOut = ''
|
||||
for i = 1, #PARTS do
|
||||
sOut = sOut .. PARTS[i].sName .. ', '
|
||||
end
|
||||
sOut = sOut:sub( 1, -3)
|
||||
EgtOutLog( 'Travi trovate : ' .. sOut, 1)
|
||||
end
|
||||
-- Ne recupero le dimensioni
|
||||
for i = 1, #PARTS do
|
||||
local Ls = EgtGetFirstNameInGroup( PARTS[i].id, 'Box')
|
||||
local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
if not b3Solid then
|
||||
BEAM.ERR = 15
|
||||
BEAM.MSG = 'Box undefined for beam ' .. PARTS[i].sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
PARTS[i].b3PartOriginal = b3Solid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- recupero parametri generali da progetto
|
||||
BeamExec.GetGeneralParameters()
|
||||
|
||||
-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella
|
||||
local idTempGroup = BeamLib.CreateTempGroup()
|
||||
|
||||
-- Se devo creare la barra
|
||||
if bCreateBar then
|
||||
if #PARTS == 0 then
|
||||
-- Recupero l'identificativo del gruppo di lavoro corrente
|
||||
local nMGrpId = EgtGetCurrMachGroup()
|
||||
-- Recupero le dimensioni della barra
|
||||
dRawW = EgtGetInfo(nMGrpId, 'BARWIDTH', 'd')
|
||||
dRawH = EgtGetInfo(nMGrpId, 'BARHEIGHT', 'd')
|
||||
else
|
||||
-- Ne verifico le dimensioni
|
||||
dRawW = PARTS[1].b3PartOriginal:getDimY()
|
||||
dRawH = PARTS[1].b3PartOriginal:getDimZ()
|
||||
end
|
||||
local vBeamErr = {}
|
||||
for i = 2, #PARTS do
|
||||
local dDimW = PARTS[i].b3PartOriginal:getDimY()
|
||||
local dDimH = PARTS[i].b3PartOriginal:getDimZ()
|
||||
if ( abs( dDimW - dRawW) > 100 * GEO.EPS_SMALL or abs( dDimH - dRawH) > 100 * GEO.EPS_SMALL) and
|
||||
( abs( dDimH - dRawW) > 100 * GEO.EPS_SMALL or abs( dDimW - dRawH) > 100 * GEO.EPS_SMALL) then
|
||||
table.insert( vBeamErr, i)
|
||||
end
|
||||
end
|
||||
if #vBeamErr > 0 then
|
||||
local sOut = 'Rimosse travi con sezioni diverse dalla prima :\n'
|
||||
for i = #vBeamErr, 1, -1 do
|
||||
sOut = sOut .. PARTS[vBeamErr[i]].sName .. '\n'
|
||||
table.remove( PARTS, vBeamErr[i])
|
||||
end
|
||||
ResetMachGroup( PARTS)
|
||||
BEAM.ERR = 16
|
||||
BEAM.MSG = sOut
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
return
|
||||
end
|
||||
|
||||
-- TODO in caso di "GEN_sPiecesLoadingPosition = FULL_PRE_ROTATION" bisogna controllare anche sezione ribaltata di 90°
|
||||
-- Verifico sezione barra non troppo grande
|
||||
if not BeamData.MAX_WIDTH2 or not BeamData.MAX_HEIGHT2 then
|
||||
if ( dRawW > BeamData.MAX_WIDTH + 10 * GEO.EPS_SMALL or dRawH > BeamData.MAX_HEIGHT + 10 * GEO.EPS_SMALL) then
|
||||
ResetMachGroup( PARTS)
|
||||
local sOut = 'Sezione (' .. EgtNumToString( dRawW, 2) .. ' x ' .. EgtNumToString( dRawH, 2) .. ') ' ..
|
||||
'oltre i limiti della macchina (' .. EgtNumToString( BeamData.MAX_WIDTH, 2) .. ' x ' .. EgtNumToString( BeamData.MAX_HEIGHT, 2) .. ') '
|
||||
BEAM.ERR = 17
|
||||
BEAM.MSG = sOut
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
else
|
||||
if ( dRawW > BeamData.MAX_WIDTH + 10 * GEO.EPS_SMALL or dRawH > BeamData.MAX_HEIGHT + 10 * GEO.EPS_SMALL) and
|
||||
( dRawW > BeamData.MAX_WIDTH2 + 10 * GEO.EPS_SMALL or dRawH > BeamData.MAX_HEIGHT2 + 10 * GEO.EPS_SMALL) then
|
||||
ResetMachGroup( PARTS)
|
||||
local sOut = 'Sezione (' .. EgtNumToString( dRawW, 2) .. ' x ' .. EgtNumToString( dRawH, 2) .. ') ' ..
|
||||
'oltre i limiti della macchina (' .. EgtNumToString( BeamData.MAX_WIDTH, 2) .. ' x ' .. EgtNumToString( BeamData.MAX_HEIGHT, 2) .. ') ' ..
|
||||
'e (' .. EgtNumToString( BeamData.MAX_WIDTH2, 2) .. ' x ' .. EgtNumToString( BeamData.MAX_HEIGHT2, 2) .. ')'
|
||||
BEAM.ERR = 17
|
||||
BEAM.MSG = sOut
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Verifico sezione barra non troppo piccola
|
||||
if dRawW < BeamData.MIN_WIDTH - 10 * GEO.EPS_SMALL or dRawH < BeamData.MIN_HEIGHT - 10 * GEO.EPS_SMALL then
|
||||
ResetMachGroup( PARTS)
|
||||
local sOut = 'Sezione (' .. EgtNumToString( dRawW, 2) .. ' x ' .. EgtNumToString( dRawH, 2) .. ') ' ..
|
||||
'sotto i limiti della macchina (' .. EgtNumToString( BeamData.MIN_WIDTH, 2) .. ' x ' .. EgtNumToString( BeamData.MIN_HEIGHT, 2) .. ')'
|
||||
BEAM.ERR = 17
|
||||
BEAM.MSG = sOut
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
|
||||
-- Lunghezza della barra
|
||||
local dRawL = dBarLen + 0.1
|
||||
-- Sovramateriale di testa
|
||||
local dOvmHead = 0
|
||||
if #PARTS > 0 then
|
||||
dOvmHead = PARTS[1].dPosX or 0
|
||||
end
|
||||
|
||||
-- Sistemo le travi nel grezzo
|
||||
local bPbOk, sPbErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, nil, PARTS, BEAM.FLAG ~= 6, BEAM.FLAG == 10)
|
||||
if not bPbOk then
|
||||
BEAM.ERR = 18
|
||||
BEAM.MSG = sPbErr
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
else
|
||||
-- Scrivo altezza e larghezza barra nel gruppo di lavoro corrente
|
||||
local nMGrpId = EgtGetCurrMachGroup()
|
||||
EgtSetInfo(nMGrpId, 'BARHEIGHT', dRawH)
|
||||
EgtSetInfo(nMGrpId, 'BARWIDTH', dRawW)
|
||||
end
|
||||
-- sistemazioni per pezzi nella barra
|
||||
else
|
||||
-- ciclo sui grezzi
|
||||
local nRawId = EgtGetFirstRawPart()
|
||||
while nRawId do
|
||||
-- massimo un pezzo per grezzo
|
||||
local nPartId = EgtGetFirstPartInRawPart( nRawId)
|
||||
-- box del pezzo
|
||||
local Ls = EgtGetFirstNameInGroup( nPartId, 'Box')
|
||||
local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
-- se nel grezzo c'è un pezzo
|
||||
if nPartId then
|
||||
-- creo o pulisco gruppo geometrie aggiuntive
|
||||
BeamLib.CreateOrEmptyAddGroup( nPartId)
|
||||
-- aggiungo faccia per taglio iniziale al pezzo
|
||||
BeamLib.AddPartStartFace( nPartId, b3Solid)
|
||||
-- aggiungo faccia per taglio finale al pezzo
|
||||
BeamLib.AddPartEndFace( nPartId, b3Solid)
|
||||
end
|
||||
-- passo al successivo grezzo
|
||||
nRawId = EgtGetNextRawPart( nRawId)
|
||||
end
|
||||
-- elimino le lavorazioni
|
||||
EgtRemoveAllOperations()
|
||||
-- Recupero l'identificativo del gruppo di lavoro corrente
|
||||
local nMGrpId = EgtGetCurrMachGroup()
|
||||
-- Recupero l'elenco ordinato delle travi da inserire nella barra
|
||||
for i = 1, 100 do
|
||||
local sKey = 'PART'..tostring( i)
|
||||
local sVal = EgtGetInfo( nMGrpId, sKey)
|
||||
local vVal = EgtSplitString( sVal or '')
|
||||
if not vVal or #vVal < 2 then break end
|
||||
local nPartId = tonumber( vVal[1])
|
||||
local dPosX = tonumber( vVal[2])
|
||||
table.insert( PARTS, { nInd = #PARTS + 1, id = nPartId, dPosX = dPosX, sName = ( EgtGetName( nPartId) or ( 'Id=' .. tonumber( nPartId)))})
|
||||
end
|
||||
-- se lunghezza barra non settata, la leggo ora
|
||||
if not dBarLen then
|
||||
dBarLen = EgtGetInfo( nMGrpId, 'BARLEN', 'd')
|
||||
end
|
||||
-- Recupero tutte le informazioni dei pezzi
|
||||
local dLen = dBarLen
|
||||
for i = 1, #PARTS do
|
||||
-- aggiorno grezzo precedente
|
||||
PARTS[i].idRaw = EgtGetRawPartFromPart( PARTS[i].id)
|
||||
PARTS[i].bIsLastPart = ( i == #PARTS)
|
||||
-- dimensioni del grezzo ( comprende sovramateriale di testa e lavorazione di coda per separazione)
|
||||
PARTS[i].b3Raw = EgtGetRawPartBBox( PARTS[i].idRaw)
|
||||
PARTS[i].dRawLength = PARTS[i].b3Raw:getDimX()
|
||||
PARTS[i].dRawWidth = PARTS[i].b3Raw:getDimY()
|
||||
PARTS[i].dRawHeight = PARTS[i].b3Raw:getDimZ()
|
||||
-- dimensione pezzo finito
|
||||
PARTS[i].idBoxTm = EgtGetFirstInGroup( EgtGetFirstNameInGroup( PARTS[i].id, 'Box') or GDB_ID.NULL)
|
||||
PARTS[i].b3Part = EgtGetBBoxGlob( PARTS[i].idBoxTm, GDB_BB.STANDARD)
|
||||
PARTS[i].dLength = PARTS[i].b3Part:getDimX()
|
||||
PARTS[i].dWidth = PARTS[i].b3Part:getDimY()
|
||||
PARTS[i].dHeight = PARTS[i].b3Part:getDimZ()
|
||||
PARTS[i].bSquareSection = abs( PARTS[i].dWidth - PARTS[i].dHeight) < 100 * GEO.EPS_SMALL
|
||||
PARTS[i].nIndexInParts = i
|
||||
PARTS[i].SplittingPoints = BeamLib.GetPartSplittingPoints( PARTS[i])
|
||||
PARTS[i].NotClampableLength = { STD = { dHead = 0, dTail = 0}, SIDE = { dHead = 0, dTail = 0}, DOWN = { dHead = 0, dTail = 0}}
|
||||
PARTS[i].sBTLInfo = EgtGetInfo( PARTS[i].id, 'PROJ', 's') or nil
|
||||
PARTS[i].idTempGroup = idTempGroup
|
||||
|
||||
PARTS[i].sAISetupConfig = EgtGetInfo( PARTS[i].id, 'AISETUP', 's') or
|
||||
( GENERAL_PARAMETERS.BTL[PARTS[i].sBTLInfo] and GENERAL_PARAMETERS.BTL[PARTS[i].sBTLInfo].sAISetupConfig) or -- i parametri BTL potrebbero non esistere
|
||||
GENERAL_PARAMETERS.PROJECT.sAISetupConfig or nil
|
||||
|
||||
-- si carica configurazione lavorazioni
|
||||
TIMER:startElapsed('Json')
|
||||
BeamExec.GetStrategiesFromJSONinBD( PARTS[i].sAISetupConfig)
|
||||
PARTS[i].GeneralParameters = BeamLib.GetPieceGeneralParameters( PARTS[i], GENERAL_PARAMETERS_JSON)
|
||||
TIMER:stopElapsed('Json')
|
||||
-- parametro FlipRot sempre a false perchè a barra già creata non si possono più ruotare i pezzi
|
||||
PARTS[i].CombinationList = BeamExec.GetAvailableCombinations( PARTS[i], false)
|
||||
|
||||
-- sovramateriale in testa al pezzo
|
||||
local dDeltaS = max( PARTS[i].dPosX - ( dBarLen - dLen), 0)
|
||||
PARTS[i].dHeadOverMaterial = dDeltaS
|
||||
|
||||
-- lunghezza grezzo (comprende sovramateriale di testa e mm tagliati in coda dalla lavorazione, tipicamente 5.4mm dello spessore lama)
|
||||
local dCrawLen = PARTS[i].dRawLength
|
||||
-- materiale tolto in coda dalla lavorazione di separazione
|
||||
local dDeltaE = dCrawLen - PARTS[i].dLength - dDeltaS
|
||||
local dDeltaNextPiece
|
||||
if PARTS[i+1] then
|
||||
dDeltaNextPiece = PARTS[i+1].dPosX - ( dBarLen - dLen) - dCrawLen + dDeltaE
|
||||
else
|
||||
dDeltaNextPiece = 10000
|
||||
end
|
||||
PARTS[i].dDistanceToNextPiece = dDeltaNextPiece
|
||||
|
||||
-- aggiorno la lunghezza residua della barra
|
||||
dLen = dLen - dCrawLen
|
||||
PARTS[i].dRestLength = dLen
|
||||
end
|
||||
end
|
||||
|
||||
-- Se richiesta solo barra, esco
|
||||
if BEAM.FLAG == 6 then
|
||||
-- Completamento senza errori e avvisi
|
||||
if nWarnCnt == 0 then
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = '---'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
end
|
||||
EgtOutLog( ' +++ BatchProcess completed')
|
||||
return
|
||||
end
|
||||
|
||||
-- Imposto Nome file CN
|
||||
local _, sName, _ = EgtSplitPath( BEAM.FILE)
|
||||
EgtSetInfo( EgtGetCurrMachGroup(), 'NcName', sName .. '.cnc')
|
||||
|
||||
-- Abilito Vmill
|
||||
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
|
||||
|
||||
-- Aggiorno Setup utensili
|
||||
EgtImportSetup()
|
||||
|
||||
-- Lavoro le features
|
||||
-- TODO gestire errori e messaggi di ritorno in questo caso
|
||||
if not GetDataConfig() then return end
|
||||
|
||||
BeamExec.GetProcessings( PARTS, BEAM.FLAG == 10)
|
||||
BeamExec.GetCombinationMatrix( PARTS, BEAM.FLAG == 10)
|
||||
BeamExec.ProcessMachinings( PARTS, BEAM.FLAG == 10)
|
||||
|
||||
local sOutput = ''
|
||||
|
||||
-- scrittura txt risultati
|
||||
for i = 1, #RESULT do
|
||||
local sMsg = ''
|
||||
if RESULT[i].sType == 'Feature' then
|
||||
if RESULT[i].ChosenStrategy.bIsApplyOk then
|
||||
sMsg = RESULT[i].ChosenStrategy.sInfo
|
||||
else
|
||||
sMsg = RESULT[i].ChosenStrategy.sApplyInfo
|
||||
end
|
||||
elseif RESULT[i].sType == 'Part' then
|
||||
sMsg = RESULT[i].sMsg
|
||||
end
|
||||
sMsg = string.gsub( sMsg or '', '\n', ' ', 10)
|
||||
sMsg = string.gsub( sMsg or '', '\r', ' ', 10)
|
||||
-- trovata almeno una strategia e feature lavorata completamente
|
||||
if RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Completed' then
|
||||
if #EgtTrim( sMsg) > 0 then
|
||||
BEAM.ERR = -19
|
||||
BEAM.MSG = sMsg
|
||||
else
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = '---'
|
||||
end
|
||||
BEAM.ROT = -( ( RESULT[i].nRotation - ( BEAM.PREROTATE90 or 0)) or 1) + 1
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.TASKID = RESULT[i].idTask
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
-- trovata almeno una strategia ma nessuna applicabile oppure non trovata alcuna strategia
|
||||
elseif RESULT[i].sType == 'Feature'
|
||||
and ( ( RESULT[i].ChosenStrategy.sStatus == 'Not-Applicable')
|
||||
or ( not RESULT[i].ChosenStrategy.sStrategyName)) then
|
||||
|
||||
nErrCnt = nErrCnt + 1
|
||||
if #sMsg == 0 then
|
||||
sMsg = 'No applicable strategy found'
|
||||
end
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
BEAM.ERR = 19
|
||||
BEAM.MSG = sMsg
|
||||
BEAM.ROT = -( ( RESULT[i].nRotation - ( BEAM.PREROTATE90 or 0)) or 1) + 1
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.TASKID = RESULT[i].idTask
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
else
|
||||
-- segnalazione scarico pezzo standard, incompleto o a caduta
|
||||
if RESULT[i].sType == 'Part' and ( RESULT[i].nErr == -100 or RESULT[i].nErr == -101 or RESULT[i].nErr == -102) then
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = sMsg
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.FALL = abs( RESULT[i].nErr + 100)
|
||||
WriteFallToLogFile( BEAM.ERR, BEAM.MSG, BEAM.CUTID, BEAM.FALL)
|
||||
-- errore da post apply, al momento non specifico
|
||||
elseif RESULT[i].sType == 'Part' and RESULT[i].nErr > 0 then
|
||||
nErrCnt = nErrCnt + 1
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
BEAM.ERR = 19
|
||||
BEAM.MSG = 'Clamp impossible'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
return
|
||||
-- feature incompleta e altro
|
||||
elseif RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Not-Completed' then
|
||||
nWarnCnt = nWarnCnt + 1
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
BEAM.ERR = -19
|
||||
BEAM.MSG = 'Incomplete : Completion index ' .. RESULT[i].ChosenStrategy.dCompletionIndex .. '/5\n' .. sMsg
|
||||
BEAM.ROT = -( ( RESULT[i].nRotation - ( BEAM.PREROTATE90 or 0)) or 1) + 1
|
||||
BEAM.CUTID = RESULT[i].idCut
|
||||
BEAM.TASKID = RESULT[i].idTask
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- calcolo alternative (scrive già le variabili globali per interfaccia)
|
||||
if BEAM.FLAG == 10 then
|
||||
TIMER:startElapsed('Alternatives')
|
||||
BeamExec.ProcessAlternatives( PARTS)
|
||||
TIMER:stopElapsed('Alternatives')
|
||||
end
|
||||
|
||||
-- si cancella gruppo temporaneo contenente entità da cancellare
|
||||
EgtErase( idTempGroup)
|
||||
|
||||
-- TODO: se scarico a caduta (-101, -102) le lavorazioni dopo separazione vanno disattivate. Scrivere info feature incompleta su quelle feature
|
||||
|
||||
-- Salvo il progetto
|
||||
EgtSaveFile( sNgeFile)
|
||||
-- copio come originale (per dichiarare progetto ricalcolato)
|
||||
EgtCopyFile( sNgeFile, sOriFile)
|
||||
|
||||
-- Visualizzazione avvisi o errori
|
||||
if #sOutput > 0 then EgtOutLog( sOutput) end
|
||||
if nErrCnt > 0 then
|
||||
PostErrView( 19, sOutput)
|
||||
elseif nWarnCnt > 0 then
|
||||
PostWarnView( 19, sOutput)
|
||||
end
|
||||
|
||||
-- Altrimenti carico il progetto salvato e dichiaro nessun errore
|
||||
else
|
||||
EgtOutLog( ' +++ Loading Project already processed >>>')
|
||||
-- Carico il progetto già fatto
|
||||
EgtOpenFile( sNgeFile)
|
||||
-- Passo in modalità lavora
|
||||
EgtSetCurrMachGroup( EgtGetLastMachGroup())
|
||||
-- Se necessario eseguo aggiornamento con setup corrente e ricalcolo delle lavorazioni
|
||||
if bToRecalc or BEAM.FLAG == 3 or BEAM.FLAG == 4 or BEAM.FLAG == 8 then
|
||||
EgtOutLog( ' +++ Recalculating all dispositions and machinings >>>')
|
||||
EgtImportSetup()
|
||||
EgtApplyAllMachinings()
|
||||
-- Salvo il progetto
|
||||
EgtSaveFile( sNgeFile)
|
||||
-- copio come originale (per dichiarare progetto ricalcolato)
|
||||
EgtCopyFile( sNgeFile, sOriFile)
|
||||
end
|
||||
end
|
||||
|
||||
-- log tempi di esecuzione
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
TIMER:logAllElapsed()
|
||||
end
|
||||
|
||||
-- *** Eseguo simulazione con verifica collisione in cieco ***
|
||||
if ( BEAM.FLAG == 0 and ( bToProcess or bToRecalc)) or BEAM.FLAG == 3 or BEAM.FLAG == 4 then
|
||||
EgtOutLog( ' +++ Simulating with collision check >>>')
|
||||
-- verifico setup
|
||||
local bSetUpOk, SetUpErrors = EgtVerifyCurrSetup()
|
||||
if not bSetUpOk then
|
||||
local sToolsList = ""
|
||||
for ToolIndex = 1, #SetUpErrors do
|
||||
sToolsList = sToolsList .. SetUpErrors[ToolIndex]
|
||||
if ToolIndex ~= #SetUpErrors then
|
||||
sToolsList = sToolsList .. ", "
|
||||
end
|
||||
end
|
||||
BEAM.ERR = 19
|
||||
BEAM.MSG = 'Error in setup: tool/s ' .. sToolsList .. ' not found'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, 0, 0, 0)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
-- lancio simulazione
|
||||
local bSimOk, nErr, sErr = EgtSimulate()
|
||||
if not bSimOk then
|
||||
if nErr == MCH_SHE.INIT then
|
||||
BEAM.ERR = 19
|
||||
BEAM.MSG = 'Error starting simulation'
|
||||
elseif nErr == MCH_SHE.COLLISION then
|
||||
BEAM.ERR = 22
|
||||
BEAM.MSG = 'Head-part collision'
|
||||
elseif nErr == MCH_SHE.OUTSTROKE then
|
||||
BEAM.ERR = 23
|
||||
BEAM.MSG = 'Axis outstroke ' .. sErr
|
||||
elseif nErr == MCH_SHE.SPECIAL then
|
||||
BEAM.ERR = 24
|
||||
BEAM.MSG = 'Special error ' .. sErr
|
||||
else
|
||||
BEAM.ERR = 25
|
||||
BEAM.MSG = 'General failure (contact supplier)'
|
||||
end
|
||||
BEAM.ROT = 0
|
||||
BEAM.CUTID = 0
|
||||
BEAM.TASKID = 0
|
||||
local vItem = EgtSplitString( sErr, ';') or {}
|
||||
for i = 1, #vItem do
|
||||
vItem[i] = EgtTrim( vItem[i] or '')
|
||||
if string.find( vItem[i], 'CUTID', 1, true) then
|
||||
BEAM.CUTID = EgtGetVal( vItem[i], 'CUTID', 'i') or 0
|
||||
elseif string.find( vItem[i], 'TASKID', 1, true) then
|
||||
BEAM.TASKID = EgtGetVal( vItem[i], 'TASKID', 'i') or 0
|
||||
end
|
||||
end
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG, BEAM.ROT, BEAM.CUTID, BEAM.TASKID)
|
||||
-- TODO gestire collisione su feature specifica!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, BEAM.CUTID, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- *** Genero programma CN *** ( se richiesto)
|
||||
local bIsGenerationEnabled = ( EgtVerifyKeyOption( 110) == false)
|
||||
if bIsGenerationEnabled and ( BEAM.FLAG == 0 or BEAM.FLAG == 4) then
|
||||
EgtOutLog( ' +++ Generating NC part program >>>')
|
||||
local sInfo = 'EgtCAM5' .. EgtIf( EgtIs64bit(), ' 64bit', '')
|
||||
if EgtGetExeVersion then
|
||||
sInfo = sInfo .. ' ver.' .. EgtGetExeVersion()
|
||||
end
|
||||
sInfo = sInfo .. ' - '
|
||||
if not EgtGenerate( '', sInfo .. sNgeFile) then
|
||||
BEAM.ERR = 20
|
||||
local _, sName, _ = EgtSplitPath( BEAM.FILE)
|
||||
BEAM.MSG = 'Error generating NC part program : ' .. sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- *** Eseguo stima tempi ***
|
||||
EgtOutLog( ' +++ Estimating T&L >>>')
|
||||
if not EgtEstimate( '', 'EgtCAM5 - ' .. sNgeFile) then
|
||||
BEAM.ERR = 21
|
||||
local _, sName, _ = EgtSplitPath( BEAM.FILE)
|
||||
BEAM.MSG = 'Error estimating production time : ' .. sName
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
PostErrView( BEAM.ERR, BEAM.MSG)
|
||||
BeamExec.AddApplyResultToGlobalList( BEAM.ERR, 0, BEAM.MSG)
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
WriteResultToJson( RESULT)
|
||||
return
|
||||
end
|
||||
local Ttot = EgtGetInfo( EgtGetCurrMachGroup(), 'Ttot', 'd')
|
||||
local sTime = 'Total Time = ' .. EgtNumToString( Ttot, 1)
|
||||
EgtOutLog( sTime)
|
||||
|
||||
-- Se modifica o simula, imposto la vista ISO 3d opportuna
|
||||
if BEAM.FLAG == 1 or BEAM.FLAG == 2 then
|
||||
local vView = { SCE_VD.ISO_NW, SCE_VD.ISO_SW, SCE_VD.ISO_NE, SCE_VD.ISO_SE}
|
||||
local nV = min( max( BeamData.SIMUL_VIEW_DIR or 2, 1), 4)
|
||||
EgtSetView( vView[nV], false)
|
||||
end
|
||||
|
||||
-- Completamento senza errori e avvisi
|
||||
if nWarnCnt == 0 then
|
||||
BEAM.ERR = 0
|
||||
BEAM.MSG = '---'
|
||||
WriteErrToLogFile( BEAM.ERR, BEAM.MSG)
|
||||
end
|
||||
|
||||
-- Scrittura tempo totale stimato di lavorazione
|
||||
WriteTimeToLogFile( Ttot)
|
||||
RESULT[#RESULT+1] = { dTime = Ttot, sType = 'Time'}
|
||||
|
||||
-- Riporto risultati in tabella globale BEAM
|
||||
BEAM.RESULT = BeamLib.TableCopyDeep( RESULT)
|
||||
-- Scrittura json risultati
|
||||
WriteResultToJson( RESULT)
|
||||
|
||||
EgtOutLog( ' +++ BatchProcess completed')
|
||||
@@ -0,0 +1,7 @@
|
||||
[Beam]
|
||||
BtlEnable=1
|
||||
BaseDir=C:\EgtData\Beam
|
||||
BtlExec=BatchProcess.lua
|
||||
Button1=Process.lua,Images\Process.png,Lavora Travi
|
||||
Button2=Swap.lua,Images\Swap.png,Scambia estremi trave
|
||||
Button3=Rotate.lua,Images\Rotate.png,Ruota trave
|
||||
@@ -0,0 +1,49 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set LUAC=C:\EgtProg\Dll32\luac54.exe
|
||||
set ROOT=%cd%\
|
||||
set OUTBASE=bin
|
||||
|
||||
if not exist %OUTBASE% mkdir %OUTBASE%
|
||||
|
||||
REM Compile all .lua files excluding bin\ and any dot folders/files
|
||||
for /f "delims=" %%F in ('dir /b /s /a-d *.lua ^| findstr /v /i /c:"\%OUTBASE%\"') do (
|
||||
set FULL=%%F
|
||||
set REL=!FULL:%ROOT%=!
|
||||
|
||||
REM Skip if REL starts with '.' or contains '\.'
|
||||
echo !REL! | findstr /r /c:"^\." /c:"\\\." >nul
|
||||
if errorlevel 1 (
|
||||
set OUT=%OUTBASE%\!REL!
|
||||
|
||||
for %%D in ("!OUT!") do mkdir "%%~dpD" 2>nul
|
||||
|
||||
echo Compiling: !REL!
|
||||
%LUAC% -o "!OUT!" -s "!FULL!"
|
||||
) else (
|
||||
echo Skipping hidden/dot path: !REL!
|
||||
)
|
||||
)
|
||||
|
||||
REM Copy all .json files excluding bin\ and any dot folders/files
|
||||
for /f "delims=" %%F in ('dir /b /s /a-d *.json ^| findstr /v /i /c:"\%OUTBASE%\"') do (
|
||||
set FULL=%%F
|
||||
set REL=!FULL:%ROOT%=!
|
||||
|
||||
REM Skip if REL starts with '.' or contains '\.'
|
||||
echo !REL! | findstr /r /c:"^\." /c:"\\\." >nul
|
||||
if errorlevel 1 (
|
||||
set OUT=%OUTBASE%\!REL!
|
||||
|
||||
for %%D in ("!OUT!") do mkdir "%%~dpD" 2>nul
|
||||
|
||||
echo Copying: !REL!
|
||||
copy /Y "!FULL!" "!OUT!" >nul
|
||||
) else (
|
||||
echo Skipping hidden/dot path: !REL!
|
||||
)
|
||||
)
|
||||
|
||||
echo Done.
|
||||
pause
|
||||
@@ -0,0 +1,247 @@
|
||||
-- Process.lua by Egalware s.r.l. 2024/04/02
|
||||
-- Gestione calcolo disposizione e lavorazioni per Travi
|
||||
-- Si opera sulla macchina corrente
|
||||
-- 2024/04/02 PRIMA VERSIONE
|
||||
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
-- Imposto direttorio strategie. N.B. Le strategie dovranno essere caricate con il nome del direttorio padre
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\Strategies\\Standard\\?.lua')
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\StrategyLibs\\?.lua')
|
||||
|
||||
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not sMachDir then
|
||||
EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
EgtOutBox( 'La macchina corrente non è configurata per lavorare travi', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Segnalazione avvio
|
||||
EgtOutLog( '*** Beam Process Start ***', 1)
|
||||
|
||||
-- Carico le librerie
|
||||
_G.package.loaded.BasicCustomerStrategies = nil
|
||||
_G.package.loaded.BeamExec = nil
|
||||
_G.package.loaded.BeamLib = nil
|
||||
_G.package.loaded.DiceCut = nil
|
||||
_G.package.loaded.FaceData = nil
|
||||
_G.package.loaded.FeatureLib = nil
|
||||
_G.package.loaded.Identity = nil
|
||||
_G.package.loaded.Logs = nil
|
||||
_G.package.loaded.MachiningLib = nil
|
||||
_G.package.loaded.PreSimulationLib = nil
|
||||
_G.package.loaded.LeadInOutLib = nil
|
||||
-- strategie di base sempre presenti
|
||||
_G.package.loaded['HEADCUT\\HEADCUT'] = nil
|
||||
_G.package.loaded['TAILCUT\\TAILCUT'] = nil
|
||||
-- libreria macchina
|
||||
_G.package.loaded.BeamDataNew = nil
|
||||
-- libreria calcolo tempo esecuzione
|
||||
_G.package.loaded.TimeLib = nil
|
||||
|
||||
-- TODO controllare se c'è un modo migliore per resettare librerie delle strategie caricate precedentemente
|
||||
-- Per ottimizzare potremmo anche ciclare solo fino al numero di strategie raggiunto per il momento.
|
||||
-- Infatti difficile ci siano 9999 strategie.
|
||||
-- reset strategie caricate come librerie
|
||||
for i = 1, 9999 do
|
||||
local idSTRTemp = EgtReplaceString( EgtNumToString( i/10000, -4), '0.', '')
|
||||
local sLibraryToReload = "STR" .. idSTRTemp .. "\\STR" .. idSTRTemp
|
||||
if _G.package.loaded[sLibraryToReload] then
|
||||
_G.package.loaded[sLibraryToReload] = nil
|
||||
end
|
||||
end
|
||||
local vtCoreStrategiesNames = EgtFindAllFiles( BEAM.BASEDIR .. '\\StrategyLibs\\*.lua')
|
||||
for i = 1, #vtCoreStrategiesNames do
|
||||
local sCurrentName = EgtSplitString( vtCoreStrategiesNames[i], '.')[1]
|
||||
if _G.package.loaded[sCurrentName] then
|
||||
_G.package.loaded[sCurrentName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Variabili globali
|
||||
PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
-- carico librerie
|
||||
local BeamExec = require( 'BeamExec')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Recupero trave (E' SEMPRE E SOLO UNA) ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessInputData()
|
||||
-- Recupero il pezzo e i suoi dati
|
||||
local nId = EgtGetFirstPart()
|
||||
if nId then
|
||||
table.insert( PARTS, { nInd = #PARTS + 1, id = nId, sName = ( EgtGetName( nId) or ( 'Id=' .. tonumber( nId)))})
|
||||
local Ls = EgtGetFirstNameInGroup( PARTS[1].id, 'Box')
|
||||
local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
if not b3Solid then
|
||||
return false
|
||||
end
|
||||
PARTS[1].b3PartOriginal = b3Solid
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetDataConfig()
|
||||
-- recupero utensili dal magazzino
|
||||
BeamExec.GetToolsFromDB()
|
||||
-- TODO da gestire eventuali errori bloccanti
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Inserimento delle travi nel grezzo ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessBeams()
|
||||
-- Lunghezza totale delle travi
|
||||
local dLen = PARTS[1].b3PartOriginal:getDimX()
|
||||
local dRawW = PARTS[1].b3PartOriginal:getDimY()
|
||||
local dRawH = PARTS[1].b3PartOriginal:getDimZ()
|
||||
|
||||
-- Determinazione minimo grezzo scaricabile
|
||||
BeamExec.CalcMinUnloadableRaw( dRawW, dRawH)
|
||||
|
||||
local dOvmHead = BeamData.OVM_HEAD or 10
|
||||
local dOvmMid = BeamData.OVM_MID or 10
|
||||
|
||||
local dRawL = max( dLen + dOvmHead + dOvmMid, BeamData.dMinRaw)
|
||||
|
||||
-- Recupero info pezzi
|
||||
local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, true)
|
||||
if not bOk then
|
||||
EgtOutLog( sErr)
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Inserimento delle lavorazioni nelle travi ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessFeatures()
|
||||
|
||||
BeamExec.GetProcessings( PARTS, true)
|
||||
BeamExec.GetCombinationMatrix( PARTS, true)
|
||||
BeamExec.ProcessMachinings( PARTS, true)
|
||||
|
||||
-- scrittura variabili globali per interfaccia
|
||||
BEAM.PREROTATE90 = PARTS[1].nInitialPosition - 1
|
||||
BEAM.PREINVERT = EgtIf( PARTS[1].bPartInCombiIsInverted, 1, 0)
|
||||
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
local sOutput = ''
|
||||
for i = 1, #RESULT do
|
||||
local sMsg = ''
|
||||
if RESULT[i].sType == 'Feature' then
|
||||
sMsg = RESULT[i].ChosenStrategy.sInfo
|
||||
elseif RESULT[i].sType == 'Part' then
|
||||
sMsg = RESULT[i].sMsg
|
||||
end
|
||||
sMsg = string.gsub( sMsg or '', '\n', ' ', 10)
|
||||
sMsg = string.gsub( sMsg or '', '\r', ' ', 10)
|
||||
-- trovata almeno una strategia e feature lavorata completamente
|
||||
if RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Completed' then
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg or '')
|
||||
|
||||
-- trovata almeno una strategia ma nessuna applicabile oppure non trovata alcuna strategia
|
||||
elseif RESULT[i].sType == 'Feature'
|
||||
and ( ( RESULT[i].ChosenStrategy.sStatus == 'Not-Applicable')
|
||||
or ( not RESULT[i].ChosenStrategy.sStrategyName)) then
|
||||
|
||||
nErrCnt = nErrCnt + 1
|
||||
if #sMsg == 0 then
|
||||
sMsg = 'No applicable strategy found'
|
||||
end
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
else
|
||||
-- segnalazione scarico pezzo standard, incompleto o a caduta
|
||||
if RESULT[i].sType == 'Part' and ( RESULT[i].nErr == -100 or RESULT[i].nErr == -101 or RESULT[i].nErr == -102) then
|
||||
-- nulla da segnalare
|
||||
|
||||
-- feature incompleta e altro
|
||||
elseif RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Not-Completed' then
|
||||
nWarnCnt = nWarnCnt + 1
|
||||
sMsg = 'Incomplete : Completion index ' .. RESULT[i].ChosenStrategy.dCompletionIndex .. '/5\n' .. sMsg
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- si calcolano alternative
|
||||
TIMER:startElapsed('Alternatives')
|
||||
BeamExec.ProcessAlternatives( PARTS)
|
||||
TIMER:stopElapsed('Alternatives')
|
||||
|
||||
-- cancello gruppo temporaneo
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
EgtErase( idTempGroup)
|
||||
|
||||
if #sOutput > 0 then EgtOutLog( sOutput) end
|
||||
if nErrCnt > 0 then
|
||||
EgtOutBox( sOutput, 'Lavora Travi', 'ERRORS')
|
||||
return false
|
||||
elseif nWarnCnt > 0 then
|
||||
EgtOutBox( sOutput, 'Lavora Travi', 'WARNINGS')
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Esecuzione ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- calcolo tempo esecuzione
|
||||
TIMER:start()
|
||||
EgtOutLog( ' Execution timer started')
|
||||
|
||||
-- script principale
|
||||
|
||||
if not MyProcessInputData() then return end
|
||||
|
||||
-- recupero parametri generali da progetto
|
||||
BeamExec.GetGeneralParameters()
|
||||
|
||||
-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella
|
||||
BeamLib.CreateTempGroup()
|
||||
|
||||
if not MyProcessBeams() then return end
|
||||
|
||||
if not GetDataConfig() then return end
|
||||
|
||||
-- Abilito Vmill
|
||||
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
|
||||
|
||||
MyProcessFeatures()
|
||||
|
||||
-- log tempi di esecuzione
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
TIMER:logAllElapsed()
|
||||
end
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
-- GetWallData.lua by Egaltech s.r.l. 2022/06/28
|
||||
-- Recupero dati da file WallData.lua di macchina
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Per test
|
||||
--GWD = {}
|
||||
--GWD.MACHINE = 'Essetre-90480019_MW'
|
||||
|
||||
local sLog = 'GetBeamData : ' .. GWD.MACHINE
|
||||
EgtOutLog( sLog)
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( GWD.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
|
||||
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
GWD.ERR = 12
|
||||
GWD.MSG = 'Error not configured for beam machine : ' .. GWD.MACHINE
|
||||
WriteErrToLogFile( GWD.ERR, GWD.MSG)
|
||||
PostErrView( GWD.ERR, GWD.MSG)
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Carico i dati globali
|
||||
_G.package.loaded.BeamData = nil
|
||||
local BD = require( 'BeamDataNew')
|
||||
|
||||
-- Assegno valori di interesse
|
||||
GWD.SIMUL_VIEW_DIR = BD.SIMUL_VIEW_DIR
|
||||
GWD.OVM_MID = BD.OVM_MID
|
||||
|
||||
-- Tutto ok
|
||||
GWD.ERR = 0
|
||||
|
||||
EgtOutLog( ' +++ GetBeamData completed')
|
||||
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 528 B |
|
After Width: | Height: | Size: 479 B |
@@ -0,0 +1,762 @@
|
||||
--BasicCustomerStrategies.lua by Egalware s.r.l. 2024/04/02
|
||||
-- Libreria strategie di base disponibili per i clienti
|
||||
-- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local BasicCustomerStrategies = {}
|
||||
|
||||
-- Include
|
||||
require( 'EgtBase')
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local ID = require( 'Identity')
|
||||
|
||||
|
||||
|
||||
-- TODO tabella da compleatare man mano che si inseriscono le varie strategie
|
||||
-- ESEMPIO SCRITTURA TABELLA CON STRATEGIE DISPONIBILI
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Cut
|
||||
-- if ID.TipoFeature( Proc) then
|
||||
-- if Proc.Topology.sName == 'QQQQQQQQQ' then
|
||||
-- Strategies = {
|
||||
-- { sStrategyId = 'STR9999',
|
||||
-- Parameters = {
|
||||
-- { sName = 'Val_1', sValue = '15', sType = 'd'},
|
||||
-- { sName = 'Val_2', sValue = 'false', sType = 'b'}
|
||||
-- }
|
||||
-- }
|
||||
-- { sStrategyId = 'STR9998'}
|
||||
-- }
|
||||
-- end
|
||||
-- end
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- *** STRATEGIE ***
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- *** EGALWARE ***
|
||||
----------------------------------------------------------------------------------
|
||||
local function GetStrategies_Egalware( Proc)
|
||||
local Strategies = {}
|
||||
|
||||
local sFile = BEAM.BASEDIR .. '\\Strategies\\AvailableStrategyList.json'
|
||||
-- se non esiste file JSON, annullo la lista contenente le strategie
|
||||
if not EgtExistsFile( sFile) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local CompleteList = {}
|
||||
CompleteList.FEATURE = BeamLib.ImportFileJSON( sFile)
|
||||
|
||||
Strategies = BeamLib.GetStrategiesFromList( Proc, CompleteList)
|
||||
|
||||
-- si salva che la strategia è stata presa dallo standard
|
||||
if Strategies and #Strategies > 0 then
|
||||
Strategies.bIsBasicStrategy = true
|
||||
end
|
||||
|
||||
return Strategies
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- *** ESSETRE ***
|
||||
----------------------------------------------------------------------------------
|
||||
local function GetStrategies_Essetre( Proc)
|
||||
local Strategies = {}
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Cut (1-10)
|
||||
if ID.IsHeadCut( Proc) then
|
||||
Strategies = { { sStrategyId = 'HEADCUT'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Cut (2-10)
|
||||
elseif ID.IsTailCut( Proc) then
|
||||
Strategies = { { sStrategyId = 'TAILCUT'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Cut (1-10)
|
||||
elseif ID.IsCut( Proc) then
|
||||
if Proc.Topology.sName == 'Cut-1-Through' or Proc.Topology.sName == 'Bevel-1-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}}
|
||||
elseif Proc.Topology.sName == 'HeadCut' then
|
||||
Strategies = { { sStrategyId = 'HEADCUT'}}
|
||||
elseif Proc.Topology.sName == 'TailCut' then
|
||||
Strategies = { { sStrategyId = 'TAILCUT'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Longitudinal Cut (0-10)
|
||||
elseif ID.IsLongitudinalCut( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Double Cut (1-11)
|
||||
elseif ID.IsDoubleCut( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Ridge or Valley Cut (0-12)
|
||||
elseif ID.IsDoubleLongitudinalCut( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Saw Cut (0-13)
|
||||
elseif ID.IsSawCut( Proc) then
|
||||
if Proc.Topology.sName == 'Cut-1-Through' or Proc.Topology.sName == 'Bevel-1-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Slot (0-16)
|
||||
elseif ID.IsSlot( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Front Slot (0-17)
|
||||
elseif ID.IsFrontSlot( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Birds Mouth (0-20)
|
||||
elseif ID.IsBirdsMouth( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Hip or Valley Rafter Notch (0-25)
|
||||
elseif ID.IsHipValleyRafterNotch( Proc) then
|
||||
if Proc.Topology.sName == 'RafterNotch-5-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Ridge Lap (1-30)
|
||||
elseif ID.IsRidgeLap( Proc) then
|
||||
if Proc.Topology.sName == 'RidgeLap-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0012'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Cut-1-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0005'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Lap Joint (0-30)
|
||||
elseif ID.IsLapJoint( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Notch/Rabbet (0-32)
|
||||
elseif ID.IsNotchRabbet( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Block Haus (0-33)
|
||||
elseif ID.IsBlockHaus( Proc) then
|
||||
if Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Notch (0-32)
|
||||
elseif ID.IsNotch( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : French Ridge Lap (1-35)
|
||||
elseif ID.IsFrenchRidgeLap( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Chamfer (0-36)
|
||||
elseif ID.IsChamfer( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Block Haus Half Lap (0-37)
|
||||
elseif ID.IsHalfBlockHaus( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Block Haus Front (0-38)
|
||||
elseif ID.IsFrontBlockHaus( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Pocket (0-39)
|
||||
elseif ID.IsPocket( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Drilling (0-40)
|
||||
elseif ID.IsDrill( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0011'}, { sStrategyId = 'STR0013'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Tenon (1-50)
|
||||
elseif ID.IsTenon( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0006'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Mortise (0-50)
|
||||
elseif ID.IsMortise( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Pocket-Round' or Proc.Topology.sName == 'Pocket-Round-Front' or Proc.Topology.sName == 'Pocket-Round-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0008'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Front Mortise (0-51)
|
||||
elseif ID.IsFrontMortise( Proc) then
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0003'}, { sStrategyId = 'STR0004'}}
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}}
|
||||
elseif Proc.Topology.sName == 'Bevel-2-Blind' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0005'}, { sStrategyId = 'STR0010'}}
|
||||
elseif Proc.Topology.sName == 'Pocket-Round' or Proc.Topology.sName == 'Pocket-Round-Front' or Proc.Topology.sName == 'Pocket-Round-Through' then
|
||||
Strategies = { { sStrategyId = 'STR0008'}}
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : House (1-52)
|
||||
elseif ID.IsHouse( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : House Mortise (0-53)
|
||||
elseif ID.IsHouseMortise( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail Tenon (1-55)
|
||||
elseif ID.IsDovetailTenon( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0001'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail Mortise (0-55)
|
||||
elseif ID.IsDovetailMortise( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0007'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail Mortise Front (0-56)
|
||||
elseif ID.IsFrontDovetailMortise( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0007'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Marking (0-60)
|
||||
elseif ID.IsMarking( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0014'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Text (0-61)
|
||||
elseif ID.IsText( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0014'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Scarf Simple (1-70)
|
||||
elseif ID.IsScarfSimple( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Scarf Joint (1-71)
|
||||
elseif ID.IsScarfJoint( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Step Joint (1-80)
|
||||
elseif ID.IsStepJoint( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0010'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Step Joint Notch (0-80)
|
||||
elseif ID.IsStepJointNotch( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0002'}, { sStrategyId = 'STR0010'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Planing (0-90)
|
||||
elseif ID.IsPlaning( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Front Profile (0-100)
|
||||
elseif ID.IsFrontProfile( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0015'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Concave Profile (0-101)
|
||||
elseif ID.IsHeadConcaveProfile( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0015'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Convex Profile (0-102)
|
||||
elseif ID.IsHeadConvexProfile( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0015'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Cambered Profile (0-103)
|
||||
elseif ID.IsHeadCamberedProfile( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0015'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Round Arch (0-104)
|
||||
elseif ID.IsRoundArch( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0015'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Profile (0-106)
|
||||
elseif ID.IsHeadProfile( Proc) then
|
||||
Strategies = { { sStrategyId = 'STR0015'}}
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Sphere (0-107)
|
||||
elseif ID.IsSphere( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Triangle Cut (0-120)
|
||||
elseif ID.IsTriangleCut( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : TyroleanDovetail (0-136)
|
||||
elseif ID.IsTyroleanDovetail( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail (0-138)
|
||||
elseif ID.IsDovetail( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Free Contour (0-250)
|
||||
elseif ID.IsFreeContour( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Outline (0-251)
|
||||
elseif ID.IsOutline( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Aperture (0-252)
|
||||
elseif ID.IsAperture( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Variant (0-900)
|
||||
elseif ID.IsVariant( Proc) then
|
||||
---------------------------------------------------------------------
|
||||
end
|
||||
|
||||
-- si salva che la strategia è stata presa dallo script
|
||||
if #Strategies > 0 then
|
||||
Strategies.bIsBasicStrategy = true
|
||||
end
|
||||
|
||||
return Strategies
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- *** PARAMETRI ***
|
||||
----------------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------------
|
||||
-- *** ESSETRE ***
|
||||
----------------------------------------------------------------------------------
|
||||
-- funzione che recupera i parametri custom della strategia. Per cliente Essetre, vengono salvati dei valori 'Q' sul processing del file NGE per modificare il comportamento delle macro
|
||||
local function GetParameters_Essetre( Proc, sStrategyIdToGet)
|
||||
local Parameters = {}
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : HeadCut
|
||||
if ID.IsHeadCut( Proc) then
|
||||
-- Per Essetre non esiste il taglio di testa, quindi si leggono le variabili Q sul processing che coincide con il taglio di testa
|
||||
if sStrategyIdToGet == 'HEADCUT' then
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q06', 'd') or 0
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer', sValue = dDepthChamfer, sType = 'd'})
|
||||
local dCuttingStrategy = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q05', 'd') or 0
|
||||
local bForceChainSaw = dCuttingStrategy > 0
|
||||
table.insert( Parameters, { sName = 'bForceChainSaw', sValue = bForceChainSaw, sType = 'b'})
|
||||
local bFinishWithMill = dCuttingStrategy == 2
|
||||
table.insert( Parameters, { sName = 'bFinishWithMill', sValue = bFinishWithMill, sType = 'b'})
|
||||
end
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Cut (1-10)
|
||||
elseif ID.IsCut( Proc) then
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q06', 'd') or 0
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer', sValue = dDepthChamfer, sType = 'd'})
|
||||
local bForcePocketing = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q07', 'd') == 1
|
||||
-- tutte le strategie che non siano svuotatura, devono essere rimosse
|
||||
if bForcePocketing and sStrategyIdToGet ~= 'STR0002' then
|
||||
Parameters.bToRemove = true
|
||||
else
|
||||
if sStrategyIdToGet == 'STR0002' then
|
||||
-- non ci sono Q per questa strategia
|
||||
elseif sStrategyIdToGet == 'STR0005' then
|
||||
local dCuttingStrategy = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q04', 'd') or 0
|
||||
local sCuttingStrategy = EgtIf( dCuttingStrategy == 1, 'KEEP_WASTE_ATTACHED', 'AUTO')
|
||||
table.insert( Parameters, { sName = 'sCuttingStrategy', sValue = sCuttingStrategy, sType = 's'})
|
||||
end
|
||||
end
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Drill (1-40)
|
||||
elseif ID.IsDrill( Proc) then
|
||||
if sStrategyIdToGet == 'STR0011' then
|
||||
local dDepthPreHole = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q03', 'd') or 0) == 1
|
||||
table.insert( Parameters, { sName = 'dDepthPreHole', sValue = dDepthPreHole, sType = 'd'})
|
||||
elseif sStrategyIdToGet == 'STR0013' then
|
||||
local bOnlyContouring = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q01', 'd') or 0) == 1
|
||||
table.insert( Parameters, { sName = 'bOnlyContouring', sValue = bOnlyContouring, sType = 'b'})
|
||||
end
|
||||
local bDrillFromOneSide = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q02', 'd') or 0) == 1
|
||||
local sDrillingMode = EgtIf( bDrillFromOneSide, 'PREFER_ONE', 'AUTO')
|
||||
table.insert( Parameters, { sName = 'sDrillingMode', sValue = sDrillingMode, sType = 's'})
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Front Profile (0-100)
|
||||
elseif ID.IsFrontProfile( Proc) then
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q01', 'd') or 0
|
||||
local dOverMaterial = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q02', 'd') or 0
|
||||
local bOnlyChamfer = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q03', 'd') or 0) == 1
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer' , sValue = dDepthChamfer, sType = 'd'})
|
||||
table.insert( Parameters, { sName = 'bOnlyChamfer' , sValue = bOnlyChamfer, sType = 'b'})
|
||||
table.insert( Parameters, { sName = 'dOverMaterial' , sValue = dOverMaterial, sType = 'd'})
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Head Concave Profile (0-101)
|
||||
elseif ID.IsHeadConcaveProfile( Proc) then
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q01', 'd') or 0
|
||||
local dOverMaterial = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q02', 'd') or 0
|
||||
local bOnlyChamfer = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q04', 'd') or 0) == 1
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer' , sValue = dDepthChamfer, sType = 'd'})
|
||||
table.insert( Parameters, { sName = 'bOnlyChamfer' , sValue = bOnlyChamfer, sType = 'b'})
|
||||
table.insert( Parameters, { sName = 'dOverMaterial' , sValue = dOverMaterial, sType = 'd'})
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Head Convex Profile (0-102)
|
||||
elseif ID.IsHeadConvexProfile( Proc) then
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q02', 'd') or 0
|
||||
local dOverMaterial = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q04', 'd') or 0
|
||||
local bOnlyChamfer = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q01', 'd') or 0) == 1
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer' , sValue = dDepthChamfer, sType = 'd'})
|
||||
table.insert( Parameters, { sName = 'bOnlyChamfer' , sValue = bOnlyChamfer, sType = 'b'})
|
||||
table.insert( Parameters, { sName = 'dOverMaterial' , sValue = dOverMaterial, sType = 'd'})
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Head Cambered Profile (0-103)
|
||||
elseif ID.IsHeadCamberedProfile( Proc) then
|
||||
local sUpperFaceStrategy = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q01', 's') or '' -- Q01 = forza fresa
|
||||
sUpperFaceStrategy = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q02', 's') or sUpperFaceStrategy or 'AUTO' -- Q02 = forza lama (se entrambi attivi comanda la lama)
|
||||
table.insert( Parameters, { sName = 'sUpperFaceStrategy' , sValue = sUpperFaceStrategy, sType = 's'})
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q03', 'd') or 0
|
||||
local dOverMaterial = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q04', 'd') or 0
|
||||
local bOnlyChamfer = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q05', 'd') or 0) == 1
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer' , sValue = dDepthChamfer, sType = 'd'})
|
||||
table.insert( Parameters, { sName = 'bOnlyChamfer' , sValue = bOnlyChamfer, sType = 'b'})
|
||||
table.insert( Parameters, { sName = 'dOverMaterial' , sValue = dOverMaterial, sType = 'd'})
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Round Arch (0-104)
|
||||
elseif ID.IsRoundArch( Proc) then
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q03', 'd') or 0
|
||||
local dOverMaterial = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q01', 'd') or 0
|
||||
local dStripWidth = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q02', 'd') or 0)
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer' , sValue = dDepthChamfer, sType = 'd'})
|
||||
table.insert( Parameters, { sName = 'dStripWidth' , sValue = dStripWidth, sType = 'b'})
|
||||
table.insert( Parameters, { sName = 'dOverMaterial' , sValue = dOverMaterial, sType = 'd'})
|
||||
--###---###---###---###---###---###---###---###---###---###---###---###---###--
|
||||
-- Feature : Head Profile (0-106)
|
||||
elseif ID.IsHeadProfile( Proc) then
|
||||
local dDepthChamfer = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q01', 'd') or 0
|
||||
local dOverMaterial = EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q02', 'd') or 0
|
||||
local bOnlyChamfer = ( EgtGetInfo( Proc.id or GDB_ID.NULL, 'Q03', 'd') or 0) == 1
|
||||
table.insert( Parameters, { sName = 'dDepthChamfer' , sValue = dDepthChamfer, sType = 'd'})
|
||||
table.insert( Parameters, { sName = 'bOnlyChamfer' , sValue = bOnlyChamfer, sType = 'b'})
|
||||
table.insert( Parameters, { sName = 'dOverMaterial' , sValue = dOverMaterial, sType = 'd'})
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
return Parameters
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- funzione che verifica se un item è contenuto in lista
|
||||
local function Contains( List, Item)
|
||||
for _, value in ipairs( List) do
|
||||
if EgtStartsWith( Item, value) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- funzione che ritorna lista utensili presenti in lista compatibili con i tag passati
|
||||
local function GetToolsFromMachDataFile( MachiningDataList, TagListToGet)
|
||||
local ToolList = {}
|
||||
|
||||
if MachiningDataList and #MachiningDataList > 0 and #TagListToGet > 0 then
|
||||
for nIndex = 1, #MachiningDataList do
|
||||
-- se utensile attivo e compatibile con TAG
|
||||
if MachiningDataList[nIndex].On and Contains( TagListToGet, MachiningDataList[nIndex].Type) then
|
||||
-- se è nuova versione, prendo il tool
|
||||
if MachiningDataList[nIndex].Tool then
|
||||
table.insert( ToolList, { sName = MachiningDataList[nIndex].Tool})
|
||||
-- altrimenti dalla lavorazione si ricava il tool
|
||||
elseif MachiningDataList[nIndex].Name then
|
||||
if EgtMdbSetCurrMachining( MachiningDataList[nIndex].Name) then
|
||||
table.insert( ToolList, { sName = EgtMdbGetCurrMachiningParam( MCH_MP.TOOL)})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return ToolList
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO da completare
|
||||
-- funzione che recupera gli utensili disponibili per un certo tipo di lavorazione
|
||||
local function GetTools_Essetre( Proc, sMachiningCategory)
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
local TagList = {}
|
||||
local ToolList = {}
|
||||
|
||||
-- CATEGORIE PREVISTE :
|
||||
-- Cutting
|
||||
-- Drill
|
||||
-- Milling, MillingFinish, MillingAntiSplint, MillingChamfer
|
||||
-- Pocketing
|
||||
-- ChainSawing
|
||||
|
||||
if sMachiningCategory == 'Cutting' then
|
||||
if EgtExistsFile( sMachDir .. '\\Beam\\CutData.lua') then
|
||||
local CutData = dofile( sMachDir .. '\\Beam\\CutData.lua')
|
||||
if ID.IsDoubleLongitudinalCut( Proc) or ID.IsLongitudinalCut( Proc) then
|
||||
TagList = { 'LongCut'}
|
||||
else
|
||||
TagList = { 'HeadSide', 'TailSide'}
|
||||
end
|
||||
ToolList = GetToolsFromMachDataFile( CutData, TagList)
|
||||
end
|
||||
elseif sMachiningCategory == 'Drilling' or ID.IsDrill( Proc) then
|
||||
if EgtExistsFile( sMachDir .. '\\Beam\\DrillData.lua') then
|
||||
local DrillData = dofile( sMachDir .. '\\Beam\\DrillData.lua')
|
||||
if sMachiningCategory == 'Pocketing' or sMachiningCategory == 'Milling' then
|
||||
TagList = { 'Pocket'}
|
||||
else
|
||||
TagList = { 'Drill', 'Predrill', 'AngleDrill', 'MultiDrill'}
|
||||
end
|
||||
ToolList = GetToolsFromMachDataFile( DrillData, TagList)
|
||||
end
|
||||
elseif sMachiningCategory == 'Milling' or sMachiningCategory == 'MillingFinish' or sMachiningCategory == 'MillingAntiSplint' or sMachiningCategory == 'MillingChamfer' or
|
||||
sMachiningCategory == 'MillingSmooth' then
|
||||
if EgtExistsFile( sMachDir .. '\\Beam\\MillingData.lua') then
|
||||
local MillingData = dofile( sMachDir .. '\\Beam\\MillingData.lua')
|
||||
-- si cercano TAG esclusivi
|
||||
if sMachiningCategory == 'MillingSmooth' then
|
||||
TagList = { 'Mark', 'Text', 'Decor01', 'CleanCorner'}
|
||||
elseif sMachiningCategory == 'MillingAntiSplint' then
|
||||
TagList = { 'AntiSplintMillCut'}
|
||||
elseif ID.IsTenon( Proc) then
|
||||
TagList = { 'Tenon'}
|
||||
elseif ID.IsDovetailTenon( Proc) then
|
||||
-- gestione passaggio di taglio tenone superiore in caso di P14>0. Si prendono le frese per tenone standard dato che serve fresa cilindrica
|
||||
if sMachiningCategory == 'MillingFinish' then
|
||||
TagList = { 'Tenon'}
|
||||
else
|
||||
TagList = { 'DtTenon'}
|
||||
end
|
||||
elseif ID.IsDovetailMortise( Proc) then
|
||||
TagList = { 'DtMortise'}
|
||||
elseif ID.IsFrontProfile( Proc) or ID.IsHeadConcaveProfile( Proc) or ID.IsHeadConvexProfile( Proc) or
|
||||
ID.IsHeadCamberedProfile( Proc) or ID.IsRoundArch( Proc) or ID.IsHeadProfile( Proc) then
|
||||
if sMachiningCategory == 'MillingFinish' then
|
||||
TagList = { 'Prof_end'}
|
||||
end
|
||||
if not TagList or #TagList == 0 then
|
||||
TagList = { 'Prof', 'Prof_end'}
|
||||
end
|
||||
elseif ID.IsFreeContour( Proc) then
|
||||
TagList = { 'FreeContour', 'Prof', 'Prof_end'}
|
||||
elseif ID.IsMarking( Proc) then
|
||||
TagList = { 'Mark'}
|
||||
elseif sMachiningCategory == 'MillingChamfer' then
|
||||
TagList = { 'Chamfer'}
|
||||
elseif ID.IsText( Proc) then
|
||||
TagList = { 'Text'}
|
||||
elseif ID.IsTyroleanDovetail( Proc) or ID.IsDovetail( Proc) then
|
||||
TagList = { 'ProfTCone', 'Long2Cut'}
|
||||
elseif ID.IsBirdsMouth( Proc) then
|
||||
TagList = { 'BirdsMouth'}
|
||||
elseif sMachiningCategory == 'MillingFinish' then
|
||||
TagList = { 'CleanCorner', 'SmallToolContour'}
|
||||
elseif ID.IsSlot( Proc) or ID.IsFrontSlot( Proc) or ID.IsLapJoint( Proc) or ID.IsNotchRabbet( Proc) or ID.IsNotch( Proc) or
|
||||
ID.IsPocket( Proc) or ID.IsMortise( Proc) or ID.IsFrontMortise( Proc) then
|
||||
TagList = { 'SideMillAsBlade', 'BHSideMill', 'Long2Cut', 'Long2CutDown', 'LongSmallCut', 'Long2CutSide'}
|
||||
elseif ID.IsDoubleLongitudinalCut( Proc) or ID.IsDoubleLongitudinalCut( Proc) then
|
||||
TagList = { 'Long2Cut', 'Long2CutDown', 'LongSmallCut', 'Long2CutSide'}
|
||||
end
|
||||
|
||||
ToolList = GetToolsFromMachDataFile( MillingData, TagList)
|
||||
end
|
||||
elseif sMachiningCategory == 'Pocketing' then
|
||||
if EgtExistsFile( sMachDir .. '\\Beam\\PocketingData.lua') then
|
||||
local PocketingData = dofile( sMachDir .. '\\Beam\\PocketingData.lua')
|
||||
-- si cercano TAG esclusivi
|
||||
if ID.IsMortise( Proc) then
|
||||
TagList = { 'Mortise'}
|
||||
else
|
||||
TagList = { 'Pocket', 'OpenPocket'}
|
||||
end
|
||||
ToolList = GetToolsFromMachDataFile( PocketingData, TagList)
|
||||
end
|
||||
elseif sMachiningCategory == 'ChainSawing' then
|
||||
if EgtExistsFile( sMachDir .. '\\Beam\\SawingData.lua') then
|
||||
local SawingData = dofile( sMachDir .. '\\Beam\\SawingData.lua')
|
||||
TagList = { 'Sawing', 'Mortising'}
|
||||
ToolList = GetToolsFromMachDataFile( SawingData, TagList)
|
||||
end
|
||||
end
|
||||
|
||||
return ToolList
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- *** Esecuzione ***
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
-- script delle strategie di base standard definito con cliente (statico e non modificabile)
|
||||
-- se non esiste JSON configurazione, o se non ha trovato nessuna strategia, prova a cercare in questi script
|
||||
function BasicCustomerStrategies.GetStrategiesFromBasicCustomerStrategies( Proc)
|
||||
local StrategiesFromScript = {}
|
||||
|
||||
-- CLIENTE : ESSETRE
|
||||
if EgtStartsWith( EgtGetCurrMachineName(), 'Essetre') then
|
||||
StrategiesFromScript = GetStrategies_Essetre( Proc)
|
||||
-- per tutti gli altri clienti, si carica standard di default EGALWARE
|
||||
else
|
||||
StrategiesFromScript = GetStrategies_Egalware( Proc)
|
||||
end
|
||||
|
||||
return StrategiesFromScript
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- lettura parametri che personalizzano le strategie. I parametri di default sono decisi con cliente
|
||||
function BasicCustomerStrategies.GetParametersFromBasicCustomerStrategies( Proc, sStrategyIdToGet)
|
||||
local ParametersFromScript = {}
|
||||
|
||||
-- CLIENTE : ESSETRE
|
||||
if EgtStartsWith( EgtGetCurrMachineName(), 'Essetre') then
|
||||
ParametersFromScript = GetParameters_Essetre( Proc, sStrategyIdToGet)
|
||||
else
|
||||
ParametersFromScript = nil
|
||||
end
|
||||
|
||||
return ParametersFromScript
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- funzione che riprocessa le strategie dopo che sono stati letti tutti i parmetri
|
||||
function BasicCustomerStrategies.UpdateStrategies( AvailableStrategies)
|
||||
-- se la strategia è settata come da rimuovere, la si toglie dalla lista
|
||||
for nIndexStrategy = #AvailableStrategies, 1, -1 do
|
||||
if AvailableStrategies[nIndexStrategy].bToRemove then
|
||||
table.remove( AvailableStrategies, nIndexStrategy)
|
||||
end
|
||||
end
|
||||
return AvailableStrategies
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------
|
||||
-- lettura utensili disponibili settati in lista machining data
|
||||
function BasicCustomerStrategies.GetToolsFromMachiningDataFile( Proc, sToolType)
|
||||
local ToolList = {}
|
||||
|
||||
-- CLIENTE : ESSETRE
|
||||
if EgtStartsWith( EgtGetCurrMachineName(), 'Essetre') then
|
||||
ToolList = GetTools_Essetre( Proc, sToolType)
|
||||
-- l'ordine di come le lavorazioni sono state in lista deve essere rispettato
|
||||
ToolList.bRespectListOrder = true
|
||||
-- per tutti gli altri si considerano tutti gli utensili a disposizione
|
||||
else
|
||||
ToolList = nil
|
||||
end
|
||||
|
||||
return ToolList
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return BasicCustomerStrategies
|
||||
@@ -0,0 +1,675 @@
|
||||
-- DiceCut.lua by Egalware s.r.l. 2024/01/23
|
||||
-- Gestione dei piano paralleli nei tagli lunghi: equidistanziamento dei piani paralleli
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local DiceCut = {}
|
||||
|
||||
-- Include
|
||||
require( 'EgtBase')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
EgtOutLog( ' DiceCut started', 1)
|
||||
|
||||
-- Dati
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- creo i piani paralleli
|
||||
-- GetParallelPlanes: restituisce un vettore con gli indici delle superfici
|
||||
-- idAddGroup: il layer
|
||||
-- b3BoxDicing: il grezzo della barra
|
||||
-- ptC: il punto centrale del piano della feature
|
||||
-- vtN: il versore normale del piano della feature
|
||||
-- nCopyPlane: 0 => genera una copia del piano passato, 1=> non genera una copia del piano passato
|
||||
-- dOffset: offset dei piani paralleli
|
||||
-- nStep: numero massimo di step
|
||||
-- Color: colre del fascio di piani
|
||||
-- dTolerance*: distanza tra i piani paralleli e i piani di taglio (se non esistono altre superfici può essere omesso)
|
||||
-- bNoTolOnFirstCut*: elimina la tolleranza per il primo piano del fascio (se non esistono altre superfici può essere omesso)
|
||||
-- ptCCut*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
-- vtNCut*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
-- ptCCut1*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
-- vtNCut1*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
local function GetParallelPlanes( idAddGroup, b3BoxDicing, ptC, vtN, nCopyPlane, dOffset, nStep, Color, dTolerance, bNoTolOnFirstCut, ptCCut, vtNCut, ptCCut1, vtNCut1 )
|
||||
local ptMyCCut
|
||||
local AreaMin = 5*5
|
||||
if ptCCut and vtNCut then
|
||||
if dTolerance then
|
||||
ptMyCCut = Point3d( ptCCut + dTolerance * vtNCut)
|
||||
end
|
||||
ptMyCCut = Point3d( ptCCut)
|
||||
end
|
||||
local ptMyCCut1
|
||||
if ptCCut1 and vtNCut1 then
|
||||
ptMyCCut1 = Point3d( ptCCut1 + 0 * vtNCut1)
|
||||
end
|
||||
local TabellaTmSurfParallel = {}
|
||||
local i = nCopyPlane
|
||||
while i < nStep do
|
||||
local SurfId = EgtSurfTmPlaneInBBox( idAddGroup, ptC + ( i * dOffset) * vtN, vtN, b3BoxDicing, GDB_RT.GLOB)
|
||||
local nFacet = EgtSurfTmFacetCount( SurfId or GDB_ID.NULL)
|
||||
if nFacet == 0 then
|
||||
-- se sono al primo taglio do una possibilità in più di girare
|
||||
if i > nCopyPlane then
|
||||
break
|
||||
end
|
||||
end
|
||||
if nFacet > 0 and vtNCut and ptMyCCut and EgtSurfArea(SurfId) > AreaMin then
|
||||
if i == nCopyPlane and bNoTolOnFirstCut then
|
||||
EgtCutSurfTmPlane( SurfId, ptCCut, -vtNCut, false, GDB_RT.GLOB)
|
||||
else
|
||||
EgtCutSurfTmPlane( SurfId, ptMyCCut, -vtNCut, false, GDB_RT.GLOB)
|
||||
end
|
||||
nFacet = EgtSurfTmFacetCount( SurfId)
|
||||
end
|
||||
if nFacet > 0 and vtNCut1 and ptMyCCut1 and EgtSurfArea(SurfId) > AreaMin then
|
||||
if i == nCopyPlane and bNoTolOnFirstCut then
|
||||
EgtCutSurfTmPlane( SurfId, ptCCut1, -vtNCut1, false, GDB_RT.GLOB)
|
||||
else
|
||||
EgtCutSurfTmPlane( SurfId, ptMyCCut1, -vtNCut1, false, GDB_RT.GLOB)
|
||||
end
|
||||
nFacet = EgtSurfTmFacetCount( SurfId)
|
||||
end
|
||||
if nFacet > 0 and EgtSurfArea(SurfId) > AreaMin then
|
||||
table.insert( TabellaTmSurfParallel, SurfId)
|
||||
--EgtSetColor( SurfId, Color)
|
||||
else
|
||||
EgtErase( SurfId)
|
||||
end
|
||||
if dOffset == 0 then
|
||||
break
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
return TabellaTmSurfParallel
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- GetOrderedCutTable:
|
||||
-- idAddGroup: il layer
|
||||
-- TabParallelPlanes: tabella delle superfici dei piani paralleli
|
||||
-- TabOrtoPlanes: tabella delle superfici dei piani ortogonali
|
||||
-- stampo l'ordine dei piani di taglio (prima tagli ortogonali piu' esterni poi taglio parallelo collettivo)
|
||||
local function GetOrderedCutTable( idAddGroup, TabParallelPlanes, TabOrtoPlanes)
|
||||
local StepParallel = #TabParallelPlanes
|
||||
local StepOrto = #TabOrtoPlanes
|
||||
local TabellaOrderParallelCut1 = {}
|
||||
|
||||
for IndexTmP=1, StepParallel do
|
||||
TabellaOrderParallelCut1[IndexTmP] = {}
|
||||
for IndexOrto=1, StepOrto do
|
||||
local ptOrtoN, vtNOrtoN = EgtSurfTmFacetCenter( TabOrtoPlanes[IndexOrto ], 0, GDB_ID.ROOT)
|
||||
local Copy1Id = EgtCopySurfTmFacet( TabParallelPlanes[IndexTmP], 0, idAddGroup)
|
||||
local Copy2Id = EgtCopySurfTmFacet( TabParallelPlanes[IndexTmP], 0, idAddGroup)
|
||||
if Copy1Id and ptOrtoN then
|
||||
EgtCutSurfTmPlane( Copy1Id, ptOrtoN, -vtNOrtoN, false, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( Copy2Id, ptOrtoN, vtNOrtoN, false, GDB_RT.GLOB)
|
||||
local nFacet1 = EgtSurfTmFacetCount( Copy1Id)
|
||||
local nFacet2 = EgtSurfTmFacetCount( Copy2Id)
|
||||
if nFacet1 < 1 then
|
||||
EgtErase( Copy1Id)
|
||||
EgtErase( Copy2Id)
|
||||
EgtCutSurfTmPlane( TabParallelPlanes[IndexTmP], ptOrtoN, vtNOrtoN, false, GDB_RT.GLOB)
|
||||
elseif nFacet2 < 1 then
|
||||
EgtErase( Copy1Id)
|
||||
EgtErase( Copy2Id)
|
||||
break
|
||||
else
|
||||
table.insert( TabellaOrderParallelCut1[IndexTmP], Copy1Id)
|
||||
EgtErase( Copy2Id)
|
||||
EgtCutSurfTmPlane( TabParallelPlanes[IndexTmP], ptOrtoN, vtNOrtoN, false, GDB_RT.GLOB)
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert(TabellaOrderParallelCut1[IndexTmP], TabParallelPlanes[IndexTmP])
|
||||
end
|
||||
return TabellaOrderParallelCut1
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- GetOrtoCutCenter:
|
||||
-- idFacet: l'id della faccia
|
||||
-- ptC: il punto centrale della faccia
|
||||
-- vtN: il versore normale della faccia
|
||||
-- vtO: il versore dei piani ortogonali
|
||||
-- dOffsetEff: offset della distanza dal punto centrale
|
||||
-- Verifica se l'asse X del box costruito sopra la superficie è più grande di un certo offset
|
||||
local function GetOrtoCutCenter( FacetId, ptC, vtN, vtO, dOffsetEff)
|
||||
local FrameLocal = Frame3d( EgtSurfTmFacetCenter( FacetId, 0, GDB_ID.ROOT))
|
||||
EgtSetGridFrame(FrameLocal)
|
||||
local IdAuxLocal = EgtGroup(EgtGetParent( FacetId), FrameLocal)
|
||||
EgtSetName( IdAuxLocal, "AuxLocal")
|
||||
local BoxLocal = EgtGetBBoxRef( FacetId, GDB_BB.STANDARD, FrameLocal)
|
||||
local ptS = EgtGP( EgtSurfTmBBox( IdAuxLocal, BoxLocal, GDB_RT.GRID), GDB_ID.ROOT)
|
||||
EgtErase( IdAuxLocal)
|
||||
EgtSetGridFrame(Frame3d())
|
||||
-- riferimento intrinseco
|
||||
local asseX = Vector3d( vtO)
|
||||
local asseY = vtN ^ asseX
|
||||
local Frame = Frame3d( ptC, ptC + asseX, ptC + asseY)
|
||||
-- ingombro della faccia secondo questo riferimento
|
||||
local Box = EgtGetBBoxRef( FacetId, GDB_BB.STANDARD, Frame)
|
||||
local dLen = Box:getDimX()
|
||||
local dWidth = Box:getDimY()
|
||||
|
||||
-- se faccia non troppo lunga, con un lato piccolo e non diretta troppo verso il basso, non servono dice
|
||||
-- TODO si può eliminare questo test dato che vengono verificate già volume e dimensione del cubetto??
|
||||
local dMaxLen = BeamData.MAX_LEN_DICE or 600
|
||||
if dLen < dMaxLen and dWidth < dMaxLen and
|
||||
( dLen < dOffsetEff + 1.0 or dWidth < dOffsetEff + 1.0) then
|
||||
return nil, nil, nil
|
||||
end
|
||||
|
||||
local N = ceil( dLen / dOffsetEff)
|
||||
local dOffsetRel = ( dLen / N) + 10 * GEO.EPS_SMALL
|
||||
local dCopyPlane
|
||||
local dCenOffs = ( Box:getMax():getX() + Box:getMin():getX()) / 2
|
||||
|
||||
if dLen <= dOffsetRel then
|
||||
dCopyPlane = 1
|
||||
elseif dLen <= 2 * dOffsetRel then
|
||||
dOffsetRel = dOffsetEff
|
||||
dCopyPlane = 0
|
||||
else
|
||||
if N % 2 == 0 then
|
||||
dCopyPlane = 0
|
||||
elseif N % 2 == 1 then
|
||||
dCopyPlane = 0.5
|
||||
end
|
||||
end
|
||||
|
||||
return dOffsetRel, dCopyPlane, dCenOffs, ptS
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- TableMesh:
|
||||
-- TableOrto: tabella delle superfici dei piani ortogonali
|
||||
-- TableParallel: tabella delle superfici dei piani paralleli
|
||||
-- Forma una tabella unica delle superfici di taglio inserendo strati di tagli ortogonali alternati da strati di taglio parallelo
|
||||
local function TableMesh( TableOrto, TableParallel)
|
||||
local TableUnited = {}
|
||||
for i=1, #TableOrto do
|
||||
table.insert( TableUnited, TableOrto[i])
|
||||
table.insert( TableUnited, TableParallel[i])
|
||||
end
|
||||
return TableUnited
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- FindValue:
|
||||
-- tab: tabella da scansionare
|
||||
-- val: valore da cercare
|
||||
-- Verifica se tab contiene val, a supporto della funzione SortOrtoCutsByNormalMethod
|
||||
local function FindValue( tab, val)
|
||||
for index, value in ipairs( tab) do
|
||||
if value == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- SortOrtoCutsByNormalMethod:
|
||||
-- TabParallelPlanes: tabella delle superfici dei piani paralleli
|
||||
-- TabOrtoPlanes: tabella delle superfici dei piani ortogonali
|
||||
-- stampo l'ordine dei piani di taglio sfruttando il prodotto dei versori normali (prima tagli ortogonali piu' esterni poi taglio parallelo collettivo)
|
||||
local function SortOrtoCutsByNormalMethod( TabParallelPlanes, TabOrtoPlanes)
|
||||
-- tabella dei tagli ordinati
|
||||
local TabOrderOrtoCut = {}
|
||||
-- tabella ausiliaria dei dati inseriti nell'ordine
|
||||
local TabAux = {}
|
||||
-- ciclo di ordinamento
|
||||
local StepParallel = #TabParallelPlanes
|
||||
local StepOrto = #TabOrtoPlanes
|
||||
for IndexTmP=1, StepParallel do
|
||||
TabOrderOrtoCut[IndexTmP] = {}
|
||||
local ptParalN, vtNParalN = EgtSurfTmFacetCenter( TabParallelPlanes[IndexTmP][1], 0, GDB_ID.ROOT)
|
||||
for IndexOrto=1, StepOrto do
|
||||
for i=1, #TabOrtoPlanes[IndexOrto] do
|
||||
-- identificativo del taglio
|
||||
local OrtoPlaneId = TabOrtoPlanes[IndexOrto][i]
|
||||
-- controlla che l'elemento da valutare non sia gia' stato inserito nella tabella
|
||||
if not FindValue( TabAux, OrtoPlaneId) then
|
||||
local ptOrtoN, vtNOrtoN = EgtSurfTmFacetCenter( OrtoPlaneId, 0, GDB_ID.ROOT)
|
||||
local scalarProduct = ( ptOrtoN - ptParalN) * vtNParalN
|
||||
if scalarProduct > 0 then
|
||||
table.insert( TabOrderOrtoCut[IndexTmP], OrtoPlaneId)
|
||||
table.insert( TabAux, OrtoPlaneId)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- cancello dal DB geometrico i tagli non inseriti
|
||||
for IndexOrto=1, StepOrto do
|
||||
for i=1, #TabOrtoPlanes[IndexOrto] do
|
||||
-- identificativo del taglio
|
||||
local OrtoPlaneId = TabOrtoPlanes[IndexOrto][i]
|
||||
-- ricerco il taglio tra gli inseriti
|
||||
if not FindValue( TabAux, OrtoPlaneId) then
|
||||
EgtErase( OrtoPlaneId)
|
||||
end
|
||||
end
|
||||
end
|
||||
return TabOrderOrtoCut
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- VerifyFirstOrthoCut :
|
||||
-- CutTable: tabella dei tagli
|
||||
-- dOffsetParallel: offset della distanza dal punto centrale
|
||||
-- b3BoxDicing: il grezzo della barra
|
||||
-- Verifica se l'asse X del box costruito sopra le 2 facce è più piccolo di un certo offset e quindi la faccia O è superflua
|
||||
local function VerifyFirstOrthoCut( CutTable, dOffsetParallel, b3BoxDicing)
|
||||
|
||||
if not CutTable[1] or not CutTable[2] then return end
|
||||
|
||||
local CutOId = CutTable[1][1]
|
||||
local Cut1Id = CutTable[2][1]
|
||||
local Cut2Id = CutTable[2][2]
|
||||
|
||||
if CutOId and Cut1Id and Cut2Id then
|
||||
-- centri e normali delle due semifacce
|
||||
local ptC1, vtN1 = EgtSurfTmFacetCenter( Cut1Id, 0, GDB_ID.ROOT)
|
||||
local ptC2, vtN2 = EgtSurfTmFacetCenter( Cut2Id, 0, GDB_ID.ROOT)
|
||||
-- normale alla faccia ortogonale
|
||||
local _, vtO = EgtSurfTmFacetCenter( CutOId, 0, GDB_ID.ROOT)
|
||||
vtO = vtO - vtO * vtN1 * vtN1 ; vtO:normalize()
|
||||
local dMaxElev = EgtSurfTmFacetElevationInBBox( CutOId, 0, b3BoxDicing, true, GDB_ID.ROOT)
|
||||
-- calcolo lunghezza prima semi-faccia
|
||||
local asseX1 = vtO
|
||||
local asseY1 = vtN1 ^ asseX1
|
||||
local Frame1 = Frame3d( ptC1, ptC1+asseX1, ptC1+asseY1)
|
||||
local Box1 = EgtGetBBoxRef( Cut1Id, GDB_BB.STANDARD, Frame1)
|
||||
local x1 = Box1:getDimX()
|
||||
-- prendo il massimo tra la lugnhezza della faccia parallela e l'elevazione della corrispondente ortogonale
|
||||
x1 = max( x1, dMaxElev)
|
||||
-- calcolo lunghezza seconda semi-faccia
|
||||
local asseX2 = vtO
|
||||
local asseY2 = vtN2 ^ asseX2
|
||||
local Frame2 = Frame3d( ptC2, ptC2+asseX2, ptC2+asseY2)
|
||||
local Box2 = EgtGetBBoxRef( Cut2Id, GDB_BB.STANDARD, Frame2)
|
||||
local x2 = Box2:getDimX()
|
||||
-- lunghezza totale faccia
|
||||
local dLongSize = x1 + x2
|
||||
-- se faccia piccola e non orientata verso il basso, elimino ortogonale e unisco le due parti
|
||||
if dLongSize <= dOffsetParallel + 1.0 then
|
||||
local idAddGroup = EgtGetParent( Cut1Id)
|
||||
local SurfId = EgtSurfTmBySewing( idAddGroup, { Cut1Id, Cut2Id})
|
||||
--EgtSetColor( SurfId, Color3d( FUCHSIA(), 60))
|
||||
EgtErase( CutOId)
|
||||
table.remove( CutTable[1], 1)
|
||||
table.remove( CutTable[2], 1)
|
||||
table.remove( CutTable[2], 1)
|
||||
table.insert( CutTable[2], 1, SurfId)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ricavo i vertici del box
|
||||
local function CalcolaPuntiEstremiBox( b3BoxDicing)
|
||||
local ptMin = b3BoxDicing:getMin()
|
||||
local ptMax = b3BoxDicing:getMax()
|
||||
local TBoxPoint = {}
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMin:getX(), ptMin:getY(), ptMin:getZ()), On = true})
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMax:getX(), ptMin:getY(), ptMin:getZ()), On = true})
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMin:getX(), ptMax:getY(), ptMin:getZ()), On = true})
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMax:getX(), ptMax:getY(), ptMin:getZ()), On = true})
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMin:getX(), ptMin:getY(), ptMax:getZ()), On = true})
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMax:getX(), ptMin:getY(), ptMax:getZ()), On = true})
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMin:getX(), ptMax:getY(), ptMax:getZ()), On = true})
|
||||
table.insert( TBoxPoint, { P = Point3d( ptMax:getX(), ptMax:getY(), ptMax:getZ()), On = true})
|
||||
return TBoxPoint
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- restituisce i punti che devono essere presi in considerazione per la costruzione del BoundingBox
|
||||
local function VerificaEstremiGrezzo( ptC, vtN, TPoint)
|
||||
for i = 1, #TPoint do
|
||||
if ( TPoint[i].P - ptC) * vtN < 0 then
|
||||
TPoint[i].On = false
|
||||
end
|
||||
end
|
||||
return TPoint
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- ricavo l'altezza del BoundingBox assegnati gli estremi del grezzo e la feature
|
||||
-- le funzioni commentate permettono di vedere la creazione di BoundingBox
|
||||
local function DistanzaMassima( idAddGroup, ptC1, vtN1, ptC2, vtN2, b3BoxDicing, TPoint)
|
||||
-- calcolo il riferimento nel piano 1
|
||||
local Frame1 = Frame3d( ptC1, vtN1)
|
||||
-- determino l'ingombro in questo riferimento della parte di trave compresa nel o nei piani
|
||||
local BB1 = BBox3d()
|
||||
-- punti di vertice della trave compresi
|
||||
for i = 1, #TPoint do
|
||||
if TPoint[i].On then
|
||||
local ptP = Point3d( TPoint[i].P)
|
||||
ptP:toLoc( Frame1)
|
||||
BB1:Add( ptP)
|
||||
end
|
||||
end
|
||||
-- eventuale altra faccia
|
||||
if ptC2 and vtN2 then
|
||||
local IdAux = EgtGroup( idAddGroup)
|
||||
local IdSurf2 = EgtSurfTmPlaneInBBox( IdAux, ptC2, vtN2, b3BoxDicing, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( IdSurf2, ptC1, -vtN1, false, GDB_RT.GLOB)
|
||||
if IdSurf2 then
|
||||
local BB2 = EgtGetBBoxRef( IdSurf2, GDB_BB.STANDARD, Frame1)
|
||||
BB1:Add( BB2)
|
||||
end
|
||||
EgtErase( IdAux)
|
||||
end
|
||||
if not BB1:isEmpty() then
|
||||
return ( BB1:getMax():getZ() + 0.1)
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- DiceCut.GetDice :
|
||||
-- nParent: il layer
|
||||
-- BBoxRawPart: il grezzo della barra
|
||||
-- ptCPlanes: il punto centrale del piano della feature
|
||||
-- vtNPlanes: il versore normale del piano della feature
|
||||
-- bGetOrtoPlanes*: se voglio calcolare i piani ortogonali al piano passato (se non esistono altre superfici può essere omesso)
|
||||
-- ptCBond*: il punto centrale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
-- vtNBond*: il versore normale della superfice limitante (se non esistono altre superfici può essere omesso)
|
||||
-- dOrthoMaxDim : massima profondità taglio se faccia singola perpendicolare facce laterali trave
|
||||
-- dCustMaxDimDice: dimensione massima customizzata, sostituisce il parametro BeamData.MAX_DIM_DICE (se negativa qualunque, se positiva deve stare nel MAX)
|
||||
-- bDownHead : taglio con testa da sotto
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- function DiceCut.GetDice( nParent, BBoxRawPart, ptCPlanes, vtNPlanes, bGetOrtoPlanes, ptCBond, vtNBond, dOrthoMaxDim, dCustMaxDimDice, bDownHead)
|
||||
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------
|
||||
-- DiceCut.GetDice :
|
||||
-- Part : pezzo
|
||||
-- Face1 : table. Contiene tutti i dati della faccia principale. Obbligatori i campi '.ptCenter' e '.vtN'
|
||||
-- Face2 : table. Contiene tutti i dati della faccia secondaria. Se non esiste, la table è vuota ({}). Se esiste, obbligatori i campi '.ptCenter' e '.vtN'
|
||||
-- OptionaParameters : eventuali parametri opzionali
|
||||
---------------------------------------------------------------------------------------------------------------
|
||||
function DiceCut.GetDice( Part, Face1, Face2, OptionalParameters)
|
||||
-- gruppo per geometria addizionale
|
||||
local idAddGroup
|
||||
if OptionalParameters.bSaveAddedGeometries then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
|
||||
-- faccia primaria
|
||||
local ptCMainFace
|
||||
local vtNMainFace
|
||||
if Face1.ptCenter and Face1.vtN then
|
||||
ptCMainFace = Point3d( Face1.ptCenter)
|
||||
vtNMainFace = Vector3d( Face1.vtN)
|
||||
end
|
||||
-- faccia secondaria; se non esiste, si forza il calcolo dei piani ortogonali
|
||||
local ptCSubordinateFace
|
||||
local vtNSubordinateFace
|
||||
local bGetOrtoPlanes
|
||||
if Face2.ptCenter and Face2.vtN then
|
||||
ptCSubordinateFace = Point3d( Face2.ptCenter)
|
||||
vtNSubordinateFace = Vector3d( Face2.vtN)
|
||||
bGetOrtoPlanes = false
|
||||
else
|
||||
bGetOrtoPlanes = true
|
||||
end
|
||||
|
||||
-- parametri opzionali e default
|
||||
-- box per dicing
|
||||
local b3BoxDicing = OptionalParameters.b3BoxDicing or Part.b3Part
|
||||
-- distanza tra piani paralleli
|
||||
local dOffsetParallel = OptionalParameters.dOffsetParallel or BeamData.MAX_DIM_DICE
|
||||
-- distanza tra piani ortogonali
|
||||
local dOffsetOrthogonal = OptionalParameters.dOffsetOrthogonal or BeamData.MAX_DIM_DICE
|
||||
-- numero massimo piani paralleli
|
||||
local nStepParallel = OptionalParameters.nStepParallel or 100
|
||||
-- numero massimo piani perpendicolari
|
||||
local nStepOrthogonal = OptionalParameters.nStepOrthogonal or 100
|
||||
-- distanza tra piani paralleli e piani di taglio (era sempre 0, serve???)
|
||||
local dTolerance = OptionalParameters.dTolerance or 0
|
||||
|
||||
--Ricavo le altezze dei BoundingBox contenente feature e estremi del grezzo
|
||||
local TBoxPoint = CalcolaPuntiEstremiBox( b3BoxDicing)
|
||||
TBoxPoint = VerificaEstremiGrezzo( ptCMainFace, vtNMainFace, TBoxPoint)
|
||||
if ptCSubordinateFace and vtNSubordinateFace then
|
||||
TBoxPoint = VerificaEstremiGrezzo( ptCSubordinateFace, vtNSubordinateFace, TBoxPoint)
|
||||
end
|
||||
local dElevP = DistanzaMassima( idAddGroup, ptCMainFace, vtNMainFace, ptCSubordinateFace, vtNSubordinateFace, b3BoxDicing, TBoxPoint)
|
||||
local dElevO
|
||||
if ptCSubordinateFace and vtNSubordinateFace and not AreOppositeVectorApprox( vtNSubordinateFace, vtNMainFace) then
|
||||
dElevO = DistanzaMassima( idAddGroup, ptCSubordinateFace, vtNSubordinateFace, ptCMainFace, vtNMainFace, b3BoxDicing, TBoxPoint)
|
||||
end
|
||||
|
||||
-- aggiungo piccolo extra agli offset
|
||||
dOffsetParallel = dOffsetParallel + 10 * GEO.EPS_SMALL
|
||||
dOffsetOrthogonal = dOffsetOrthogonal + 10 * GEO.EPS_SMALL
|
||||
|
||||
-- se piani non ortogonali, diminuisco la distanza di offset opportunamente
|
||||
local dOffsetParallelOriginal = dOffsetParallel
|
||||
if not bGetOrtoPlanes then
|
||||
local dCoeff = max( ( vtNMainFace ^ vtNSubordinateFace):len(), 0.5)
|
||||
dOffsetParallel = dOffsetParallel * dCoeff
|
||||
dOffsetOrthogonal = dOffsetOrthogonal * dCoeff
|
||||
end
|
||||
|
||||
local n = ceil( dElevP / dOffsetParallel)
|
||||
dOffsetParallel = dElevP / n
|
||||
if dElevO then
|
||||
local m = ceil( dElevO / dOffsetOrthogonal)
|
||||
dOffsetOrthogonal = dElevO / m
|
||||
end
|
||||
|
||||
-- elenco di tutte le superfici generate dai tagli
|
||||
local TabFUCHSIA = {}
|
||||
local TabGREEN = {}
|
||||
|
||||
-- PIANI PARALLELI alla faccia di taglio
|
||||
local TabellaTmSurfP = {}
|
||||
local TabFromIn = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCMainFace, vtNMainFace, 0, dOffsetParallel, nStepParallel, Color3d( FUCHSIA(), 60), dTolerance, true, ptCSubordinateFace, vtNSubordinateFace)
|
||||
for i = #TabFromIn, 1, -1 do
|
||||
table.insert( TabellaTmSurfP, TabFromIn[i])
|
||||
end
|
||||
|
||||
-- PIANI ORTOGONALI alla faccia di taglio
|
||||
-- orientamento definito da seconda faccia
|
||||
if not bGetOrtoPlanes then
|
||||
local TabellaTmSurfOrto = {}
|
||||
local TabFromIn = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCSubordinateFace, vtNSubordinateFace, 0, dOffsetOrthogonal, nStepOrthogonal, Color3d( GREEN(), 60), dTolerance, false, ptCMainFace, vtNMainFace)
|
||||
for i = #TabFromIn, 1, -1 do
|
||||
table.insert( TabellaTmSurfOrto, TabFromIn[i])
|
||||
end
|
||||
local TabellaOrderParallelCut = GetOrderedCutTable( idAddGroup, TabellaTmSurfP, TabellaTmSurfOrto) -- Ottiene la tabella dei tagli paralleli ordinati
|
||||
local TabellaOrderOrtoCut = GetOrderedCutTable( idAddGroup, TabellaTmSurfOrto, TabellaTmSurfP) -- Ottiene la tabella dei tagli ortogonali da riordinare per strato
|
||||
|
||||
TabGREEN = SortOrtoCutsByNormalMethod( TabellaOrderParallelCut, TabellaOrderOrtoCut) -- I tagli ortogonali vengono ordinati per strato
|
||||
TabFUCHSIA = TabellaOrderParallelCut -- I tagli paralleli sono già ordinati
|
||||
|
||||
-- orientamento da definire
|
||||
else
|
||||
for PlnInd = 1, #TabellaTmSurfP do
|
||||
-- piano interno
|
||||
local ptCInner, vtNInner = EgtSurfTmFacetCenter( TabellaTmSurfP[PlnInd], 0, GDB_ID.ROOT)
|
||||
-- eventuale piano esterno
|
||||
local ptCOuter, vtNOuter = nil, nil
|
||||
if PlnInd > 1 then
|
||||
ptCOuter, vtNOuter = EgtSurfTmFacetCenter( TabellaTmSurfP[PlnInd-1], 0, GDB_ID.ROOT)
|
||||
vtNOuter = -vtNOuter
|
||||
end
|
||||
-- calcolo la direzione dei piani ortogonali
|
||||
local vtO = VectorFromUprightOrtho( vtNInner)
|
||||
if vtNInner:getZ() > -0.0175 or abs( vtNInner:getY()) > 0.8 then
|
||||
vtO:rotate( vtNInner, 90)
|
||||
-- se diretto troppo ortogonalmente all'asse trave e taglio non da sotto, lo ruoto ulteriormente
|
||||
if ( abs( vtO:getY()) > 4 * abs( vtO:getX()) or b3BoxDicing:getDimZ() > 620) then
|
||||
vtO:rotate( vtNInner, 90)
|
||||
-- se faccia principale verso il basso (almeno -3deg), lo inverto per iniziare da sopra
|
||||
if vtNInner:getZ() < -0.05 then
|
||||
vtO = -vtO
|
||||
end
|
||||
else
|
||||
if vtNInner:getX() > -0.017 then
|
||||
if vtO:getX() < -0.001 then vtO = -vtO end
|
||||
else
|
||||
if vtO:getX() > 0.001 then vtO = -vtO end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- se quasi verticale (fino a 20 gradi di distanza) su faccia inclinata in Y, ruoto di 90 gradi
|
||||
if vtO:getZ() > 0.939 and abs( vtNInner:getY()) > 0.5 then
|
||||
vtO:rotate( vtNInner, 90)
|
||||
end
|
||||
-- calcolo le dimensioni dell'offset e dove posizionare la prima faccia:
|
||||
-- CopyPlane: 0 => crea la prima faccia direttamente sul punto passato
|
||||
-- CopyPlane: 1 => crea la prima faccia e tutte le altre con l'offset passato
|
||||
-- CopyPlane: 0.5 => crea la prima faccia a metà offset e tutte le altre con l'offest intero
|
||||
local OffsetRel, CopyPlane, dCenOffs, ptCStart = GetOrtoCutCenter( TabellaTmSurfP[PlnInd], ptCInner, vtNInner, vtO, dOffsetOrthogonal)
|
||||
|
||||
if OffsetRel and CopyPlane and dCenOffs then
|
||||
ptCInner = ptCInner + dCenOffs * vtO
|
||||
local TabRight = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCStart, vtO, CopyPlane, -OffsetRel, nStepOrthogonal, Color3d( GREEN(), 60),
|
||||
dTolerance, false, ptCInner, vtNInner, ptCOuter, vtNOuter)
|
||||
if CopyPlane == 0 then
|
||||
CopyPlane = 1
|
||||
end
|
||||
local TabLeft = GetParallelPlanes( idAddGroup, b3BoxDicing, ptCStart, vtO, CopyPlane, OffsetRel, nStepOrthogonal, Color3d( GREEN(), 60),
|
||||
dTolerance, false, ptCInner, vtNInner, ptCOuter, vtNOuter)
|
||||
-- carico la tabella con gli indici riordinati
|
||||
local TempOrtoTab = {}
|
||||
for i = #TabLeft, 1, -1 do
|
||||
table.insert( TempOrtoTab, TabLeft[i])
|
||||
end
|
||||
for i = 1, #TabRight do
|
||||
table.insert( TempOrtoTab, TabRight[i])
|
||||
end
|
||||
-- creo una tabella per ogni piano per generare i tagli sulla Inner
|
||||
local TempParTab = GetOrderedCutTable( idAddGroup, {TabellaTmSurfP[PlnInd]}, TempOrtoTab)
|
||||
for i = 1, #TempParTab do
|
||||
table.insert( TabFUCHSIA, TempParTab[i])
|
||||
end
|
||||
table.insert( TabGREEN, TempOrtoTab)
|
||||
else
|
||||
table.insert( TabFUCHSIA, {TabellaTmSurfP[PlnInd]})
|
||||
table.insert( TabGREEN, {})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Se sono state costruite non più di una faccia parallela e una faccia perpendicolare, allora non servono e tengo le originali
|
||||
if #TabGREEN == 1 and #TabGREEN[1] <= 1 and #TabFUCHSIA == 1 and #TabFUCHSIA[1] <= 1 then
|
||||
if #TabGREEN[1] == 1 then
|
||||
EgtErase( TabGREEN[1][1])
|
||||
end
|
||||
TabGREEN = {}
|
||||
if #TabFUCHSIA[1] == 1 then
|
||||
EgtErase( TabFUCHSIA[1][1])
|
||||
end
|
||||
TabFUCHSIA = {}
|
||||
end
|
||||
|
||||
-- Si uniscono le tabelle dei tagli ortogonali e paralleli in una sola tabella
|
||||
local UltimateTable = TableMesh( TabGREEN, TabFUCHSIA)
|
||||
|
||||
-- Se esiste la superficie limitante (nFacet == 2) verifica se il taglio più esterno è superfluo e quindi viene eliminato
|
||||
if not bGetOrtoPlanes then
|
||||
VerifyFirstOrthoCut( UltimateTable, dOffsetParallelOriginal, b3BoxDicing)
|
||||
-- se rimangono due sole facce, devono coincidere con le originali e quindi sono superflue
|
||||
if #UltimateTable == 2 and #UltimateTable[1] == 1 and #UltimateTable[2] == 1 then
|
||||
EgtErase( UltimateTable[1][1])
|
||||
EgtErase( UltimateTable[2][1])
|
||||
UltimateTable = {}
|
||||
end
|
||||
end
|
||||
|
||||
return UltimateTable
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
-- PrintOrderCut:
|
||||
-- TabellaOrderCut: tabella delle superfici di taglio
|
||||
-- stampo l'ordine dei piani di taglio ricevendo una tabella con gli strati parallelo/ortogonali già ordinati
|
||||
function DiceCut.PrintOrderCut( TabellaOrderCut)
|
||||
local Step = #TabellaOrderCut
|
||||
if Step > 0 then
|
||||
EgtOutLog( " L'ordine delle superfici da tagliare è il seguente:")
|
||||
else
|
||||
EgtOutLog( ' Non sono necessarie superfici aggiuntive di taglio.')
|
||||
end
|
||||
for i = 1, Step do
|
||||
if i % 2 == 1 then
|
||||
EgtOutLog( ' *** Strato di taglio ' .. EgtNumToString( ( i + 1) / 2, 0))
|
||||
if #TabellaOrderCut[i] > 0 then
|
||||
EgtOutLog( ' Tagli ortogonali: ')
|
||||
else
|
||||
EgtOutLog( ' Tagli ortogonali assenti')
|
||||
end
|
||||
else
|
||||
if #TabellaOrderCut[i] > 0 then
|
||||
EgtOutLog( ' Tagli paralleli: ')
|
||||
else
|
||||
EgtOutLog( ' Tagli paralleli assenti')
|
||||
end
|
||||
end
|
||||
for j=1, #TabellaOrderCut[i] do
|
||||
EgtOutLog( ' Indice faccia ' .. (TabellaOrderCut[i][j] or 0))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
local function DiceCutTest()
|
||||
|
||||
-- salvo l'indice del layer Trimesh selezionato
|
||||
local SelectedIndex = EgtGetFirstSelectedObj()
|
||||
-- verifico che sia selezionato un elemento
|
||||
if not SelectedIndex then return end
|
||||
|
||||
-- salvo l'indice del layer Processing
|
||||
local nAddGrpId = EgtGetParent( SelectedIndex)
|
||||
-- salvo l'indice del layer Part
|
||||
local nRawPart = EgtGetParent( nAddGrpId)
|
||||
local nBox = EgtGetFirstNameInGroup( nRawPart, 'Box')
|
||||
-- carico il bounding box della trave
|
||||
-- local b3BoxDicing = EgtGetBBoxGlob( nRawPart, GDB_BB.STANDARD )
|
||||
local b3BoxDicing = EgtGetBBoxGlob( nBox, GDB_BB.STANDARD )
|
||||
-- seleziono il Part e il Layer di destinazione
|
||||
EgtSetCurrPartLayer( nRawPart, nAddGrpId)
|
||||
|
||||
-- conto il numero di facce da processare
|
||||
local nFacet = EgtSurfTmFacetCount( SelectedIndex)
|
||||
EgtOutLog( ' Numero facce ' .. nFacet, 1)
|
||||
|
||||
-- salvo
|
||||
local TabPlanesFeatures = {}
|
||||
for i = 1, nFacet do
|
||||
local ptC, vtN = EgtSurfTmFacetCenter( SelectedIndex, i - 1, GDB_ID.ROOT)
|
||||
table.insert( TabPlanesFeatures, { ptC = ptC, vtN = vtN})
|
||||
end
|
||||
local ptC1 = Point3d( TabPlanesFeatures[1].ptC)
|
||||
local vtN1 = Vector3d( TabPlanesFeatures[1].vtN)
|
||||
|
||||
local CutTable = {}
|
||||
if nFacet == 1 then
|
||||
CutTable = DiceCut.GetDice( nAddGrpId, b3BoxDicing, ptC1, vtN1, true)
|
||||
elseif nFacet == 2 then
|
||||
CutTable = DiceCut.GetDice( nAddGrpId, b3BoxDicing, ptC1, vtN1, false, TabPlanesFeatures[2].ptC, TabPlanesFeatures[2].vtN)
|
||||
end
|
||||
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
DiceCut.PrintOrderCut( CutTable)
|
||||
end
|
||||
|
||||
EgtDeselectAll()
|
||||
|
||||
EgtDraw()
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
--DiceCutTest()
|
||||
|
||||
return DiceCut
|
||||
@@ -0,0 +1,738 @@
|
||||
-- FaceData.lua by Egalware s.r.l. 2024/04/18
|
||||
-- Libreria lettura o calcolo dati e proprietà delle facce di una trimesh
|
||||
-- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local FaceData = {}
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local Logs = require( 'Logs')
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- restituisce la matrice delle adiacenze di Proc dove i e j sono le facce e a(ij) è l'angolo tra di esse; 0 se nessuna adiacenza
|
||||
function FaceData.GetAdjacencyMatrix( Proc)
|
||||
local vAdj = {}
|
||||
|
||||
-- essendo la matrice simmetrica a diagonale nulla, ne calcolo solo la metà superiore
|
||||
for i = 1, Proc.nFct do
|
||||
vAdj[i] = {}
|
||||
for j = i + 1, Proc.nFct do
|
||||
_, _, _, vAdj[i][j] = EgtSurfTmFacetsContact( Proc.id, i - 1, j - 1, GDB_ID.ROOT)
|
||||
if not vAdj[i][j] then
|
||||
vAdj[i][j] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- riempio di conseguenza il resto della matrice
|
||||
for i = 1, Proc.nFct do
|
||||
vAdj[i][i] = 0
|
||||
for j = i + 1, Proc.nFct do
|
||||
vAdj[j][i] = vAdj[i][j]
|
||||
end
|
||||
|
||||
end
|
||||
return vAdj
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- restituisce un vettore con gli indici (0 based) delle facce triangolari (o quasi) di Proc
|
||||
function FaceData.GetTriangularFaces( Proc)
|
||||
-- se la feature ha una sola faccia, esco subito
|
||||
if Proc.nFct <= 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local vTriangularFaces = {}
|
||||
|
||||
for i = 1, Proc.nFct do
|
||||
if BeamLib.Is3EdgesApprox( Proc, i - 1) then
|
||||
table.insert( vTriangularFaces, i - 1)
|
||||
end
|
||||
|
||||
end
|
||||
return vTriangularFaces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetNotAdjacentFaces( Proc, idFace)
|
||||
local NotAdjacentFaces = {}
|
||||
|
||||
for i = 1, Proc.nFct do
|
||||
if Proc.Faces[i].id ~= idFace then
|
||||
local bIsAdjacent = false
|
||||
for j = 1, #Proc.Faces[idFace + 1].Adjacencies do
|
||||
if Proc.Faces[i].id == Proc.Faces[idFace + 1].Adjacencies[j] then
|
||||
bIsAdjacent = true
|
||||
end
|
||||
end
|
||||
if not bIsAdjacent then
|
||||
table.insert( NotAdjacentFaces, Proc.Faces[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return NotAdjacentFaces
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- restituisce una tabella che correla numero di adiacenze e id delle facce con quello stesso numero di adiacenze
|
||||
function FaceData.GetFacesByAdjacencyNumber( Proc)
|
||||
-- se la feature ha una sola faccia, esco subito
|
||||
if Proc.nFct <= 1 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local FacesByAdjacencyNumber = {}
|
||||
|
||||
for i = 1, 10 do
|
||||
FacesByAdjacencyNumber[i] = {}
|
||||
end
|
||||
for i = 1, Proc.nFct do
|
||||
if #Proc.Faces[i].Adjacencies > 0 then
|
||||
table.insert( FacesByAdjacencyNumber[#Proc.Faces[i].Adjacencies], Proc.Faces[i])
|
||||
end
|
||||
end
|
||||
|
||||
return FacesByAdjacencyNumber
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function FaceData.GetEdgesInfo( ProcOrId, idFace )
|
||||
local Edges = {}
|
||||
|
||||
-- disambiguazione feature vs id trimesh
|
||||
local Proc = {}
|
||||
if type( ProcOrId) == "table" then
|
||||
Proc = ProcOrId
|
||||
elseif type( ProcOrId) == "number" then
|
||||
Proc.id = ProcOrId
|
||||
else
|
||||
error( 'GetEdgesInfo : Only feature or trimesh supported')
|
||||
end
|
||||
|
||||
local nFaceType, EdgesEgt = EgtSurfTmGetFacetOutlineInfo( Proc.id, idFace, GDB_ID.ROOT)
|
||||
|
||||
for i = 1, #EdgesEgt do
|
||||
local nPreviousEdgeIndex = i - 1
|
||||
if i == 1 then
|
||||
nPreviousEdgeIndex = #EdgesEgt
|
||||
end
|
||||
local nNextEdgeIndex = i + 1
|
||||
if i == #EdgesEgt then
|
||||
nNextEdgeIndex = 1
|
||||
end
|
||||
|
||||
-- l'elevazione si tiene sempre positiva e la normale sempre diretta verso l'interno della faccia
|
||||
-- per sapere se il lato è aperto c'è la proprietà apposita bIsOpen
|
||||
local CurrentEdge = {}
|
||||
CurrentEdge.idAdjacentFace = EdgesEgt[i].Adj
|
||||
CurrentEdge.dLength = EdgesEgt[i].Len
|
||||
CurrentEdge.dElevation = abs( EdgesEgt[i].Elev)
|
||||
CurrentEdge.bIsOpen = EdgesEgt[i].Open
|
||||
CurrentEdge.vtN = Vector3d( EdgesEgt[i].Norm)
|
||||
if CurrentEdge.bIsOpen then
|
||||
CurrentEdge.vtN = -CurrentEdge.vtN
|
||||
end
|
||||
CurrentEdge.bIsStartOpen = EdgesEgt[nPreviousEdgeIndex].Open
|
||||
CurrentEdge.bIsEndOpen = EdgesEgt[nNextEdgeIndex].Open
|
||||
CurrentEdge.ptStart = Point3d( EdgesEgt[i].Start)
|
||||
CurrentEdge.ptEnd = Point3d( EdgesEgt[nNextEdgeIndex].Start)
|
||||
CurrentEdge.vtEdge = CurrentEdge.ptEnd - CurrentEdge.ptStart ; CurrentEdge.vtEdge:normalize()
|
||||
CurrentEdge.sType = 'Standard'
|
||||
CurrentEdge.id = i - 1
|
||||
|
||||
-- se nella Proc ci sono le adiacenze e il lato ha adiacenza, si salva l'angolo con la faccia adiacente
|
||||
if Proc.AdjacencyMatrix then
|
||||
if CurrentEdge.idAdjacentFace > -1 then
|
||||
CurrentEdge.dAdjacencyAngle = Proc.AdjacencyMatrix[idFace + 1][CurrentEdge.idAdjacentFace + 1]
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( Edges, CurrentEdge)
|
||||
end
|
||||
|
||||
return nFaceType, Edges
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function FaceData.GetFacesInfo( Proc, Part, FacesToGet)
|
||||
local Faces = {}
|
||||
|
||||
local function FaceIsToGet( nIndex)
|
||||
if not FacesToGet then return false end
|
||||
for i = 1, #FacesToGet do
|
||||
-- correggo indice perche' id delle facce è 0-based
|
||||
if FacesToGet[i] == nIndex - 1 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local vAdj
|
||||
if Proc.AdjacencyMatrix then
|
||||
vAdj = Proc.AdjacencyMatrix
|
||||
else
|
||||
vAdj = FaceData.GetAdjacencyMatrix( Proc)
|
||||
end
|
||||
|
||||
if not Proc.nFct then
|
||||
Proc.nFct = EgtSurfTmFacetCount( Proc.id) or 0
|
||||
end
|
||||
|
||||
for i = 1, Proc.nFct do
|
||||
Faces[i] = {}
|
||||
Faces[i].id = i - 1
|
||||
Faces[i].idTrimesh = Proc.id
|
||||
Faces[i].ptCenter, Faces[i].vtN = EgtSurfTmFacetCenter( Proc.id, i - 1, GDB_ID.ROOT)
|
||||
if Proc.nFct < 7 or FaceIsToGet( i) then
|
||||
-- frame OCS faccia
|
||||
Faces[i].frFrameHV = Frame3d( Faces[i].ptCenter, Faces[i].vtN)
|
||||
-- elevazione calcolata rispetto al box della parte
|
||||
Faces[i].dElevation = EgtSurfTmFacetElevationInBBox( Proc.id, i - 1, Part.b3Part, true, GDB_ID.ROOT)
|
||||
-- TODO qui sarebbe meglio l'area vera e non quella del rettangolo minimo
|
||||
local _, dLongDimension, dShortDimension = EgtSurfTmFacetMinAreaRectangle( Proc.id, i - 1, GDB_ID.ROOT)
|
||||
Faces[i].dArea = dShortDimension * dLongDimension
|
||||
Faces[i].dLMinRectangle = dLongDimension
|
||||
Faces[i].dWMinRectangle = dShortDimension
|
||||
-- volume approssimato di materiale asportato lavorando questa faccia
|
||||
Faces[i].dMachinedVolumeApprox = Faces[i].dArea * Faces[i].dElevation
|
||||
|
||||
local nFaceType, Edges = FaceData.GetEdgesInfo( Proc, i - 1)
|
||||
Faces[i].bIsOkForMachining = nFaceType < 1
|
||||
Faces[i].Edges = Edges
|
||||
|
||||
-- adiacenze della faccia
|
||||
-- TODO chiamarle in modo che si capisca che sono solo gli id e non l'intero oggetto faccia
|
||||
Faces[i].Adjacencies = {}
|
||||
for j = 1, Proc.nFct do
|
||||
if vAdj[i][j] and vAdj[i][j] ~= 0 and ( i ~= j) then
|
||||
table.insert( Faces[i].Adjacencies, j - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return Faces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function FaceData.IsFaceRectangle( Face)
|
||||
-- recupero gruppo per geometrie temporanee
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
|
||||
local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Face.idTrimesh, Face.id, idTempGroup)
|
||||
if nContourCnt > 1 then
|
||||
error( 'IsFaceRectangle : too many loops')
|
||||
end
|
||||
|
||||
local bIsRectangular = EgtCurveIsARectangle( nContourId)
|
||||
|
||||
return bIsRectangular
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function FaceData.IsFaceParallelogram( Face)
|
||||
-- recupero gruppo per geometrie temporanee
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
|
||||
local nContourId, nContourCnt = EgtExtractSurfTmFacetLoops( Face.idTrimesh, Face.id, idTempGroup)
|
||||
if nContourCnt > 1 then
|
||||
error( 'IsFaceParallelogram : too many loops')
|
||||
end
|
||||
|
||||
local bIsTrapezoid = EgtCurveIsATrapezoid( nContourId)
|
||||
local bIsRhomboid = false
|
||||
-- un parallelogramma è un trapezoide con i lati paralleli a due a due
|
||||
if bIsTrapezoid
|
||||
and AreOppositeVectorApprox( Face.Edges[1].vtN, Face.Edges[3].vtN)
|
||||
and AreOppositeVectorApprox( Face.Edges[2].vtN, Face.Edges[4].vtN) then
|
||||
|
||||
bIsRhomboid = true
|
||||
end
|
||||
|
||||
return bIsRhomboid
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareBottomFaces( FaceA, FaceB)
|
||||
local dMaxVolumeRelativeChange = 0.15
|
||||
-- si prende la faccia con volume lavorato maggiore
|
||||
if FaceA.dMachinedVolumeApprox > ( 1 + dMaxVolumeRelativeChange) * FaceB.dMachinedVolumeApprox + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif FaceB.dMachinedVolumeApprox > ( 1 + dMaxVolumeRelativeChange) * FaceA.dMachinedVolumeApprox + 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se volume lavorato simile, si prende la faccia con minore elevazione
|
||||
else
|
||||
if FaceA.dElevation < FaceB.dElevation - 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif FaceB.dElevation < FaceA.dElevation - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareEdgesBottomFace( EdgeA, EdgeB)
|
||||
-- prima i lati con facce adiacenti
|
||||
if ( EdgeA.idAdjacentFace > -1) and ( EdgeB.idAdjacentFace < 0) then
|
||||
return true
|
||||
elseif ( EdgeA.idAdjacentFace < 0) and ( EdgeB.idAdjacentFace > -1) then
|
||||
return false
|
||||
-- se entrambi con facce adiacenti, si sceglie quello convesso (non chiuso)
|
||||
else
|
||||
if EdgeA.bIsOpen and not ( EdgeB.bIsOpen) then
|
||||
return true
|
||||
elseif not ( EdgeA.bIsOpen) and EdgeB.bIsOpen then
|
||||
return false
|
||||
-- se entrambi aperti o entrambi chiusi, si sceglie quello più lungo
|
||||
else
|
||||
if EdgeA.dLength > EdgeB.dLength then
|
||||
return true
|
||||
elseif EdgeA.dLength < EdgeB.dLength then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO valutare refactoring per mettere i calcoli del tunnel in una funzione
|
||||
-- TODO creare le facce tunnel solo se non ci sono già. Verirficare all'inizio se già presente in AddGrpId e nel caso riferire all'id di quella esistente e ricalcolare solo le informazioni della faccia.
|
||||
-- TODO test iniziale replicato in GetMainFaces
|
||||
local function GetTunnelFaces( Proc, Part)
|
||||
local TunnelAddedFaces = {}
|
||||
|
||||
if not ( ( Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5)
|
||||
or ( Proc.nFct == 1 ) or Proc.Topology.sName == 'Bevel-2-Blind') then
|
||||
|
||||
error( 'GetTunnelFaces : Topology not implemented')
|
||||
end
|
||||
|
||||
-- direzione del tunnel
|
||||
local vtTunnelDirection = V_NULL()
|
||||
if Proc.nFct == 1 then
|
||||
local EdgesSortedByElevation = BeamLib.TableCopyDeep( Proc.Faces[1].Edges)
|
||||
table.sort( EdgesSortedByElevation, function (a, b) return a.dElevation > b.dElevation end )
|
||||
vtTunnelDirection = Proc.Faces[1].vtN ^ EdgesSortedByElevation[1].vtN
|
||||
else
|
||||
vtTunnelDirection = Proc.Faces[1].vtN ^ Proc.Faces[ Proc.Faces[1].Adjacencies[1] + 1].vtN
|
||||
end
|
||||
|
||||
-- centro del tunnel
|
||||
local frTunnel = Frame3d( Proc.Faces[1].ptCenter, vtTunnelDirection)
|
||||
local b3Tunnel = EgtGetBBoxRef( Proc.id, GDB_BB.STANDARD, frTunnel)
|
||||
local ptTunnelCenter = b3Tunnel:getCenter()
|
||||
ptTunnelCenter:toGlob( frTunnel)
|
||||
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Proc.idPart)
|
||||
if not nAddGrpId then
|
||||
-- TODO gestire meglio questo errore. Non conviene creare e verificare all'inizio se il gruppo esiste?
|
||||
EgtOutLog( 'Error : missing AddGroup')
|
||||
return TunnelAddedFaces
|
||||
end
|
||||
|
||||
-- faccia centrale
|
||||
local nMiddleTmId = EgtSurfTmPlaneInBBox( nAddGrpId, ptTunnelCenter, vtTunnelDirection, Part.b3Part, GDB_ID.ROOT)
|
||||
-- TODO se non si riesce a costruire la faccia bisogna dare errore o semplicemente non ritornarla??
|
||||
for i = 1, Proc.nFct do
|
||||
EgtCutSurfTmPlane( nMiddleTmId, Proc.Faces[i].ptCenter, -Proc.Faces[i].vtN, false, GDB_ID.ROOT)
|
||||
end
|
||||
|
||||
-- facce laterali
|
||||
local nLateralTmId = EgtCopyGlob( Proc.id, nAddGrpId) or GDB_ID.NULL
|
||||
EgtCutSurfTmPlane( nLateralTmId, ptTunnelCenter, -vtTunnelDirection, false, GDB_ID.ROOT)
|
||||
|
||||
-- unione facce
|
||||
-- TODO cambiare nome alla trimesh?? non contiene più solamente la faccia di mezzo
|
||||
TunnelAddedFaces.MiddleFaceTm = {}
|
||||
TunnelAddedFaces.MiddleFaceTm.id = EgtSurfTmBySewing( nAddGrpId, { nMiddleTmId, nLateralTmId}, true)
|
||||
|
||||
-- TODO c'è un modo più elegante per raccogliere le informazioni delle facce aggiunte
|
||||
TunnelAddedFaces.MiddleFaceTm.sType = 'Tunnel'
|
||||
TunnelAddedFaces.MiddleFaceTm.nFct = EgtSurfTmFacetCount( TunnelAddedFaces.MiddleFaceTm.id)
|
||||
TunnelAddedFaces.MiddleFaceTm.Faces = FaceData.GetFacesInfo( TunnelAddedFaces.MiddleFaceTm, Part)
|
||||
|
||||
return TunnelAddedFaces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetBottomFaces( Proc)
|
||||
local BottomFaces = {}
|
||||
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
return nil
|
||||
elseif not ( Proc.Topology.sFamily == 'Rabbet'
|
||||
or Proc.Topology.sFamily == 'VGroove'
|
||||
or Proc.Topology.sFamily == 'Groove'
|
||||
or Proc.Topology.sFamily == 'Pocket'
|
||||
or Proc.Topology.sFamily == 'Bevel'
|
||||
or Proc.Topology.sFamily == 'DoubleBevel'
|
||||
or Proc.Topology.sFamily == 'Cut'
|
||||
or Proc.Topology.sFamily == 'HeadCut'
|
||||
or Proc.Topology.sFamily == 'TailCut') then
|
||||
error( 'GetBottomFace : Topology not implemented')
|
||||
end
|
||||
|
||||
if Proc.nFct == 1 then
|
||||
return { Proc.Faces[1]}
|
||||
end
|
||||
|
||||
-- la faccia di fondo ha sempre Fct - 1 adiacenze, tranne caso speciale DoubleBevel con facce di chiusura triangolari
|
||||
local FacesByAdjacencyNumber = FaceData.GetFacesByAdjacencyNumber( Proc)
|
||||
if FacesByAdjacencyNumber then
|
||||
BottomFaces = FacesByAdjacencyNumber[ Proc.nFct - 1]
|
||||
-- caso speciale DoubleBevel
|
||||
if #BottomFaces == 0 then
|
||||
if Proc.nParts == 1 then
|
||||
BottomFaces = FacesByAdjacencyNumber[ Proc.nFct / 2]
|
||||
-- DoubleBevel composto da più parti
|
||||
else
|
||||
for i = #FacesByAdjacencyNumber, 1, -1 do
|
||||
if #FacesByAdjacencyNumber[i] > 0 then
|
||||
BottomFaces = FacesByAdjacencyNumber[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
-- se non sono state trovate facce di fondo significa che nessuna faccia ha adiacenze -> DoubleBevel-2
|
||||
if #BottomFaces == 0 then
|
||||
BottomFaces = Proc.Faces
|
||||
end
|
||||
end
|
||||
end
|
||||
-- si rimuovono le facce non adatte ad essere lavorate
|
||||
local nBottomFaces = #BottomFaces
|
||||
local nCurrentFace = 1
|
||||
while nCurrentFace <= nBottomFaces do
|
||||
if not BottomFaces[nCurrentFace].bIsOkForMachining then
|
||||
table.remove( BottomFaces, nCurrentFace)
|
||||
nBottomFaces = nBottomFaces - 1
|
||||
end
|
||||
nCurrentFace = nCurrentFace + 1
|
||||
end
|
||||
-- la BottomFace 1 è quella che permette di asportare il volume maggiore; nei casi ambigui si sceglie quella a minor elevazione
|
||||
table.sort( BottomFaces, CompareBottomFaces)
|
||||
end
|
||||
|
||||
if #BottomFaces == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
BottomFaces[1].sType = 'Bottom'
|
||||
|
||||
-- calcolo MainEdges implementato solo se 4 lati esatti
|
||||
if #BottomFaces[1].Edges ~= 4 then
|
||||
return BottomFaces
|
||||
end
|
||||
|
||||
BottomFaces[1].MainEdges = {}
|
||||
BottomFaces[1].MainEdges.LongEdges = {}
|
||||
BottomFaces[1].MainEdges.SideEdges = {}
|
||||
|
||||
local EdgesSorted = {}
|
||||
for i = 1, #BottomFaces[1].Edges do
|
||||
table.insert( EdgesSorted, {})
|
||||
EdgesSorted[#EdgesSorted].nIndex = i
|
||||
EdgesSorted[#EdgesSorted].dLength = BottomFaces[1].Edges[i].dLength
|
||||
EdgesSorted[#EdgesSorted].idAdjacentFace = BottomFaces[1].Edges[i].idAdjacentFace
|
||||
end
|
||||
table.sort( EdgesSorted, CompareEdgesBottomFace)
|
||||
local nFirstLongEdgeIndex
|
||||
if #EdgesSorted > 0 then
|
||||
nFirstLongEdgeIndex = EdgesSorted[1].nIndex
|
||||
end
|
||||
|
||||
for i = 1, #BottomFaces[1].Edges do
|
||||
local nPreviousEdgeIndex = i - 1
|
||||
if i == 1 then
|
||||
nPreviousEdgeIndex = #BottomFaces[1].Edges
|
||||
end
|
||||
local nNextEdgeIndex = i + 1
|
||||
if i == #BottomFaces[1].Edges then
|
||||
nNextEdgeIndex = 1
|
||||
end
|
||||
|
||||
local CurrentEdge = {}
|
||||
CurrentEdge.idAdjacentFace = BottomFaces[1].Edges[i].idAdjacentFace
|
||||
CurrentEdge.vtN = BottomFaces[1].Edges[i].vtN
|
||||
CurrentEdge.dLength = BottomFaces[1].Edges[i].dLength
|
||||
CurrentEdge.bIsOpen = BottomFaces[1].Edges[i].bIsOpen
|
||||
CurrentEdge.dElevation = BottomFaces[1].Edges[i].dElevation
|
||||
CurrentEdge.bIsStartOpen = BottomFaces[1].Edges[i].bIsStartOpen
|
||||
CurrentEdge.bIsEndOpen = BottomFaces[1].Edges[i].bIsEndOpen
|
||||
CurrentEdge.ptStart = BottomFaces[1].Edges[i].ptStart
|
||||
CurrentEdge.ptEnd = BottomFaces[1].Edges[i].ptEnd
|
||||
CurrentEdge.vtEdge = BottomFaces[1].Edges[i].vtEdge
|
||||
CurrentEdge.id = BottomFaces[1].Edges[i].id
|
||||
|
||||
if nFirstLongEdgeIndex then
|
||||
if i == nFirstLongEdgeIndex then
|
||||
BottomFaces[1].MainEdges.LongEdges[1] = CurrentEdge
|
||||
BottomFaces[1].MainEdges.LongEdges[1].sType = 'Long'
|
||||
elseif nNextEdgeIndex == nFirstLongEdgeIndex then
|
||||
BottomFaces[1].MainEdges.SideEdges[1] = CurrentEdge
|
||||
BottomFaces[1].MainEdges.SideEdges[1].sType = 'Side'
|
||||
elseif nPreviousEdgeIndex == nFirstLongEdgeIndex then
|
||||
BottomFaces[1].MainEdges.SideEdges[2] = CurrentEdge
|
||||
BottomFaces[1].MainEdges.SideEdges[2].sType = 'Side'
|
||||
else
|
||||
BottomFaces[1].MainEdges.LongEdges[2] = CurrentEdge
|
||||
BottomFaces[1].MainEdges.LongEdges[2].sType = 'Long'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return BottomFaces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetLongFaces( Proc, MainFaces)
|
||||
local LongFaces = {}
|
||||
|
||||
if Proc.nFct > 6 then
|
||||
error( 'GetLongFaces : Topology not implemented')
|
||||
elseif Proc.nFct == 1 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local BottomFace
|
||||
local BottomFaces = MainFaces.BottomFaces or GetBottomFaces( Proc)
|
||||
if BottomFaces and #BottomFaces > 0 then
|
||||
BottomFace = BottomFaces[1]
|
||||
end
|
||||
|
||||
local idFirstLongFace = GDB_ID.NULL
|
||||
local idSecondLongFace = GDB_ID.NULL
|
||||
if not BottomFace then
|
||||
local FacesSortedByGreatestArea = {}
|
||||
for i = 1, Proc.nFct do
|
||||
FacesSortedByGreatestArea[i] = {}
|
||||
FacesSortedByGreatestArea[i].id = Proc.Faces[i].id
|
||||
FacesSortedByGreatestArea[i].dArea = Proc.Faces[i].dArea
|
||||
end
|
||||
table.sort( FacesSortedByGreatestArea, function (a, b) return a.dArea > b.dArea end)
|
||||
idFirstLongFace = FacesSortedByGreatestArea[1].id
|
||||
local FacesNotAdjacent = GetNotAdjacentFaces( Proc, idFirstLongFace)
|
||||
idSecondLongFace = FacesNotAdjacent[1].id
|
||||
elseif BottomFace.MainEdges then
|
||||
if BottomFace.MainEdges.LongEdges[1].idAdjacentFace > -1 then
|
||||
idFirstLongFace = BottomFace.MainEdges.LongEdges[1].idAdjacentFace
|
||||
end
|
||||
if BottomFace.MainEdges.LongEdges[2].idAdjacentFace > -1 then
|
||||
idSecondLongFace = BottomFace.MainEdges.LongEdges[2].idAdjacentFace
|
||||
end
|
||||
end
|
||||
if idFirstLongFace > -1 and Proc.Faces[idFirstLongFace + 1].bIsOkForMachining then
|
||||
table.insert( LongFaces, Proc.Faces[idFirstLongFace + 1])
|
||||
end
|
||||
if idSecondLongFace > -1 and Proc.Faces[idSecondLongFace + 1].bIsOkForMachining then
|
||||
table.insert( LongFaces, Proc.Faces[idSecondLongFace + 1])
|
||||
end
|
||||
|
||||
for i = 1, #LongFaces do
|
||||
LongFaces[i].sType = 'Long'
|
||||
|
||||
-- calcolo MainEdges possibile solo se 4 lati esatti
|
||||
if #LongFaces[i].Edges ~= 4 then
|
||||
break
|
||||
end
|
||||
|
||||
LongFaces[i].MainEdges = {}
|
||||
LongFaces[i].MainEdges.SideEdges = {}
|
||||
LongFaces[i].MainEdges.OppositeEdges = {}
|
||||
|
||||
for j = 1, #LongFaces[i].Edges do
|
||||
local nPreviousEdgeIndex = j - 1
|
||||
if j == 1 then
|
||||
nPreviousEdgeIndex = #LongFaces[1].Edges
|
||||
end
|
||||
local nNextEdgeIndex = j + 1
|
||||
if j == #LongFaces[i].Edges then
|
||||
nNextEdgeIndex = 1
|
||||
end
|
||||
|
||||
local CurrentEdge = {}
|
||||
CurrentEdge.idAdjacentFace = LongFaces[i].Edges[j].idAdjacentFace
|
||||
CurrentEdge.vtN = LongFaces[i].Edges[j].vtN
|
||||
CurrentEdge.dLength = LongFaces[i].Edges[j].dLength
|
||||
CurrentEdge.bIsOpen = LongFaces[i].Edges[j].bIsOpen
|
||||
CurrentEdge.dElevation = LongFaces[i].Edges[j].dElevation
|
||||
CurrentEdge.bIsStartOpen = LongFaces[i].Edges[j].bIsStartOpen
|
||||
CurrentEdge.bIsEndOpen = LongFaces[i].Edges[j].bIsEndOpen
|
||||
CurrentEdge.ptStart = LongFaces[i].Edges[j].ptStart
|
||||
CurrentEdge.ptEnd = LongFaces[i].Edges[j].ptEnd
|
||||
CurrentEdge.vtEdge = LongFaces[i].Edges[j].vtEdge
|
||||
CurrentEdge.id = LongFaces[i].Edges[j].id
|
||||
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
if CurrentEdge.idAdjacentFace > -1 then
|
||||
table.insert( LongFaces[i].MainEdges.SideEdges, CurrentEdge)
|
||||
LongFaces[i].MainEdges.SideEdges[#LongFaces[i].MainEdges.SideEdges].sType = 'Side'
|
||||
else
|
||||
table.insert( LongFaces[i].MainEdges.OppositeEdges, CurrentEdge)
|
||||
LongFaces[i].MainEdges.OppositeEdges[#LongFaces[i].MainEdges.OppositeEdges].sType = 'Opposite'
|
||||
end
|
||||
else
|
||||
if CurrentEdge.idAdjacentFace == BottomFace.id then
|
||||
LongFaces[i].MainEdges.BottomEdge = CurrentEdge
|
||||
LongFaces[i].MainEdges.BottomEdge.sType = 'Bottom'
|
||||
elseif LongFaces[i].Edges[nNextEdgeIndex].idAdjacentFace == BottomFace.id then
|
||||
LongFaces[i].MainEdges.SideEdges[1] = CurrentEdge
|
||||
LongFaces[i].MainEdges.SideEdges[1].sType = 'Side'
|
||||
elseif LongFaces[i].Edges[nPreviousEdgeIndex].idAdjacentFace == BottomFace.id then
|
||||
LongFaces[i].MainEdges.SideEdges[2] = CurrentEdge
|
||||
LongFaces[i].MainEdges.SideEdges[2].sType = 'Side'
|
||||
else
|
||||
table.insert( LongFaces[i].MainEdges.OppositeEdges, CurrentEdge)
|
||||
LongFaces[i].MainEdges.OppositeEdges[#LongFaces[i].MainEdges.OppositeEdges].sType = 'Opposite'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return LongFaces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetSideFaces( Proc, MainFaces)
|
||||
local SideFaces = {}
|
||||
|
||||
if Proc.nFct > 6 then
|
||||
error( 'GetSideFaces : Topology not implemented')
|
||||
elseif Proc.nFct == 1 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local BottomFace
|
||||
local BottomFaces = MainFaces.BottomFaces or GetBottomFaces( Proc)
|
||||
if BottomFaces and #BottomFaces > 0 then
|
||||
BottomFace = BottomFaces[1]
|
||||
end
|
||||
local LongFaces = MainFaces.LongFaces or GetLongFaces( Proc, MainFaces)
|
||||
|
||||
local idFirstSideFace = GDB_ID.NULL
|
||||
local idSecondSideFace = GDB_ID.NULL
|
||||
if LongFaces[1] and LongFaces[1].MainEdges then
|
||||
if not LongFaces[1].MainEdges.SideEdges[1].bIsOpen then
|
||||
idFirstSideFace = LongFaces[1].MainEdges.SideEdges[1].idAdjacentFace
|
||||
end
|
||||
if not LongFaces[1].MainEdges.SideEdges[2].bIsOpen then
|
||||
idSecondSideFace = LongFaces[1].MainEdges.SideEdges[2].idAdjacentFace
|
||||
end
|
||||
end
|
||||
if idFirstSideFace > -1 and Proc.Faces[idFirstSideFace + 1].bIsOkForMachining then
|
||||
table.insert( SideFaces, Proc.Faces[idFirstSideFace + 1])
|
||||
SideFaces[#SideFaces].sType = 'Side'
|
||||
end
|
||||
if idSecondSideFace > -1 and Proc.Faces[idSecondSideFace + 1].bIsOkForMachining then
|
||||
table.insert( SideFaces, Proc.Faces[idSecondSideFace + 1])
|
||||
SideFaces[#SideFaces].sType = 'Side'
|
||||
end
|
||||
|
||||
for i = 1, #SideFaces do
|
||||
SideFaces[i].sType = 'Side'
|
||||
|
||||
-- calcolo MainEdges possibile solo se 4 lati esatti
|
||||
if #SideFaces[i].Edges ~= 4 then
|
||||
break
|
||||
end
|
||||
|
||||
SideFaces[i].MainEdges = {}
|
||||
SideFaces[i].MainEdges.LongEdges = {}
|
||||
SideFaces[i].MainEdges.OppositeEdges = {}
|
||||
|
||||
for j = 1, #SideFaces[i].Edges do
|
||||
local nPreviousEdgeIndex = j - 1
|
||||
if j == 1 then
|
||||
nPreviousEdgeIndex = #SideFaces[1].Edges
|
||||
end
|
||||
local nNextEdgeIndex = j + 1
|
||||
if j == #SideFaces[i].Edges then
|
||||
nNextEdgeIndex = 1
|
||||
end
|
||||
|
||||
local CurrentEdge = {}
|
||||
CurrentEdge.idAdjacentFace = SideFaces[i].Edges[j].idAdjacentFace
|
||||
CurrentEdge.vtN = SideFaces[i].Edges[j].vtN
|
||||
CurrentEdge.dLength = SideFaces[i].Edges[j].dLength
|
||||
CurrentEdge.bIsOpen = SideFaces[i].Edges[j].bIsOpen
|
||||
CurrentEdge.dElevation = SideFaces[i].Edges[j].dElevation
|
||||
CurrentEdge.bIsStartOpen = SideFaces[i].Edges[j].bIsStartOpen
|
||||
CurrentEdge.bIsEndOpen = SideFaces[i].Edges[j].bIsEndOpen
|
||||
CurrentEdge.ptStart = SideFaces[i].Edges[j].ptStart
|
||||
CurrentEdge.ptEnd = SideFaces[i].Edges[j].ptEnd
|
||||
CurrentEdge.vtEdge = SideFaces[i].Edges[j].vtEdge
|
||||
CurrentEdge.id = SideFaces[i].Edges[j].id
|
||||
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
if CurrentEdge.idAdjacentFace > -1 then
|
||||
table.insert( SideFaces[i].MainEdges.LongEdges, CurrentEdge)
|
||||
else
|
||||
table.insert( SideFaces[i].MainEdges.OppositeEdges, CurrentEdge)
|
||||
end
|
||||
else
|
||||
if CurrentEdge.idAdjacentFace == BottomFace.id then
|
||||
SideFaces[i].MainEdges.BottomEdge = CurrentEdge
|
||||
SideFaces[i].MainEdges.BottomEdge.sType = 'Bottom'
|
||||
elseif SideFaces[i].Edges[nNextEdgeIndex].idAdjacentFace == BottomFace.id then
|
||||
SideFaces[i].MainEdges.LongEdges[1] = CurrentEdge
|
||||
SideFaces[i].MainEdges.LongEdges[1].sType = 'Long'
|
||||
elseif SideFaces[i].Edges[nPreviousEdgeIndex].idAdjacentFace == BottomFace.id then
|
||||
SideFaces[i].MainEdges.LongEdges[2] = CurrentEdge
|
||||
SideFaces[i].MainEdges.LongEdges[2].sType = 'Long'
|
||||
else
|
||||
table.insert( SideFaces[i].MainEdges.OppositeEdges, CurrentEdge)
|
||||
SideFaces[i].MainEdges.OppositeEdges[#SideFaces[i].MainEdges.OppositeEdges].sType = 'Opposite'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return SideFaces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- recupero facce principali della feature, in base alla topologia
|
||||
-- TODO test iniziale replicato in GetTunnelFaces
|
||||
function FaceData.GetMainFaces( Proc, Part)
|
||||
|
||||
local MainFaces = {}
|
||||
|
||||
-- CASO 1 : Feature tipo LapJoint
|
||||
if Proc.Topology.sFamily == 'Rabbet' or Proc.Topology.sFamily == 'VGroove' or Proc.Topology.sFamily == 'Groove' or
|
||||
Proc.Topology.sFamily == 'Pocket' or Proc.Topology.sFamily == 'Tunnel' or Proc.Topology.sFamily == 'Bevel' or
|
||||
Proc.Topology.sFamily == 'DoubleBevel' or Proc.Topology.sFamily == 'Cut' or Proc.Topology.sFamily == 'HeadCut' or Proc.Topology.sFamily == 'TailCut' then
|
||||
|
||||
if Proc.nParts == 1 and ( ( Proc.Topology.bIsThrough and Proc.Topology.bAllRightAngles and Proc.nFct < 5)
|
||||
or ( Proc.nFct == 1) or Proc.Topology.sName == 'Bevel-2-Blind') then
|
||||
|
||||
MainFaces.TunnelAddedFaces = GetTunnelFaces( Proc, Part)
|
||||
end
|
||||
|
||||
MainFaces.BottomFaces = GetBottomFaces( Proc)
|
||||
if Proc.nParts == 1 then
|
||||
MainFaces.LongFaces = GetLongFaces( Proc, MainFaces)
|
||||
MainFaces.SideFaces = GetSideFaces( Proc, MainFaces)
|
||||
-- caso tipo DoubleBevel con facce separate
|
||||
else
|
||||
MainFaces.LongFaces = {}
|
||||
MainFaces.SideFaces = {}
|
||||
end
|
||||
|
||||
else
|
||||
MainFaces = nil
|
||||
end
|
||||
|
||||
return MainFaces
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
return FaceData
|
||||
@@ -0,0 +1,275 @@
|
||||
-- Identity.lua by Egalware s.r.l. 2024/04/02
|
||||
-- Libreria Riconoscimento della feature
|
||||
-- 2024/04/02 PRIMA VERSIONE CALCOLO LAVORAZIONI CON STRATEGIE
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local Identity = {}
|
||||
|
||||
---------------------------------------------------------------------
|
||||
------------------------ SPECIAL TOPOLOGY -------------------------
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Cut
|
||||
function Identity.IsHeadCut( Proc)
|
||||
return Identity.IsCut( Proc) and Proc.Topology.sName == 'HeadCut'
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Tail Cut
|
||||
function Identity.IsTailCut( Proc)
|
||||
return Identity.IsCut( Proc) and Proc.Topology.sName == 'TailCut'
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
------------------------ STANDARD FEATURES ------------------------
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Cut
|
||||
function Identity.IsCut( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 10)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Longitudinal Cut
|
||||
function Identity.IsLongitudinalCut( Proc)
|
||||
return (( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 10)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Double Cut
|
||||
function Identity.IsDoubleCut( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 11)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Ridge or Valley Cut
|
||||
function Identity.IsDoubleLongitudinalCut( Proc)
|
||||
return ( Proc.nGrp == 0 and Proc.nPrc == 12)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Saw Cut
|
||||
function Identity.IsSawCut( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 13)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Slot
|
||||
function Identity.IsSlot( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 16)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Front Slot
|
||||
function Identity.IsFrontSlot( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 17)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Birds Mouth
|
||||
function Identity.IsBirdsMouth( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 20)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Hip or Valley Rafter Notch
|
||||
function Identity.IsHipValleyRafterNotch( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 25)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Ridge Lap
|
||||
function Identity.IsRidgeLap( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 30)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Lap Joint
|
||||
function Identity.IsLapJoint( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 30)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Notch/Rabbet
|
||||
function Identity.IsNotchRabbet( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 32)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Block Haus
|
||||
function Identity.IsBlockHaus( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 33)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Notch
|
||||
function Identity.IsNotch( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 34)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : French Ridge Lap
|
||||
function Identity.IsFrenchRidgeLap( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 35)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Chamfer
|
||||
function Identity.IsChamfer( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 36)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Block Haus Half Lap
|
||||
function Identity.IsHalfBlockHaus( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 37)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Block Haus Front
|
||||
function Identity.IsFrontBlockHaus( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 38)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Pocket
|
||||
function Identity.IsPocket( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 39)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Drilling
|
||||
function Identity.IsDrill( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 40)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Tenon
|
||||
function Identity.IsTenon( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 50)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Mortise
|
||||
function Identity.IsMortise( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 50)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Front Mortise
|
||||
function Identity.IsFrontMortise( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 51)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : House
|
||||
function Identity.IsHouse( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 52)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : House Mortise
|
||||
function Identity.IsHouseMortise( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 53)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail Tenon
|
||||
function Identity.IsDovetailTenon( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 55)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail Mortise
|
||||
function Identity.IsDovetailMortise( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 55)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail Mortise Front
|
||||
function Identity.IsFrontDovetailMortise( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 56)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Marking
|
||||
function Identity.IsMarking( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 60)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Text
|
||||
function Identity.IsText( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 61)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Scarf Simple
|
||||
function Identity.IsScarfSimple( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 70)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Scarf Joint
|
||||
function Identity.IsScarfJoint( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 71)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Step Joint
|
||||
function Identity.IsStepJoint( Proc)
|
||||
return ( ( Proc.nGrp == 1 or Proc.nGrp == 2) and Proc.nPrc == 80)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Step Joint Notch
|
||||
function Identity.IsStepJointNotch( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 80)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Planing
|
||||
function Identity.IsPlaning( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 90)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Front Profile
|
||||
function Identity.IsFrontProfile( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 100)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Concave Profile
|
||||
function Identity.IsHeadConcaveProfile( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 101)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Convex Profile
|
||||
function Identity.IsHeadConvexProfile( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 102)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Cambered Profile
|
||||
function Identity.IsHeadCamberedProfile( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 103)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Round Arch
|
||||
function Identity.IsRoundArch( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 104)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Head Profile
|
||||
function Identity.IsHeadProfile( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 106)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Sphere
|
||||
function Identity.IsSphere( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 107)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Triangle Cut
|
||||
function Identity.IsTriangleCut( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 120)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : TyroleanDovetail
|
||||
function Identity.IsTyroleanDovetail( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 1 or Proc.nGrp == 2 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 136)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Dovetail
|
||||
function Identity.IsDovetail( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 1 or Proc.nGrp == 2 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 138)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Free Contour
|
||||
function Identity.IsFreeContour( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 250)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Outline
|
||||
function Identity.IsOutline( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 251)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Aperture
|
||||
function Identity.IsAperture( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 252)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature : Variant
|
||||
function Identity.IsVariant( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 1 or Proc.nGrp == 2 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 900)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
-- Feature Decor
|
||||
function Identity.IsDecor( Proc)
|
||||
return ( ( Proc.nGrp == 0 or Proc.nGrp == 3 or Proc.nGrp == 4) and Proc.nPrc == 959)
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
|
||||
return Identity
|
||||
@@ -0,0 +1,247 @@
|
||||
-- LeadInOutLib.lua by Egalware s.r.l. 2025/11/24
|
||||
-- Libreria stima collisioni per travi
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local LeadInOutLib = {}
|
||||
|
||||
-- Include
|
||||
require( 'EgtBase')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local FaceData = require( 'FaceData')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
EgtOutLog( ' LeadInOutLib started', 1)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetExtraAddLengthInclinedSides( Face, Edge)
|
||||
|
||||
-- se faccia rettangolare i lati sono tutti a 90deg, inutile fare conti
|
||||
if FaceData.IsFaceRectangle( Face) then
|
||||
return 0, 0
|
||||
end
|
||||
|
||||
local nPreviousEdgeIndex = Edge.id + 1 - 1
|
||||
if nPreviousEdgeIndex < 1 then
|
||||
nPreviousEdgeIndex = #Face.Edges
|
||||
end
|
||||
local nNextEdgeIndex = Edge.id + 1 + 1
|
||||
if nNextEdgeIndex > #Face.Edges then
|
||||
nNextEdgeIndex = 1
|
||||
end
|
||||
|
||||
local vtEdgePrevious = Face.Edges[nPreviousEdgeIndex].vtEdge
|
||||
local vtEdgeNext = Face.Edges[nNextEdgeIndex].vtEdge
|
||||
local dLengthEdgePrevious = Face.Edges[nPreviousEdgeIndex].dLength
|
||||
local dLengthEdgeNext = Face.Edges[nNextEdgeIndex].dLength
|
||||
|
||||
local dExtraPrevious = dLengthEdgePrevious * ( Edge.vtEdge * -vtEdgePrevious)
|
||||
local dExtraNext = dLengthEdgeNext * ( -Edge.vtEdge * vtEdgeNext)
|
||||
|
||||
return dExtraPrevious, dExtraNext
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetPerpendicularLeadInOutDirection( Face, Edge)
|
||||
|
||||
-- informazioni lati adiacenti
|
||||
local nCurrentEdgeIndex = Edge.id + 1
|
||||
local nPreviousEdgeIndex = ( nCurrentEdgeIndex == 1 and #Face.Edges) or nCurrentEdgeIndex - 1
|
||||
local nNextEdgeIndex = ( nCurrentEdgeIndex == #Face.Edges and 1) or nCurrentEdgeIndex + 1
|
||||
local EdgeNext = Face.Edges[nNextEdgeIndex]
|
||||
local EdgePrevious = Face.Edges[nPreviousEdgeIndex]
|
||||
|
||||
-- tra le direzioni dei due lati adiacenti, si sceglie la migliore da cui attaccare, ossia quella più vicina alla perpendicolare al lato di lavoro
|
||||
local dCosAngleStart = -EdgePrevious.vtEdge * Edge.vtN
|
||||
local dCosAngleEnd = EdgeNext.vtEdge * Edge.vtN
|
||||
local vtLeadInOut
|
||||
-- se le due direzioni sono entro i 5° scelgo quella a Z assoluta minore, altrimenti quella più vicino alla perpendicolare
|
||||
-- massima differenza scalare per variazione di 5deg: cos(0) - cos(0 + 5) = 1 - cos(5)
|
||||
local dScalarTolerance = 1 - 0.996
|
||||
if abs( dCosAngleStart - dCosAngleEnd) < dScalarTolerance then
|
||||
if abs( EdgePrevious.vtEdge:getZ()) < abs( EdgeNext.vtEdge:getZ()) then
|
||||
vtLeadInOut = Vector3d( -EdgePrevious.vtEdge)
|
||||
else
|
||||
vtLeadInOut = Vector3d( EdgeNext.vtEdge)
|
||||
end
|
||||
else
|
||||
if dCosAngleStart > dCosAngleEnd then
|
||||
vtLeadInOut = Vector3d( -EdgePrevious.vtEdge)
|
||||
else
|
||||
vtLeadInOut = Vector3d( EdgeNext.vtEdge)
|
||||
end
|
||||
end
|
||||
|
||||
return vtLeadInOut
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CalculateLeadInOutLength( ptToolCenter, vtNFace, b3Box, vtLeadInOut, Tool)
|
||||
|
||||
-- al momento gestita solo lama
|
||||
if not Tool.sFamily == 'SawBlade' then
|
||||
error(' Tool family not implemented')
|
||||
end
|
||||
|
||||
-- Box del pezzo espansi ortogonalmente alle tre direzioni canoniche X, Y e Z
|
||||
local b3BoxX = BBox3d( b3Box) ; b3BoxX:expand( 0, 1000, 1000)
|
||||
local b3BoxY = BBox3d( b3Box) ; b3BoxY:expand( 1000, 0, 1000)
|
||||
local b3BoxZ = BBox3d( b3Box) ; b3BoxZ:expand( 1000, 1000, 0)
|
||||
|
||||
-- si setta utensile lama per il controllo collisione
|
||||
EgtCAvSetSawTool( Tool.dThickness, Tool.dDiameter, Tool.dThickness, 0, 0)
|
||||
|
||||
-- calcolo distanza di cui retrarre con funzioni Tool Collision Avoidance
|
||||
local dLength = min( EgtCAvToolPosBox( ptToolCenter + Tool.dThickness * vtNFace, vtNFace, b3BoxX, vtLeadInOut),
|
||||
EgtCAvToolPosBox( ptToolCenter + Tool.dThickness * vtNFace, vtNFace, b3BoxY, vtLeadInOut),
|
||||
EgtCAvToolPosBox( ptToolCenter + Tool.dThickness * vtNFace, vtNFace, b3BoxZ, vtLeadInOut))
|
||||
|
||||
return dLength
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function LeadInOutLib.CalculateLeadInOut( sLeadInOutType, Parameters, OptionalParameters)
|
||||
|
||||
-- parametri obbligatori
|
||||
local Face = Parameters.Face
|
||||
local Edge = Parameters.Edge
|
||||
local Part = Parameters.Part
|
||||
local Tool = Parameters.Tool
|
||||
local dDepthToMachine = Parameters.dDepthToMachine
|
||||
|
||||
-- parametri opzionali
|
||||
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
||||
|
||||
local LeadInOut = {}
|
||||
local bIsStartClosed = not Edge.bIsStartOpen
|
||||
local bIsEndClosed = not Edge.bIsEndOpen
|
||||
|
||||
-- accorciamento per lati chiusi
|
||||
LeadInOut.dToolMarkLength = sqrt( dDepthToMachine * Tool.dDiameter - dDepthToMachine * dDepthToMachine)
|
||||
LeadInOut.dExtraAddLengthStart, LeadInOut.dExtraAddLengthEnd = GetExtraAddLengthInclinedSides( Face, Edge)
|
||||
-- allungamento per faccia singola (aperta in tutte le direzioni)
|
||||
LeadInOut.dAddedLengthOpenFace = BeamData.CUT_EXTRA
|
||||
|
||||
local LeadIn = {}
|
||||
local LeadOut = {}
|
||||
LeadIn.dStartAddLength = 0
|
||||
LeadOut.dEndAddLength = 0
|
||||
LeadIn.nType = MCH_MILL_LI.LINEAR
|
||||
LeadOut.nType = MCH_MILL_LI.LINEAR
|
||||
LeadIn.dPerpDistance = 0
|
||||
LeadOut.dPerpDistance = 0
|
||||
LeadIn.dTangentDistance = 0
|
||||
LeadOut.dTangentDistance = 0
|
||||
LeadIn.dElevation = 0
|
||||
LeadOut.dElevation = 0
|
||||
LeadIn.dCompLength = 0
|
||||
LeadOut.dCompLength = 0
|
||||
|
||||
-- calcolo allungamenti / accorciamenti
|
||||
if bIsStartClosed and bIsEndClosed then
|
||||
LeadIn.dStartAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthStart
|
||||
LeadOut.dEndAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthEnd
|
||||
elseif bIsStartClosed then
|
||||
LeadIn.dStartAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthStart
|
||||
-- eventuale correzione per accorciamento maggiore di larghezza tasca
|
||||
LeadOut.dEndAddLength = max( -LeadIn.dStartAddLength - Edge.dLength + 10 * BeamData.CUT_EXTRA, BeamData.CUT_EXTRA)
|
||||
elseif bIsEndClosed then
|
||||
LeadOut.dEndAddLength = -LeadInOut.dToolMarkLength - LeadInOut.dExtraAddLengthEnd
|
||||
-- eventuale correzione per accorciamento maggiore di larghezza tasca
|
||||
LeadIn.dStartAddLength = max( -LeadOut.dEndAddLength - Edge.dLength + 10 * BeamData.CUT_EXTRA, BeamData.CUT_EXTRA)
|
||||
else
|
||||
LeadIn.dStartAddLength = LeadInOut.dAddedLengthOpenFace
|
||||
LeadOut.dEndAddLength = LeadInOut.dAddedLengthOpenFace
|
||||
end
|
||||
|
||||
-- calcolo punti notevoli della lavorazione
|
||||
-- punti di inizio e fine lavorazione alla profondità di lavoro reale, considerando allungamenti/accorciamenti
|
||||
local ptStartAtDepth = Edge.ptStart - Edge.vtEdge * LeadIn.dStartAddLength + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
local ptEndAtDepth = Edge.ptEnd + Edge.vtEdge * LeadOut.dEndAddLength + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
-- punti in centro lama
|
||||
local ptStartBladeCenter = ptStartAtDepth + Edge.vtN * Tool.dDiameter / 2
|
||||
local ptEndBladeCenter = ptEndAtDepth + Edge.vtN * Tool.dDiameter / 2
|
||||
|
||||
-- box per calcolo uscita lama
|
||||
-- se è un taglio di testa o coda va aggiunto il sovramateriale
|
||||
local b3BoxPartExpanded = BBox3d( Part.b3Part)
|
||||
if bCannotSplitRestLength then
|
||||
b3BoxPartExpanded = BeamLib.GetPartBoxWithHeadTail( Part, sRestLengthSideForPreSimulation)
|
||||
end
|
||||
-- il box si espande in tutte le direzioni per contemplare la sicurezza CUT_SIC
|
||||
b3BoxPartExpanded:expand( BeamData.CUT_SIC)
|
||||
|
||||
-- calcolo attacco scelto
|
||||
if sLeadInOutType == 'Perpendicular' then
|
||||
|
||||
-- scelta direzione migliore per l'attacco
|
||||
local vtLeadInOut = GetPerpendicularLeadInOutDirection( Face, Edge)
|
||||
|
||||
-- frame solidale al lato di lavoro (X lungo il lato, Y normale al lato)
|
||||
local frEdge = Frame3d( Edge.ptStart, Face.vtN, Edge.vtEdge)
|
||||
|
||||
-- direzione nel frame solidale al lato di lavoro
|
||||
local vtLeadInOuttLoc = Vector3d( vtLeadInOut)
|
||||
vtLeadInOuttLoc:toLoc( frEdge)
|
||||
|
||||
-- calcolo distanza per uscire dal box con questa lama nella direzione vtLeadInOut
|
||||
local dLeadInLength = CalculateLeadInOutLength( ptStartBladeCenter, Face.vtN, b3BoxPartExpanded, vtLeadInOut, Tool)
|
||||
local dLeadOutLength = CalculateLeadInOutLength( ptEndBladeCenter, Face.vtN, b3BoxPartExpanded, vtLeadInOut, Tool)
|
||||
|
||||
-- componenti dell'attacco
|
||||
LeadIn.dPerpDistance = dLeadInLength * vtLeadInOuttLoc:getY()
|
||||
LeadIn.dTangentDistance = dLeadInLength * -vtLeadInOuttLoc:getX()
|
||||
LeadOut.dPerpDistance = dLeadOutLength * vtLeadInOuttLoc:getY()
|
||||
LeadOut.dTangentDistance = dLeadOutLength * vtLeadInOuttLoc:getX()
|
||||
|
||||
-- punti dell'attacco
|
||||
LeadIn.ptPoint = Point3d( ptStartAtDepth + vtLeadInOut * dLeadInLength)
|
||||
LeadOut.ptPoint = Point3d( ptEndAtDepth + vtLeadInOut * dLeadOutLength)
|
||||
|
||||
elseif sLeadInOutType == 'Tangent' then
|
||||
|
||||
-- calcolo distanza per uscire dal box con questa lama nella direzione tangenziale
|
||||
local dLeadInLength = CalculateLeadInOutLength( ptStartBladeCenter, Face.vtN, b3BoxPartExpanded, -Edge.vtEdge, Tool)
|
||||
local dLeadOutLength = CalculateLeadInOutLength( ptEndBladeCenter, Face.vtN, b3BoxPartExpanded, Edge.vtEdge, Tool)
|
||||
|
||||
-- componenti dell'attacco
|
||||
LeadIn.dPerpDistance = 0
|
||||
LeadIn.dTangentDistance = dLeadInLength
|
||||
LeadOut.dPerpDistance = 0
|
||||
LeadOut.dTangentDistance = dLeadOutLength
|
||||
|
||||
-- punti dell'attacco
|
||||
LeadIn.ptPoint = Point3d( ptStartAtDepth - Edge.vtEdge * dLeadInLength)
|
||||
LeadOut.ptPoint = Point3d( ptEndAtDepth + Edge.vtEdge * dLeadOutLength)
|
||||
end
|
||||
|
||||
-- lunghezza totale attacco
|
||||
LeadIn.dTotalLength = sqrt( LeadIn.dPerpDistance ^ 2 + LeadIn.dTangentDistance ^ 2)
|
||||
LeadOut.dTotalLength = sqrt( LeadOut.dPerpDistance ^ 2 + LeadOut.dTangentDistance ^ 2)
|
||||
|
||||
LeadInOut.dTotalLength = LeadIn.dTotalLength + LeadOut.dTotalLength
|
||||
LeadInOut.LeadIn = LeadIn
|
||||
LeadInOut.LeadOut = LeadOut
|
||||
|
||||
return LeadInOut
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function LeadInOutLib.InvertLeadInOut( LeadIn, LeadOut)
|
||||
|
||||
local dOriginalStartAddLength = LeadIn.dStartAddLength
|
||||
local dOriginalEndAddLength = LeadOut.dEndAddLength
|
||||
|
||||
LeadIn, LeadOut = LeadOut, LeadIn
|
||||
|
||||
LeadIn.dStartAddLength = dOriginalEndAddLength
|
||||
LeadOut.dEndAddLength = dOriginalStartAddLength
|
||||
LeadIn.dEndAddLength = nil
|
||||
LeadOut.dStartAddLength = nil
|
||||
|
||||
return LeadIn, LeadOut
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
return LeadInOutLib
|
||||
@@ -0,0 +1,200 @@
|
||||
-- Logs.lua by Egalware s.r.l. 2024/11/20
|
||||
-- Libreria per logs vari
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local Logs = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function Logs.WriteFeaturesLog( ProcessingsOnPart, PartInfo, nReProcessCycles)
|
||||
|
||||
local nCycles = 1
|
||||
local nOffsetIndex = 0
|
||||
if #ProcessingsOnPart.Rotation > 4 then
|
||||
nCycles = 2
|
||||
end
|
||||
|
||||
EgtOutLog( ' === === === === === === === === === === REPROCESS CYCLES ' .. EgtNumToString( nReProcessCycles) .. ' === === === === === === === === === === === ===')
|
||||
EgtOutLog( ' === === === === === === === === === === FEATURES STRATEGIES === === === === === === === === === === === ===')
|
||||
for nCycle = 1, nCycles do
|
||||
local nStartIndex = 1 + nOffsetIndex
|
||||
local nEndIndex = 4 + nOffsetIndex
|
||||
EgtOutLog( ' === === === === === === === === === === === === === === === === === === === === === === === === === === ===')
|
||||
EgtOutLog( ' === === === === === === === === FEATURES STRATEGIES PIECE INVERTED === === === === === === === === === ===')
|
||||
EgtOutLog( ' Feature ID | BTL POSITION | 90 ROTATION | 180 ROTATION | 270 ROTATION |')
|
||||
EgtOutLog( '----------------------------------------------------------------------------------------------------------')
|
||||
|
||||
local nProcessingsNumber
|
||||
local nFirstAvailableRotation
|
||||
-- ricerco prima rotazione effettivamente calcolata. In genere è sempre la prima
|
||||
for i = nStartIndex, nEndIndex do
|
||||
if PartInfo.CombinationList.Rotations[i-nOffsetIndex] == 1 then
|
||||
nProcessingsNumber = #ProcessingsOnPart.Rotation[i]
|
||||
nFirstAvailableRotation = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- per ogni feature
|
||||
for ProcLog = 1, nProcessingsNumber do
|
||||
-- ricavo il massimo numero di strategie per feature
|
||||
local nMaxStrategiesPerFeature = 0
|
||||
for nRotLog = nStartIndex, nEndIndex do
|
||||
if PartInfo.CombinationList.Rotations[nRotLog-nOffsetIndex] == 1 and ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies then
|
||||
nMaxStrategiesPerFeature = max( nMaxStrategiesPerFeature, #ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies)
|
||||
end
|
||||
end
|
||||
|
||||
-- ciclo su tutte le strategie
|
||||
for nCountStrategies = 1, nMaxStrategiesPerFeature do
|
||||
local sLogLine = ''
|
||||
-- al primo ciclo scrivo ID feature
|
||||
if nCountStrategies == 1 then
|
||||
sLogLine = ' ' .. tostring( ProcessingsOnPart.Rotation[nFirstAvailableRotation][ProcLog].id)
|
||||
while string.len( sLogLine) <= 20 do
|
||||
sLogLine = sLogLine .. ' '
|
||||
end
|
||||
sLogLine = sLogLine .. '|'
|
||||
else
|
||||
sLogLine = ' |'
|
||||
end
|
||||
|
||||
for nRotLog = nStartIndex, nEndIndex do
|
||||
-- se rotazione abilitata
|
||||
if PartInfo.CombinationList.Rotations[nRotLog-nOffsetIndex] == 1 then
|
||||
-- se ci sono strategie
|
||||
if ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies and ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies] then
|
||||
-- se la strategia è stat processata e ha un risultato
|
||||
if ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result then
|
||||
-- leggo lo stato della strategia per aggiungere un suffisso
|
||||
local sStatusStrategy = ' '
|
||||
local sIndexes, sRating = '', ''
|
||||
if not ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sStatus or
|
||||
ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sStatus == 'Not-Applicable' then
|
||||
sStatusStrategy = 'N'
|
||||
sRating = '----'
|
||||
if EgtStartsWith( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sInfo, 'REJECTED') then
|
||||
sIndexes = ' ( --- REJECTED ---)'
|
||||
else
|
||||
sIndexes = ' (C:---|Q:---|T:---)'
|
||||
end
|
||||
else
|
||||
if ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sStatus == 'Completed' then
|
||||
sStatusStrategy = 'C'
|
||||
elseif ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.sStatus == 'Not-Completed' then
|
||||
sStatusStrategy = 'P'
|
||||
end
|
||||
sRating = EgtNumToString( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.dCompositeRating, -1)
|
||||
sIndexes = ' (C:'.. EgtNumToString( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.dCompletionIndex, -1)..
|
||||
'|Q:'.. EgtNumToString( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.dQuality, -1)..
|
||||
'|T:'.. EgtNumToString( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].Result.dTimeIndex, -1)..')'
|
||||
end
|
||||
-- se c'è una chosen strategy, si aggiunge prefisso '*' per indicare nel log qual è la strategia che è stata scelta
|
||||
local nIndexBestStrategy = ProcessingsOnPart.Rotation[nRotLog][ProcLog].nIndexBestStrategy or 0
|
||||
local sLogLineProc = EgtIf( nIndexBestStrategy == nCountStrategies, '*', '') .. sRating .. sIndexes .. ' (' ..
|
||||
tostring( ProcessingsOnPart.Rotation[nRotLog][ProcLog].AvailableStrategies[nCountStrategies].sStrategyId) .. ')' ..
|
||||
sStatusStrategy .. ' |'
|
||||
while string.len( sLogLineProc) <= 38 do
|
||||
sLogLineProc = ' ' .. sLogLineProc
|
||||
end
|
||||
sLogLine = sLogLine .. sLogLineProc
|
||||
else
|
||||
sLogLine = sLogLine .. ' 0 (STR----)- |'
|
||||
end
|
||||
else
|
||||
sLogLine = sLogLine .. ' |'
|
||||
end
|
||||
-- rotazione non presa in considerazione
|
||||
else
|
||||
if nCountStrategies == 1 then
|
||||
sLogLine = sLogLine .. ' ---------- |'
|
||||
else
|
||||
sLogLine = sLogLine .. ' |'
|
||||
end
|
||||
end
|
||||
end
|
||||
EgtOutLog( sLogLine)
|
||||
end
|
||||
|
||||
end
|
||||
EgtOutLog( '----------------------------------------------------------------------------------------------------------')
|
||||
nOffsetIndex = 4
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function Logs.WriteCombinationLog( CombinationsList, BestCombination)
|
||||
EgtOutLog( ' === === === === === === === === === === COMBINATIONS === === === === === === ')
|
||||
EgtOutLog( ' COMBI (UNL) POS | RATING | COMPLETE | NO COMPL | NO EXEC | ROTATE |')
|
||||
EgtOutLog( '------------------------------------------------------------------------------')
|
||||
|
||||
for CombiLog = 1, #CombinationsList do
|
||||
local sPartPosition = EgtIf( CombinationsList[CombiLog].bPartInCombiIsInverted, 'INV', 'ORI')
|
||||
local sLogLine = ' ' .. CombinationsList[CombiLog].sBitIndexCombination .. ' (' .. CombinationsList[CombiLog].nUnloadPos .. ') ' .. sPartPosition .. ' |'
|
||||
-- rating
|
||||
local sOtherField = EgtNumToString( CombinationsList[CombiLog].dTotalRating, - 3) .. ' |'
|
||||
while string.len( sOtherField) <= 15 do
|
||||
sOtherField = ' ' .. sOtherField
|
||||
end
|
||||
sLogLine = sLogLine .. sOtherField
|
||||
-- completed
|
||||
sOtherField = tostring( CombinationsList[CombiLog].nComplete) .. ' |'
|
||||
while string.len( sOtherField) <= 11 do
|
||||
sOtherField = ' ' .. sOtherField
|
||||
end
|
||||
sLogLine = sLogLine .. sOtherField
|
||||
-- not completed
|
||||
sOtherField = tostring( CombinationsList[CombiLog].nNotComplete) .. ' |'
|
||||
while string.len( sOtherField) <= 11 do
|
||||
sOtherField = ' ' .. sOtherField
|
||||
end
|
||||
sLogLine = sLogLine .. sOtherField
|
||||
-- not executed
|
||||
sOtherField = tostring( CombinationsList[CombiLog].nNotExecute) .. ' |'
|
||||
while string.len( sOtherField) <= 11 do
|
||||
sOtherField = ' ' .. sOtherField
|
||||
end
|
||||
sLogLine = sLogLine .. sOtherField
|
||||
-- rotations
|
||||
sOtherField = tostring( CombinationsList[CombiLog].nRotations) .. ' |'
|
||||
while string.len( sOtherField) <= 11 do
|
||||
sOtherField = ' ' .. sOtherField
|
||||
end
|
||||
sLogLine = sLogLine .. sOtherField
|
||||
|
||||
EgtOutLog( sLogLine)
|
||||
end
|
||||
local sPartPosition = EgtIf( BestCombination.bPartInCombiIsInverted, 'INV', 'ORI')
|
||||
EgtOutLog( '------------------------------------------------------------------------------')
|
||||
EgtOutLog( ' BEST ROTATION : ' .. BestCombination.sBitIndexCombination .. ' (' .. BestCombination.nUnloadPos .. ') ' .. sPartPosition)
|
||||
EgtOutLog( '---------------------------')
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function Logs.WriteMainFacesLog( Proc, MainFaces)
|
||||
-- reset eventuali visualizzazioni facce a due colori
|
||||
EgtSurfTmResetTwoColors( Proc.id)
|
||||
|
||||
if MainFaces.BottomFaces then
|
||||
for i = 1, #MainFaces.BottomFaces do
|
||||
EgtOutLog( 'Bottom Face : ' .. MainFaces.BottomFaces[i].id)
|
||||
end
|
||||
-- colore differente per la faccia di fondo principale
|
||||
--EgtSurfTmSetFaceColor( Proc.id, MainFaces.BottomFaces[1].id, 1)
|
||||
end
|
||||
if MainFaces.LongFaces then
|
||||
for i = 1, #MainFaces.LongFaces do
|
||||
EgtOutLog( 'Long Face : ' .. MainFaces.LongFaces[i].id)
|
||||
end
|
||||
end
|
||||
if MainFaces.SideFaces then
|
||||
for i = 1, #MainFaces.SideFaces do
|
||||
EgtOutLog( 'Side Face : ' .. MainFaces.SideFaces[i].id)
|
||||
end
|
||||
end
|
||||
if MainFaces.TunnelAddedFaces then
|
||||
EgtOutLog( 'Middle Face (Trimesh): ' .. MainFaces.TunnelAddedFaces.MiddleFaceTm.id)
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------
|
||||
|
||||
return Logs
|
||||
@@ -0,0 +1,547 @@
|
||||
-- PreSimulationLib.lua by Egalware s.r.l. 2025/11/24
|
||||
-- Libreria stima collisioni per travi
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local PreSimulationLib = {}
|
||||
|
||||
-- Include
|
||||
require( 'EgtBase')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
|
||||
EgtOutLog( ' PreSimulationLib started', 1)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetMachineAxes()
|
||||
|
||||
local LinearAxes = {}
|
||||
local RotativeAxes = {}
|
||||
|
||||
-- si recuperano tutti gli assi, lineari e rotativi
|
||||
local AxesNames = EgtGetAllCurrAxesNames()
|
||||
for i = 1, #AxesNames do
|
||||
-- EgtGetAxisType restituisce vero se asse lineare, false se asse rotativo
|
||||
if EgtGetAxisType( AxesNames[i]) then
|
||||
LinearAxes[#LinearAxes + 1] = {}
|
||||
LinearAxes[#LinearAxes].sName = AxesNames[i]
|
||||
else
|
||||
RotativeAxes[#RotativeAxes + 1] = {}
|
||||
RotativeAxes[#RotativeAxes].sName = AxesNames[i]
|
||||
end
|
||||
end
|
||||
|
||||
return LinearAxes, RotativeAxes
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function LogOutstroke( sToolName, ptOnToolTipCenter, vtHead, OptionalParameters)
|
||||
|
||||
-- parametri opzionali
|
||||
OptionalParameters = OptionalParameters or {}
|
||||
local LinearAxesValues = OptionalParameters.LinearAxesValues
|
||||
local RotativeAxesValues = OptionalParameters.RotativeAxesValues
|
||||
|
||||
-- gruppo per geometrie temporanee
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
|
||||
-- si disegnano punto e vettore
|
||||
local idPoint = EgtPoint( idTempGroup, ptOnToolTipCenter, GDB_RT.GLOB)
|
||||
local idVector = EgtVector( idTempGroup, vtHead, ptOnToolTipCenter, GDB_RT.GLOB)
|
||||
EgtSetColor( idPoint, RED())
|
||||
EgtSetColor( idVector, RED())
|
||||
|
||||
-- nome utensile
|
||||
EgtOutLog( 'Tool ' .. sToolName)
|
||||
|
||||
-- si loggano valori di punto e vettore
|
||||
EgtOutLog( ' Presimulation : OutStroke, Tip Point = ' .. tostring( ptOnToolTipCenter) .. ', id = ' .. idPoint .. ', vtHead = ' .. tostring( vtHead) .. ', id = ' .. idVector)
|
||||
|
||||
-- se disponibili, si loggano anche i valori calcolati degli assi
|
||||
if LinearAxesValues then
|
||||
EgtOutLog( ' ' .. 'Lin1' .. ' = ' .. tostring( LinearAxesValues[1]) .. ', ' .. 'Lin2' .. ' = ' .. tostring( LinearAxesValues[2]) .. ', ' .. 'Lin3' .. ' = ' .. tostring( LinearAxesValues[3]))
|
||||
end
|
||||
if RotativeAxesValues then
|
||||
EgtOutLog( ' ' .. 'Rot1' .. ' = ' .. tostring( RotativeAxesValues[1]) .. ', ' .. 'Rot2' .. ' = ' .. tostring( RotativeAxesValues[2]) .. ', ' .. 'Rot3' .. ' = ' .. tostring( RotativeAxesValues[3]))
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- costruzione trimesh del grezzo restante in testa o in coda
|
||||
local function GetRestlengthSurfTm( Part, sSide)
|
||||
|
||||
-- si costruisce il box in globale
|
||||
local b3RestLength
|
||||
if sSide == 'Head' then
|
||||
local b3PartWithOvermaterial = BeamLib.GetPartBoxWithHeadTail( Part, sSide)
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMax():getX(), Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( b3PartWithOvermaterial:getMax():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
b3RestLength = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
elseif sSide == 'Tail' then
|
||||
local b3PartWithOvermaterial = BeamLib.GetPartBoxWithHeadTail( Part, sSide)
|
||||
local dXMin = b3PartWithOvermaterial:getMin():getX()
|
||||
-- si evita sempre di lavorare col motore dietro la coda della barra (potrebbe succedere con barra restante molto corta): in quel caso si deve sempre separare prima
|
||||
dXMin = min( dXMin, Part.b3Part:getMin():getX() - 2000)
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMin():getX(), Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( dXMin, Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
b3RestLength = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
-- caso non testato, non dovrebbe mai finire qui (il default che arriva da fuori è Tail)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
-- si crea la trimesh dal box
|
||||
local idRestLengthBoxTm = EgtSurfTmBBox( Part.idTempGroup, b3RestLength , false, GDB_RT.GLOB)
|
||||
|
||||
return idRestLengthBoxTm
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function PreSimulationLib.GetPointOnToolTipCenter( ptPointAtDepth, vtHead, vtNFace, vtToolOffset, Tool)
|
||||
|
||||
return ptPointAtDepth + vtToolOffset * Tool.dDiameter / 2 + vtNFace * EgtIf( AreSameVectorApprox( vtHead, vtNFace), 0, Tool.dThickness)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- calcolo punto sull'uscita testa a partire dal punto di lavorazione o di attacco sul diametro utensile
|
||||
local function GetToolExitPoint( ptMachining, vtNEdge, vtHead, Tool, bIsDownUp)
|
||||
|
||||
local ptToolExitPoint = Point3d( ptMachining + vtNEdge * Tool.dDiameter / 2) + vtHead * EgtIf( bIsDownUp, ( Tool.dLength - Tool.dThickness), Tool.dLength)
|
||||
|
||||
return ptToolExitPoint
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- calcolo pivot in riferimento globale, dati punto sull'uscita utensile e direzioni
|
||||
local function GetGlobalPivot( ptToolExit, vtC, vtHead, vtMovePivot)
|
||||
|
||||
-- frame solidale all'utensile (lo stesso in cui vtMovePivot è definito)
|
||||
local frTool = Frame3d( ptToolExit, vtHead, vtC)
|
||||
local vtMovePivotGlob = Vector3d( vtMovePivot)
|
||||
vtMovePivotGlob:toGlob( frTool)
|
||||
local ptPivot = ptToolExit + vtMovePivotGlob
|
||||
|
||||
return ptPivot
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- restituisce i punti notevoli della lavorazioni in cui fare il controllo
|
||||
local function GetCollisionPointsToCheck( Edge, dDepthToMachine)
|
||||
|
||||
local PointsToCheck = {}
|
||||
|
||||
-- punti notevoli
|
||||
local ptStart = Edge.ptStart + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
local ptEnd = Edge.ptEnd + Edge.vtN * ( Edge.dElevation - dDepthToMachine)
|
||||
local ptMid = Point3d( ( ptStart + ptEnd) / 2)
|
||||
|
||||
-- caso ottimizzato: lato parallelo ad una direzione principale
|
||||
local bIsEdgeParallelToMainDirection =
|
||||
AreSameOrOppositeVectorApprox( Edge.vtEdge, X_AX())
|
||||
or AreSameOrOppositeVectorApprox( Edge.vtEdge, Y_AX())
|
||||
or AreSameOrOppositeVectorApprox( Edge.vtEdge, Z_AX())
|
||||
|
||||
-- aggiunta punti
|
||||
table.insert( PointsToCheck, ptStart)
|
||||
if not bIsEdgeParallelToMainDirection then
|
||||
table.insert( PointsToCheck, ptMid)
|
||||
end
|
||||
table.insert( PointsToCheck, ptEnd)
|
||||
|
||||
return PointsToCheck
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CheckOutOfStrokePoint( ptOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
-- impostazione utensile
|
||||
local bOkTool = EgtSetCalcTool( Tool.sName, Tool.sHead, Tool.nExit)
|
||||
if not bOkTool then
|
||||
error( 'CheckOutOfStrokePoint : cannot set calc tool')
|
||||
end
|
||||
|
||||
-- settaggio SCC per discriminare soluzioni multiple
|
||||
EgtSetCalcSolCh( nSCC)
|
||||
|
||||
-- se presente, settaggio asse bloccato
|
||||
if sBlockedAxis and type( sBlockedAxis) == "string" then
|
||||
local BlockedAxis = EgtSplitString( sBlockedAxis, '=')
|
||||
EgtSetRotAxisBlock( BlockedAxis[1], tonumber( BlockedAxis[2]))
|
||||
end
|
||||
|
||||
-- calcolo assi rotativi
|
||||
local bOkAngles, nSolutionsAngles, RotativeAxesValues = EgtGetCalcAnglesEx( vtHead, vtAux)
|
||||
local dRotative1 = RotativeAxesValues[1]
|
||||
local dRotative2 = RotativeAxesValues[2]
|
||||
local dRotative3 = RotativeAxesValues[3]
|
||||
|
||||
if not bOkAngles then
|
||||
error( ' CheckOutOfStrokePoint : error')
|
||||
end
|
||||
|
||||
-- se nessuna soluzione dagli assi rotativi, è in extracorsa
|
||||
if nSolutionsAngles == 0 then
|
||||
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
LogOutstroke( Tool.sName, ptOnToolTipCenter, vtHead, { RotativeAxesValues = { dRotative1, dRotative2, dRotative3}})
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- calcolo assi lineari
|
||||
local bOkPositions, _, dLinear1, dLinear2, dLinear3 = EgtGetCalcPositions( ptOnToolTipCenter, dRotative1, dRotative2, dRotative3)
|
||||
|
||||
if not bOkPositions then
|
||||
|
||||
error( ' CheckOutOfStrokePoint : error')
|
||||
end
|
||||
|
||||
-- verifica finecorsa per assi lineari (assi rotativi già verificati)
|
||||
local bAllAxesInStroke = EgtVerifyOutstroke( dLinear1, dLinear2, dLinear3)
|
||||
|
||||
-- extracorsa
|
||||
if not bAllAxesInStroke then
|
||||
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
LogOutstroke( Tool.sName, ptOnToolTipCenter, vtHead, { LinearAxesValues = { dLinear1, dLinear2, dLinear3}, RotativeAxesValues = { dRotative1, dRotative2, dRotative3}})
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- EgtSetAxisPos( 'T', dT)
|
||||
-- EgtSetAxisPos( 'Y', dY)
|
||||
-- EgtSetAxisPos( 'Z', dZ)
|
||||
-- EgtSetAxisPos( 'C', dC1)
|
||||
-- EgtSetAxisPos( 'A', dA1)
|
||||
|
||||
-- se si arriva qui, il punto non è in finecorsa
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- check extracorsa da punti sul tip dell'utensile
|
||||
function PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
for i = 1, #PointsOnToolTipCenter do
|
||||
|
||||
local bOutOfStroke = CheckOutOfStrokePoint( PointsOnToolTipCenter[i], vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
-- se trovato extracorsa inutile procedere con gli altri punti
|
||||
if bOutOfStroke then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- se arrivati qui, nessun extracorsa
|
||||
return false
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- check extracorsa da geometria
|
||||
-- TODO da considerare anche gli attacchi
|
||||
function PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeometry, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
local b3GeomMaxOffset = EgtGetBBoxGlob( idGeometry, GDB_BB.STANDARD)
|
||||
local ptBoxCenter = b3GeomMaxOffset:getCenter()
|
||||
local dBoxDimX = b3GeomMaxOffset:getDimX()
|
||||
local dBoxDimY = b3GeomMaxOffset:getDimY()
|
||||
local dBoxDimZ = b3GeomMaxOffset:getDimZ()
|
||||
|
||||
-- si controlla il finecorsa nei punti al centro delle 6 facce del box
|
||||
local PointsOnToolTipCenter = {}
|
||||
-- X+
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter + dBoxDimX / 2 * X_AX()))
|
||||
-- X-
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter - dBoxDimX / 2 * X_AX()))
|
||||
-- Y+
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter + dBoxDimY / 2 * Y_AX()))
|
||||
-- Y-
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter - dBoxDimY / 2 * Y_AX()))
|
||||
-- Z+
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter + dBoxDimZ / 2 * Z_AX()))
|
||||
-- Z-
|
||||
table.insert( PointsOnToolTipCenter, Point3d( ptBoxCenter - dBoxDimZ / 2 * Z_AX()))
|
||||
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromPoints( PointsOnToolTipCenter, vtHead, nSCC, Tool, vtAux, sBlockedAxis)
|
||||
|
||||
return bOutOfStroke
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MoveMachineAxesToPosition( ptOnToolTipCenter, vtHead, vtAux)
|
||||
|
||||
-- calcolo assi rotativi
|
||||
local bOkAngles, nSolutionsAngles, RotativeAxesValues = EgtGetCalcAnglesEx( vtHead, vtAux)
|
||||
local dRotative1 = RotativeAxesValues[1]
|
||||
local dRotative2 = RotativeAxesValues[2]
|
||||
local dRotative3 = RotativeAxesValues[3]
|
||||
|
||||
if not bOkAngles then
|
||||
error( ' MoveMachineAxesToPosition : error')
|
||||
end
|
||||
|
||||
-- calcolo assi lineari
|
||||
local bOkPositions, _, dLinear1, dLinear2, dLinear3 = EgtGetCalcPositions( ptOnToolTipCenter, dRotative1, dRotative2, dRotative3)
|
||||
|
||||
if not bOkPositions then
|
||||
|
||||
error( ' MoveMachineAxesToPosition : error')
|
||||
end
|
||||
|
||||
local AxesNames = EgtGetAllCurrAxesNames()
|
||||
local dTHome = EgtGetAxisHomePos( AxesNames[1])
|
||||
|
||||
-- spostamento assi in posizione (la T non si sposta perchè si sposta il pezzo)
|
||||
EgtSetAxisPos( AxesNames[2], dLinear2)
|
||||
EgtSetAxisPos( AxesNames[3], dLinear3)
|
||||
EgtSetAxisPos( AxesNames[4], dRotative1)
|
||||
EgtSetAxisPos( AxesNames[5], dRotative2)
|
||||
if dRotative3 then
|
||||
EgtSetAxisPos( AxesNames[6], dRotative3)
|
||||
end
|
||||
|
||||
return dLinear1 - dTHome
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CheckCollisionPoint( sAxis, ptOnToolTipCenter, vtHead, vtAux, Part, bCannotSplitRestLength, sRestLengthSideForPreSimulation, bCheckOnlyRestlength)
|
||||
|
||||
-- spostamento assi macchina in posizione
|
||||
local dDeltaXHeadOffset = MoveMachineAxesToPosition( ptOnToolTipCenter, vtHead, vtAux)
|
||||
|
||||
-- si recuperano gli id delle geometrie dell'asse con cui controllare la collisione
|
||||
local idCollisionGroup = EgtGetFirstNameInGroup( EgtGetAxisId( sAxis), 'COLLISION')
|
||||
local idCollisionGroupOther = EgtGetFirstNameInGroup( EgtGetAxisId( sAxis), 'OTHER_COLLISION') or GDB_ID.NULL
|
||||
local CollisionGroupEntitiesId = EgtGetAllInGroup( idCollisionGroup)
|
||||
local CollisionGroupOtherEntitiesId = EgtGetAllInGroup( idCollisionGroupOther)
|
||||
-- si tengono solo gli elementi trimesh
|
||||
local CollisionSurfTmId = {}
|
||||
for i = 1, #CollisionGroupEntitiesId do
|
||||
if EgtGetType( CollisionGroupEntitiesId[i]) == GDB_TY.SRF_MESH then
|
||||
local idCollisionSurfTmCopy = EgtCopyGlob( CollisionGroupEntitiesId[i], Part.idTempGroup)
|
||||
EgtMove( idCollisionSurfTmCopy, Vector3d( dDeltaXHeadOffset, 0, 0), GDB_RT.GLOB)
|
||||
table.insert( CollisionSurfTmId, idCollisionSurfTmCopy)
|
||||
end
|
||||
end
|
||||
-- se presenti geometrie nel gruppo other si aggiungono anche quelle
|
||||
if CollisionGroupOtherEntitiesId and #CollisionGroupOtherEntitiesId > 0 then
|
||||
for i = 1, #CollisionGroupOtherEntitiesId do
|
||||
if EgtGetType( CollisionGroupOtherEntitiesId[i]) == GDB_TY.SRF_MESH then
|
||||
local idCollisionOtherSurfTmCopy = EgtCopyGlob( CollisionGroupOtherEntitiesId[i], Part.idTempGroup)
|
||||
EgtMove( idCollisionOtherSurfTmCopy, Vector3d( dDeltaXHeadOffset, 0, 0), GDB_RT.GLOB)
|
||||
table.insert( CollisionSurfTmId, idCollisionOtherSurfTmCopy)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- check collisione con pezzo
|
||||
local bCollisionFoundPiece = false
|
||||
if not bCheckOnlyRestlength then
|
||||
local idCheckCollisionTm = Part.idBoxTm
|
||||
-- se testa o coda attaccate, si considerano nella superficie di collisione
|
||||
if bCannotSplitRestLength then
|
||||
local b3CheckCollision = BeamLib.GetPartBoxWithHeadTail( Part, sRestLengthSideForPreSimulation)
|
||||
idCheckCollisionTm = EgtSurfTmBBox( Part.idTempGroup, b3CheckCollision, false, GDB_RT.GLOB)
|
||||
end
|
||||
for i = 1, #CollisionSurfTmId do
|
||||
bCollisionFoundPiece = EgtCDeSolidSolid( idCheckCollisionTm, CollisionSurfTmId[i], BeamData.COLL_SIC)
|
||||
if not type( bCollisionFoundPiece) == "boolean" then
|
||||
error( 'Presimulation fail')
|
||||
end
|
||||
if EgtGetDebugLevel() >= 3 and bCollisionFoundPiece then
|
||||
EgtSetColor( CollisionSurfTmId[i], RED())
|
||||
end
|
||||
if bCollisionFoundPiece then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- se trovata collisione con pezzo è inutile procedere con il grezzo
|
||||
if bCollisionFoundPiece then
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- check collisione con grezzo restante, se con il pezzo non c'è collisione e non è un taglio di testa o coda
|
||||
local bCollisionFoundRestLength = false
|
||||
if not ( bCollisionFoundPiece or bCannotSplitRestLength) then
|
||||
local idRestLengthSurfFr = GetRestlengthSurfTm( Part, sRestLengthSideForPreSimulation)
|
||||
if idRestLengthSurfFr then
|
||||
for i = 1, #CollisionSurfTmId do
|
||||
bCollisionFoundRestLength = EgtCDeSolidSolid( idRestLengthSurfFr, CollisionSurfTmId[i], BeamData.COLL_SIC)
|
||||
if not type( bCollisionFoundRestLength) == "boolean" then
|
||||
error( 'Presimulation fail')
|
||||
end
|
||||
if EgtGetDebugLevel() >= 3 and bCollisionFoundRestLength then
|
||||
EgtSetColor( CollisionSurfTmId[i], ORANGE())
|
||||
end
|
||||
if bCollisionFoundRestLength then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return false, bCollisionFoundRestLength
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- controllo collisione con verifica intersezione trimesh e geometrie da macchina
|
||||
local function CheckCollisionWithAxis( sAxis, MachiningParameters, OptionalParameters)
|
||||
|
||||
-- parametri obbligatori
|
||||
local Edge = MachiningParameters.Edge
|
||||
local vtNFace = MachiningParameters.vtNFace
|
||||
local vtHead = MachiningParameters.vtHead
|
||||
local Part = MachiningParameters.Part
|
||||
local Tool = MachiningParameters.Tool
|
||||
local dDepthToMachine = MachiningParameters.dDepthToMachine
|
||||
|
||||
-- parametri opzionali
|
||||
OptionalParameters = OptionalParameters or {}
|
||||
local bCheckOnlyRestlength = OptionalParameters.bCheckOnlyRestlength or false
|
||||
local sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
local bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
||||
local vtAux = OptionalParameters.vtAux
|
||||
|
||||
-- se normale faccia non parallela a direzione testa c'è qualcosa che non va
|
||||
if not AreSameOrOppositeVectorApprox( vtNFace, vtHead) then
|
||||
error( 'CheckCollisionWithAxis : invalid directions')
|
||||
end
|
||||
|
||||
-- punti notevoli della lavorazione in cui fare il check
|
||||
local PointsToCheck = OptionalParameters.PointsToCheck or GetCollisionPointsToCheck( Edge, dDepthToMachine)
|
||||
|
||||
-- punti sul tip dell'utensile, in centro
|
||||
local PointsOnToolTipCenter = {}
|
||||
for i = 1, #PointsToCheck do
|
||||
PointsOnToolTipCenter[i] = PreSimulationLib.GetPointOnToolTipCenter( PointsToCheck[i], vtHead, vtNFace, Edge.vtN, Tool)
|
||||
end
|
||||
|
||||
local bMoveAfterSplit = false
|
||||
|
||||
-- se almeno in un punto c'è collisione con il pezzo si ritorna collisione
|
||||
-- se non si trova collisione si ritorna se è necessario separare prima di effettuare la lavorazione (ossia non c'è collisione con il pezzo ma c'è con il grezzo restante)
|
||||
for i = 1, #PointsOnToolTipCenter do
|
||||
|
||||
local bCollisionFoundPiece, bCollisionFoundRestLength = CheckCollisionPoint( sAxis, PointsOnToolTipCenter[i], vtHead, vtAux, Part, bCannotSplitRestLength, sRestLengthSideForPreSimulation, bCheckOnlyRestlength)
|
||||
|
||||
-- se trovata collisione con pezzo è inutile controllare gli altri punti
|
||||
if bCollisionFoundPiece then
|
||||
|
||||
return true
|
||||
|
||||
-- se trovata collisione con grezzo si setta che la lavorazione è da fare dopo separazione e si prosegue con gli altri punti
|
||||
elseif bCollisionFoundRestLength then
|
||||
|
||||
bMoveAfterSplit = true
|
||||
end
|
||||
end
|
||||
|
||||
-- se si arriva qui significa che non è stata trovata alcuna collisione con pezzo
|
||||
return false, bMoveAfterSplit
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function PreSimulationLib.CheckCollision( sBladeEngagement, Parameters, OptionalParameters)
|
||||
|
||||
local bCollisionFound
|
||||
local bMoveAfterSplitL3, bMoveAfterSplitR3, bMoveAfterSplitR2, bMoveAfterSplitR1
|
||||
|
||||
-- parametri obbligatori
|
||||
local Edge = Parameters.Edge
|
||||
local vtNFace = Parameters.vtNFace
|
||||
local Tool = Parameters.Tool
|
||||
|
||||
-- parametri opzionali, in parte da far transitare
|
||||
OptionalParameters = OptionalParameters or {}
|
||||
|
||||
local OptionalParametersCheckCollisionWithAxis = {}
|
||||
OptionalParametersCheckCollisionWithAxis.bCheckOnlyRestlength = false
|
||||
OptionalParametersCheckCollisionWithAxis.PointsToCheck = OptionalParameters.PointsToCheck or nil
|
||||
OptionalParametersCheckCollisionWithAxis.sRestLengthSideForPreSimulation = OptionalParameters.sRestLengthSideForPreSimulation or 'Tail'
|
||||
OptionalParametersCheckCollisionWithAxis.bCannotSplitRestLength = OptionalParameters.bCannotSplitRestLength or false
|
||||
OptionalParametersCheckCollisionWithAxis.sBlockedAxis = OptionalParameters.sBlockedAxis
|
||||
OptionalParametersCheckCollisionWithAxis.vtAux = OptionalParameters.vtAux
|
||||
|
||||
local sBlockedAxis = OptionalParameters.sBlockedAxis
|
||||
local bIsDicing = OptionalParameters.bIsDicing or false
|
||||
local bDisableRealElevationCheck = OptionalParameters.bDisableRealElevationCheck or false
|
||||
local bCheckOnlyRestlengthForAxisABC = false
|
||||
|
||||
-- se cubetti in modalità standard (no DownUp) gli assi AB e C si controllano solo con grezzo (ci sarebbe collisione con il materiale già rimosso controllando AB e C con pezzo)
|
||||
if bIsDicing and ( sBladeEngagement == 'Standard') then
|
||||
bCheckOnlyRestlengthForAxisABC = true
|
||||
-- se l'elevazione reale (rispetto al pezzo + eventuale materiale in testa/coda) è maggiore del massimo materiale è sempre collisione
|
||||
-- TODO rifare con funzione
|
||||
elseif not bDisableRealElevationCheck then
|
||||
local Edge = Parameters.Edge
|
||||
local vtNFace = Parameters.vtNFace
|
||||
local dDepthToMachine = Parameters.dDepthToMachine
|
||||
local b3BoxForElevationCheck = BBox3d( Parameters.Part.b3Part)
|
||||
-- se è un taglio di testa o coda va aggiunto il sovramateriale
|
||||
if OptionalParametersCheckCollisionWithAxis.bCannotSplitRestLength then
|
||||
b3BoxForElevationCheck = BeamLib.GetPartBoxWithHeadTail( Parameters.Part, OptionalParametersCheckCollisionWithAxis.sRestLengthSideForPreSimulation)
|
||||
end
|
||||
-- trimesh rettangolare con un lato corrispondente al lato da lavorare e larghezza come spessore utensile
|
||||
local idTrimesh = EgtSurfTmRectangle( Parameters.Part.idTempGroup, Edge.ptStart, Edge.ptEnd, Edge.ptEnd + vtNFace * Parameters.Tool.dThickness, GDB_RT.GLOB)
|
||||
local vtNTrimesh = EgtSurfTmFacetNormVersor( idTrimesh, 0, GDB_ID.ROOT)
|
||||
-- se trimesh con normale opposta a quella del lato, si inverte (non si sa a priori che verso avrà)
|
||||
if not AreSameVectorApprox( Edge.vtN, vtNTrimesh) then
|
||||
EgtInvertSurf( idTrimesh)
|
||||
end
|
||||
local dRealElevation = EgtSurfTmFacetElevationInBBox( idTrimesh, 0, b3BoxForElevationCheck, true, GDB_ID.ROOT)
|
||||
local dRealDepthToMachine = ( dRealElevation - Parameters.Edge.dElevation + dDepthToMachine)
|
||||
if dRealDepthToMachine > Parameters.Tool.dMaxDepth + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- SCC
|
||||
local nSCC = Tool.SetupInfo.GetSCC( Edge.vtN, Edge.vtEdge, vtNFace)
|
||||
|
||||
-- si settano utensile, SCC e asse bloccato per il controllo collisione
|
||||
local bOkTool = EgtSetCalcTool( Tool.sName, Tool.sHead, Tool.nExit)
|
||||
if not bOkTool then
|
||||
error( 'CheckCollisionWithAxis : cannot set calc tool')
|
||||
end
|
||||
EgtSetCalcSolCh( nSCC)
|
||||
if sBlockedAxis and type( sBlockedAxis) == "string" then
|
||||
local BlockedAxis = EgtSplitString( sBlockedAxis, '=')
|
||||
EgtSetRotAxisBlock( BlockedAxis[1], tonumber( BlockedAxis[2]))
|
||||
end
|
||||
|
||||
-- nomi degli assi con cui controllare la collisione
|
||||
local AxesNames = EgtGetAllCurrAxesNames()
|
||||
local sL3 = AxesNames[3]
|
||||
local sR3 = AxesNames[6]
|
||||
local sR2 = AxesNames[5]
|
||||
local sR1 = AxesNames[4]
|
||||
|
||||
-- ultimo asse lineare prima dei rotativi (solitamente Z) si controlla sempre
|
||||
bCollisionFound, bMoveAfterSplitL3 = CheckCollisionWithAxis( sL3, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
|
||||
-- assi rotativi: se richiesto si controlla la collisione solo col grezzo
|
||||
OptionalParametersCheckCollisionWithAxis.bCheckOnlyRestlength = bCheckOnlyRestlengthForAxisABC
|
||||
|
||||
if sR3 and not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR3 = CheckCollisionWithAxis( sR3, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
if not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR2 = CheckCollisionWithAxis( sR2, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
if not bCollisionFound then
|
||||
bCollisionFound, bMoveAfterSplitR1 = CheckCollisionWithAxis( sR1, Parameters, OptionalParametersCheckCollisionWithAxis)
|
||||
end
|
||||
|
||||
local bMoveAfterSplit = bMoveAfterSplitL3 or bMoveAfterSplitR3 or bMoveAfterSplitR2 or bMoveAfterSplitR1
|
||||
|
||||
return bCollisionFound, bMoveAfterSplit
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
return PreSimulationLib
|
||||
@@ -0,0 +1,122 @@
|
||||
-- BeamLib.lua by Egalware s.r.l. 2025/11/24
|
||||
-- Libreria calcolo tempo automatismo
|
||||
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local TimeLib = {}
|
||||
|
||||
|
||||
EgtOutLog( ' TimeLib started', 1)
|
||||
|
||||
|
||||
TimeLib.__index = TimeLib
|
||||
|
||||
function TimeLib.new()
|
||||
local TimeLibInstance = setmetatable({}, TimeLib)
|
||||
TimeLibInstance.dStartTime = os.clock()
|
||||
TimeLibInstance.Measurements = {}
|
||||
return TimeLibInstance
|
||||
end
|
||||
|
||||
-- reset entire timer
|
||||
function TimeLib:start()
|
||||
self.dStartTime = os.clock()
|
||||
self.Measurements = {}
|
||||
end
|
||||
|
||||
-- start elapsed measurement for a specific name
|
||||
function TimeLib:startElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
local dNow = os.clock()
|
||||
|
||||
if not self.Measurements[sMeasurementName] then
|
||||
self.Measurements[sMeasurementName] = {
|
||||
dStart = dNow,
|
||||
dLast = 0,
|
||||
dCumulative = 0,
|
||||
dRecent = 0,
|
||||
nCount = 0
|
||||
}
|
||||
else
|
||||
self.Measurements[sMeasurementName].dStart = dNow
|
||||
end
|
||||
end
|
||||
|
||||
-- stop elapsed measurement (increments count and updates cumulative)
|
||||
function TimeLib:stopElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
local dNow = os.clock()
|
||||
local Measurement = self.Measurements[sMeasurementName]
|
||||
|
||||
if Measurement and Measurement.dStart then
|
||||
local dDuration = dNow - Measurement.dStart
|
||||
Measurement.dRecent = dDuration
|
||||
Measurement.dCumulative = Measurement.dCumulative + dDuration
|
||||
Measurement.dLast = dNow
|
||||
Measurement.nCount = Measurement.nCount + 1
|
||||
Measurement.dStart = nil
|
||||
else
|
||||
-- if stop called without start, initialize with zero
|
||||
self.Measurements[sMeasurementName] = {
|
||||
dStart = nil,
|
||||
dLast = dNow,
|
||||
dCumulative = 0,
|
||||
dRecent = 0,
|
||||
nCount = 0
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- reset elapsed for a specific measurement
|
||||
function TimeLib:resetElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
self.Measurements[sMeasurementName] = nil
|
||||
end
|
||||
|
||||
-- return elapsed times: total, cumulative, recent, count
|
||||
function TimeLib:getElapsed(sName)
|
||||
local dTotal = os.clock() - self.dStartTime
|
||||
local sMeasurementName = sName or "Default"
|
||||
local Measurement = self.Measurements[sMeasurementName]
|
||||
|
||||
if Measurement then
|
||||
return dTotal, Measurement.dCumulative, Measurement.dRecent, Measurement.nCount
|
||||
else
|
||||
return dTotal, nil, nil, 0
|
||||
end
|
||||
end
|
||||
|
||||
-- log elapsed times for one measurement
|
||||
function TimeLib:logElapsed(sName)
|
||||
local dTotal, dCumulative, dRecent, nCount = self:getElapsed(sName)
|
||||
local sMeasurementName = sName or "Default"
|
||||
|
||||
if dCumulative then
|
||||
EgtOutLog(string.format(
|
||||
"%s(#%d): recent %.3f, cumulative %.3f, total %.3f",
|
||||
sMeasurementName, nCount, dRecent, dCumulative, dTotal))
|
||||
else
|
||||
EgtOutLog(string.format("Total %.3f (no '%s' measurement started)",
|
||||
dTotal, sMeasurementName))
|
||||
end
|
||||
end
|
||||
|
||||
-- log elapsed times for all measurements
|
||||
function TimeLib:logAllElapsed()
|
||||
local dTotal = os.clock() - self.dStartTime
|
||||
if next(self.Measurements) == nil then
|
||||
EgtOutLog(string.format("Total %.3f (no measurements started)", dTotal))
|
||||
return
|
||||
end
|
||||
|
||||
for sMeasurementName, Measurement in pairs(self.Measurements) do
|
||||
local dCumulative = Measurement.dCumulative
|
||||
local dRecent = Measurement.dRecent
|
||||
local nCount = Measurement.nCount
|
||||
EgtOutLog(string.format(
|
||||
"%s(#%d): recent %.3f, cumulative %.3f, total %.3f",
|
||||
sMeasurementName, nCount, dRecent, dCumulative, dTotal))
|
||||
end
|
||||
end
|
||||
|
||||
return TimeLib
|
||||
@@ -0,0 +1,96 @@
|
||||
-- BeamNestProcess.lua by Egalware s.r.l. 2026/05/11
|
||||
-- Gestione nesting automatico travi anche oblique
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( true)
|
||||
|
||||
-- Include
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
----------------------------------------------------------------------------------------------------------
|
||||
-- stati che definiscono rotazione / inversione della parte
|
||||
local STATE = {
|
||||
STD = 1, -- Standard
|
||||
ROT180 = 2, -- Rotazione 180deg attorno a X+
|
||||
INV = 3, -- Inversione (rotazione 180deg attorno a Z+)
|
||||
INV_ROT180 = 4 -- Inversione + rotazione
|
||||
}
|
||||
|
||||
----------------------------------------------------------------------------------------------------------
|
||||
-- inventario grezzi
|
||||
local RawInventory = {
|
||||
Stock = {},
|
||||
ActiveBeams = {}
|
||||
}
|
||||
|
||||
function RawInventory:BuildStock()
|
||||
if #LEN ~= #QTY then
|
||||
error( 'NestProcess: invalid stock data')
|
||||
end
|
||||
|
||||
for i = 1, #LEN do
|
||||
self.Stock[#self.Stock + 1] = {
|
||||
Length = LEN[i],
|
||||
Count = QTY[i]
|
||||
}
|
||||
end
|
||||
|
||||
return RawInventory
|
||||
end
|
||||
|
||||
function RawInventory:AddActiveBeam()
|
||||
-- TODO da fare
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------------------------------------
|
||||
-- PartTemplates (informazioni geometriche pezzi univoci) e JobPool (lista di tutti i singoli pezzi, multipli compresi, da nestare)
|
||||
local PartTemplates = {}
|
||||
local JobPool = {}
|
||||
|
||||
function PartTemplates:AddPart( id)
|
||||
PartTemplates[id] = {}
|
||||
PartTemplates[id].dLength = EgtGetInfo( id, 'L', 'd')
|
||||
-- TODO qua gli stati abilitati dovranno arrivare dalle alternatives
|
||||
local VerticesHead = EgtSplitString( EgtGetInfo( id, 'HEADOFFSETX', 'd'))
|
||||
local vtNHead = Vector3d( EgtSplitString( EgtGetInfo( id, 'HEADVTN', 'd')))
|
||||
local VerticesTail = EgtSplitString( EgtGetInfo( id, 'TAILOFFSETX', 'd'))
|
||||
local vtNTail = Vector3d( EgtSplitString( EgtGetInfo( id, 'TAILVTN', 'd')))
|
||||
PartTemplates[id].States = {
|
||||
[STATE.STD] = {
|
||||
Head = { Vertices = VerticesHead, vtN = vtNHead},
|
||||
Tail = { Vertices = VerticesTail, vtN = vtNTail}
|
||||
},
|
||||
[STATE.ROT180] = {
|
||||
Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead},
|
||||
Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead}
|
||||
},
|
||||
[STATE.INV] = {
|
||||
Head = { Vertices = VerticesTail, vtN = vtNTail},
|
||||
Tail = { Vertices = VerticesHead, vtN = vtNHead}
|
||||
},
|
||||
[STATE.INV_ROT180] = {
|
||||
Head = { Vertices = BeamLib.RotateTableFromIndex( VerticesTail, 3), vtN = vtNHead},
|
||||
Tail = { Vertices = BeamLib.RotateTableFromIndex( VerticesHead, 3), vtN = vtNHead}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
-- creazione combinata (si cicla una sola volta) di entrambe le tabelle
|
||||
local function BuildPartTemplatesAndJobPool()
|
||||
for id, nCount in pairs( PART) do
|
||||
PartTemplates:AddPart( id)
|
||||
end
|
||||
|
||||
return PartTemplates, JobPool
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
RawInventory:BuildStock()
|
||||
BuildPartTemplatesAndJobPool()
|
||||
@@ -0,0 +1,556 @@
|
||||
-- BeamNestProcess.lua by Egaltech s.r.l. 2023/01/15
|
||||
-- Gestione nesting automatico travi
|
||||
-- 2022/10/05 Piccole modifiche per far funzionare correttamente i compilati.
|
||||
-- 2022/10/06 Corretto bug che moltiplicava i pezzi se erano presenti più grezzi della stessa sezione.
|
||||
-- 2023/01/15 Piccole correzioni.
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Per test
|
||||
--NEST = {}
|
||||
--NEST.FILE = 'c:\\TechnoEssetre7\\EgtData\\Prods\\0010\\Bar_10_1.btl'
|
||||
--NEST.MACHINE = 'Essetre-90480019_MW'
|
||||
--NEST.FLAG = 3
|
||||
|
||||
local sLog = ' +++ BeamNestProcess : ' .. NEST.FILE
|
||||
EgtOutLog( sLog)
|
||||
|
||||
-- flag per abilitare statistiche in log
|
||||
local bLogStat = false
|
||||
|
||||
-- Cancello file di log specifico
|
||||
local sLogFile = EgtChangePathExtension( NEST.FILE, '.txt')
|
||||
EgtEraseFile( sLogFile)
|
||||
|
||||
-- Funzioni per scrittura su file di log specifico
|
||||
local function WriteErrToLogFile( nErr, sMsg, nRot, nCutId, nTaskId)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'ERR=' .. tostring( nErr) .. '\n')
|
||||
hFile:write( sMsg .. '\n')
|
||||
hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n')
|
||||
hFile:write( 'CUTID=' .. tostring( nCutId or 0) .. '\n')
|
||||
hFile:write( 'TASKID=' .. tostring( nTaskId or 0) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
local function WriteTimeToLogFile( dTime)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo errore
|
||||
local function PostErrView( nErr, sMsg)
|
||||
if nErr ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (err=' .. tostring( nErr) .. ')', 'ERRORS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo warning
|
||||
local function PostWarnView( nWarn, sMsg)
|
||||
if nWarn ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (wrn=' .. tostring( nWarn) .. ')', 'WARNINGS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per aggiornare dati ausiliari
|
||||
local function UpdateAuxData( sAuxFile)
|
||||
local bModif = false
|
||||
-- Se definito LOAD90, aggiorno
|
||||
local sLoad90 = EgtGetStringFromIni( 'AuxData', 'LOAD90', '', sAuxFile)
|
||||
if sLoad90 ~= '' then
|
||||
local BtlInfoId = EgtGetFirstNameInGroup( GDB_ID.ROOT, 'BtlInfo') or GDB_ID.NULL
|
||||
EgtSetInfo( BtlInfoId, 'LOAD90', sLoad90)
|
||||
bModif = true
|
||||
end
|
||||
return bModif
|
||||
end
|
||||
|
||||
local function PartsToFill( Parts)
|
||||
local nToFill = 0
|
||||
for i = 1, #Parts do
|
||||
if Parts[i].Cnt > 0 then
|
||||
nToFill = nToFill + Parts[i].Cnt
|
||||
end
|
||||
end
|
||||
return nToFill
|
||||
end
|
||||
|
||||
local function ExecMaximumFilling( Raw, Parts)
|
||||
-- Inizializzo maximum filler
|
||||
EgtMaxFillerStart()
|
||||
-- Inserisco i pezzi
|
||||
for i = 1, #Parts do
|
||||
EgtMaxFillerAddPart( i, Parts[i].Len, Parts[i].DispLen or Parts[i].Len, Parts[i].Cnt or 1)
|
||||
end
|
||||
-- Eseguo l'ottimizzazione
|
||||
EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType)
|
||||
-- Recupero i risultati
|
||||
local nFilledParts, nDiffParts, dTotFillRatio = EgtMaxFillerGetResults()
|
||||
local OneRes = {}
|
||||
for i = 0, nDiffParts - 1 do
|
||||
local nPartId, nCount = EgtMaxFillerGetOneResult( i)
|
||||
table.insert( OneRes, { Id=nPartId, Count=nCount})
|
||||
end
|
||||
--return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Time=dTime, Data=OneRes}
|
||||
return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Data=OneRes}
|
||||
end
|
||||
|
||||
-- Funzione per trovare nome MachGroup
|
||||
local function NewMachGroupName()
|
||||
local nMachGroupId = EgtGetFirstMachGroup()
|
||||
if not nMachGroupId then return 1 end
|
||||
local nMaxMachGroup = 0
|
||||
while nMachGroupId do
|
||||
sMachGroupName = EgtGetMachGroupName(nMachGroupId)
|
||||
local nMachGroupName = tonumber(sMachGroupName)
|
||||
if nMachGroupName > nMaxMachGroup then
|
||||
nMaxMachGroup = nMachGroupName
|
||||
end
|
||||
nMachGroupId = EgtGetNextMachGroup(nMachGroupId)
|
||||
end
|
||||
return nMaxMachGroup + 1
|
||||
end
|
||||
|
||||
local function TotRawCount(Raws)
|
||||
local nTotRaws = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
nTotRaws = nTotRaws + Raws[RawIndex].Count
|
||||
end
|
||||
return nTotRaws
|
||||
end
|
||||
|
||||
local function TotPartLen(Parts)
|
||||
local nTotPartLen = 0
|
||||
for PartIndex = 1, #Parts do
|
||||
nTotPartLen = nTotPartLen + ( Parts[PartIndex].Len * Parts[PartIndex].Cnt)
|
||||
end
|
||||
return nTotPartLen
|
||||
end
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
|
||||
-- recupero cartella macchine
|
||||
local sIniFilePath = EgtGetIniFile()
|
||||
local MachineDirPath = EgtGetStringFromIni( 'Mach', 'MachinesDir', '', sIniFilePath)
|
||||
-- Verifico che tutte le macchine siano abilitate per la lavorazione delle Travi
|
||||
for MachineIndex = 1, #NEST.MACHINELIST do
|
||||
local sMachDir = MachineDirPath .. '\\' .. NEST.MACHINELIST[MachineIndex]
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then
|
||||
NEST.ERR = 12
|
||||
NEST.MSG = 'Error not configured for beam machine : ' .. sMachine
|
||||
WriteErrToLogFile( NEST.ERR, NEST.MSG)
|
||||
PostErrView( NEST.ERR, NEST.MSG)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
---- Imposto la macchina corrente e verifico sia abilitata per la lavorazione delle Travi
|
||||
--EgtSetCurrMachine( NEST.MACHINE)
|
||||
--local sMachDir = EgtGetCurrMachineDir()
|
||||
--if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then
|
||||
-- NEST.ERR = 12
|
||||
-- NEST.MSG = 'Error not configured for beam machine : ' .. sMachine
|
||||
-- WriteErrToLogFile( NEST.ERR, NEST.MSG)
|
||||
-- PostErrView( NEST.ERR, NEST.MSG)
|
||||
-- return
|
||||
--end
|
||||
|
||||
---- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
--EgtRemoveBaseMachineDirFromPackagePath()
|
||||
--EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Inizializzo contatori errori e avvisi
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
|
||||
-- Grezzi
|
||||
local Raws = {}
|
||||
for nRawIndex = 1, #RAWLIST do
|
||||
local Raw = RAWLIST[nRawIndex]
|
||||
table.insert( Raws, {LenToFill = Raw.Len, StartGap = NEST.STARTOFFSET, MidGap = NEST.OFFSET, EndGap = 0, SortType = -1, Count = Raw.Qty})
|
||||
end
|
||||
-- cerco il grezzo con la lunghezza maggiore, epurata dello start gap
|
||||
local maxRawLenToFillNoStartGap = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
if Raws[RawIndex].Count > 0 then
|
||||
maxRawLenToFillNoStartGap = max( maxRawLenToFillNoStartGap, Raws[RawIndex].LenToFill - Raws[RawIndex].StartGap)
|
||||
end
|
||||
end
|
||||
|
||||
-- Pezzi
|
||||
local Parts = {}
|
||||
-- ciclo su pezzi per aggiungerli al nesting
|
||||
local dTotLen = 0
|
||||
for nPartId, nCount in pairs( PARTLIST) do
|
||||
-- recupero lunghezza pezzo
|
||||
local Len = EgtGetInfo( nPartId, "L", 'd')
|
||||
local DispLen = EgtIf( Len <= 1000, 2000, 0) --EgtIf( Len <= 2000, max( 2000, 6000 - Len), 0)
|
||||
-- aggiungo il pezzo solo se ci sta nel grezzo più lungo a disposizione
|
||||
if Len < maxRawLenToFillNoStartGap then
|
||||
for nCntIndex = 1 , nCount do
|
||||
table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = 1})
|
||||
dTotLen = dTotLen + Len
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- lunghezza totale pezzi
|
||||
local dTotPartLen = TotPartLen( Parts)
|
||||
-- calcolo media delle barre necessarie
|
||||
local NeededRawsForType = {}
|
||||
for RawIndex = 1, #Raws do
|
||||
NeededRawsForType[RawIndex] = min( ceil( dTotPartLen / Raws[RawIndex].LenToFill), Raws[RawIndex].Count)
|
||||
end
|
||||
local RawQtySum = 0
|
||||
for NeededRawIndex = 1, #NeededRawsForType do
|
||||
RawQtySum = RawQtySum + NeededRawsForType[NeededRawIndex]
|
||||
end
|
||||
local MediumRawQty = ceil( RawQtySum / #NeededRawsForType)
|
||||
if MediumRawQty > 1 then
|
||||
MediumRawQty = MediumRawQty - 1
|
||||
end
|
||||
|
||||
-- lista dei risultati
|
||||
local ResultList = {}
|
||||
local BestResult = nil
|
||||
local BestResultIndex = nil
|
||||
-- riordino lista pezzi per lunghezza
|
||||
table.sort( Parts, function( B1, B2) return B1.Len < B2.Len end)
|
||||
|
||||
local function NestSolutionByIndex( Index)
|
||||
|
||||
-- creo copia lista raw
|
||||
local TempRaws = {}
|
||||
for TempRawIndex = 1, #Raws do
|
||||
table.insert(TempRaws, {LenToFill = Raws[TempRawIndex].LenToFill, StartGap = Raws[TempRawIndex].StartGap, MidGap = Raws[TempRawIndex].MidGap, EndGap = Raws[TempRawIndex].EndGap, SortType = Raws[TempRawIndex].SortType, Count = Raws[TempRawIndex].Count})
|
||||
end
|
||||
|
||||
-- recupero pezzi corti
|
||||
local ShortList = {}
|
||||
local LongList = {}
|
||||
|
||||
for PartIndex = 1, #Parts do
|
||||
if PartIndex <= Index then
|
||||
table.insert( ShortList, Parts[PartIndex])
|
||||
else
|
||||
table.insert( LongList, Parts[PartIndex])
|
||||
end
|
||||
Parts[PartIndex].Cnt = 1
|
||||
end
|
||||
-- numero di pezzi piccoli per barra
|
||||
local ShortCount = Index
|
||||
local ShortForRaw = floor( ShortCount / MediumRawQty)
|
||||
local ExtraShortForRaw = 0
|
||||
if MediumRawQty > 0 then
|
||||
ExtraShortForRaw = fmod( ShortCount, MediumRawQty)
|
||||
end
|
||||
-- creo lista pezzi corti singoli
|
||||
local SingleShortList = {}
|
||||
for ShortIndex = 1, #ShortList do
|
||||
for ShortCount = 1, ShortList[ShortIndex].Cnt do
|
||||
table.insert( SingleShortList, {Id = ShortList[ShortIndex].Id, Len = ShortList[ShortIndex].Len, DispLen = ShortList[ShortIndex].DispLen, Cnt = 1})
|
||||
end
|
||||
end
|
||||
-- li divido per le barre previste
|
||||
local RawsShortList = {}
|
||||
local RawIndex = 0
|
||||
local ShortRawIndex = 0
|
||||
for ShortIndex = 1, #SingleShortList do
|
||||
if ShortRawIndex > 0 then
|
||||
table.insert( RawsShortList[RawIndex], SingleShortList[ShortIndex])
|
||||
ShortRawIndex = ShortRawIndex - 1
|
||||
else
|
||||
table.insert( RawsShortList, {SingleShortList[ShortIndex]})
|
||||
RawIndex = RawIndex + 1
|
||||
ShortRawIndex = ShortForRaw + EgtIf( RawIndex <= ExtraShortForRaw, 1, 0) - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Ciclo fino ad esaurimento pezzi o barre
|
||||
local dTotPartInRawLen = 0
|
||||
local nRawTot = 0
|
||||
local dRawTotLen = 0
|
||||
local dTime = 0
|
||||
local nCycle = 1
|
||||
local CurrResult = {}
|
||||
while TotRawCount( TempRaws) > 0 and PartsToFill( Parts) > 0 do
|
||||
|
||||
-- creo lista con pezzi lunghi e pezzi corti di questo Cycle
|
||||
local PartsToNest = {}
|
||||
for PartIndex = 1, #LongList do
|
||||
table.insert( PartsToNest, LongList[PartIndex])
|
||||
end
|
||||
for CycleIndex = 1, #RawsShortList do
|
||||
if CycleIndex <= nCycle then
|
||||
for PartIndex = 1, #RawsShortList[CycleIndex] do
|
||||
table.insert( PartsToNest, RawsShortList[CycleIndex][PartIndex])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se non ci sono pezzi da nestare, esco
|
||||
if PartsToFill( PartsToNest) <= 0 then
|
||||
break
|
||||
end
|
||||
-- Eseguo ottimizzazione per ogni lunghezza di barra
|
||||
local Results = {}
|
||||
for RawIndex = 1, #TempRaws do
|
||||
if TempRaws[RawIndex].Count > 0 then
|
||||
Results[RawIndex] = ExecMaximumFilling( TempRaws[RawIndex], PartsToNest)
|
||||
else
|
||||
Results[RawIndex] = { FillRatio = 0.001, LenToFill = 1000, DiffParts = 0}
|
||||
end
|
||||
end
|
||||
-- verifico quale e' quella con meno scarto
|
||||
local nMinWasteRawIndex = GDB_ID.NULL
|
||||
local dMinWaste = 100000
|
||||
for ResultIndex = 1, #Results do
|
||||
if Results[ResultIndex] then
|
||||
local dWaste = (1 - Results[ResultIndex].FillRatio) * TempRaws[ResultIndex].LenToFill
|
||||
if Results[ResultIndex].DiffParts > 0 and dWaste < dMinWaste then
|
||||
dMinWaste = dWaste
|
||||
nMinWasteRawIndex = ResultIndex
|
||||
end
|
||||
end
|
||||
end
|
||||
-- verifico se ci sono pezzi
|
||||
if nMinWasteRawIndex > 0 and Results[nMinWasteRawIndex] and Results[nMinWasteRawIndex].DiffParts > 0 then
|
||||
-- riporto barra e pezzi nel risultato corrente
|
||||
local CurrBar = { BarLen = TempRaws[nMinWasteRawIndex].LenToFill, Parts = {}}
|
||||
local CurrX = TempRaws[nMinWasteRawIndex].StartGap
|
||||
local nInfoIndex = 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartIndex = Results[nMinWasteRawIndex].Data[i].Id
|
||||
local PartId = PartsToNest[PartIndex].Id
|
||||
local dLen = PartsToNest[PartIndex].Len
|
||||
for j = 1, Results[nMinWasteRawIndex].Data[i].Count do
|
||||
-- creo pezzo copia
|
||||
CurrPart = { Index = nInfoIndex, PartId = PartId, PosX = CurrX}
|
||||
table.insert( CurrBar.Parts, CurrPart)
|
||||
CurrX = CurrX + dLen + TempRaws[nMinWasteRawIndex].MidGap
|
||||
nInfoIndex = nInfoIndex + 1
|
||||
end
|
||||
end
|
||||
table.insert( CurrResult, CurrBar)
|
||||
dTotPartInRawLen = dTotPartInRawLen + ( Results[nMinWasteRawIndex].FillRatio * TempRaws[nMinWasteRawIndex].LenToFill)
|
||||
nRawTot = nRawTot + 1
|
||||
dRawTotLen = dRawTotLen + TempRaws[nMinWasteRawIndex].LenToFill
|
||||
-- Aggiorno per prossima iterazione
|
||||
TempRaws[nMinWasteRawIndex].Count = TempRaws[nMinWasteRawIndex].Count - 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartId = Results[nMinWasteRawIndex].Data[i].Id
|
||||
PartsToNest[PartId].Cnt = PartsToNest[PartId].Cnt - Results[nMinWasteRawIndex].Data[i].Count
|
||||
end
|
||||
else
|
||||
-- se non sono riuscito ad inserire alcun pezzo esco dal ciclo perche' non ci sono pezzi inseribili
|
||||
break
|
||||
end
|
||||
nCycle = nCycle + 1
|
||||
end
|
||||
-- riporto risultato in lista
|
||||
ResultList[Index] = dTotPartInRawLen
|
||||
if not BestResult or not BestResultIndex or
|
||||
( dTotPartInRawLen > ResultList[BestResultIndex] + 0.02 or ( abs( dTotPartInRawLen - ResultList[BestResultIndex]) < 0.02 and dRawTotLen < BestResult.RawTotLen - 0.02)) then
|
||||
BestResult = CurrResult
|
||||
BestResult.RawTotLen = dRawTotLen
|
||||
BestResultIndex = Index
|
||||
end
|
||||
end
|
||||
|
||||
local CycleCount = 0
|
||||
|
||||
local MinTime = 10 + pow( 3, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MinTime: ' .. MinTime ) end
|
||||
local MaxTime = 30 + pow( 7, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MaxTime: ' .. MaxTime ) end
|
||||
local TargetRatio = 0.98
|
||||
local dTargetRatioLen = TargetRatio * dTotLen
|
||||
if bLogStat then EgtOutLog('TargetRatioLen: ' .. dTargetRatioLen ) end
|
||||
local CurrTime = 0
|
||||
|
||||
local function NestSolutionFromSP( StartingPoint, OscillationStep)
|
||||
-- ciclo sulle possibilita' da un punto di origine con uno step fisso
|
||||
local CurrResultIndex = StartingPoint
|
||||
NestSolutionByIndex( StartingPoint)
|
||||
if OscillationStep == 0 then return end
|
||||
local CycleIndex = 1
|
||||
local nOutOfBoundary = 0
|
||||
while nOutOfBoundary ~= 3 do
|
||||
CurrTime = EgtStopCounter() / 1000
|
||||
if bLogStat then EgtOutLog('CurrTime: ' .. CurrTime ) end
|
||||
if bLogStat then EgtOutLog('BestRatio: ' .. dTotLen / BestResult.RawTotLen ) end
|
||||
-- se e' passato il tempo massimo, o e' passato il tempo minimo, ha inserito tutti i pezzi e la percentuale di utilizzo del materiale e' maggiore della soglia
|
||||
if CurrTime > MaxTime or ( CurrTime > MinTime and ResultList[BestResultIndex] > dTotLen - 0.1 and ( dTotLen / BestResult.RawTotLen ) >= TargetRatio) then
|
||||
if bLogStat then EgtOutLog('Brake') end
|
||||
break
|
||||
end
|
||||
local bCurrOutOfBoundary = false
|
||||
if CurrResultIndex < 0 then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 2 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 1
|
||||
end
|
||||
end
|
||||
if CurrResultIndex > #Parts then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 1 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 2
|
||||
end
|
||||
end
|
||||
if not bCurrOutOfBoundary and not ResultList[CurrResultIndex] then
|
||||
NestSolutionByIndex( CurrResultIndex)
|
||||
if bLogStat then EgtOutLog('CurrResultIndex: ' .. CurrResultIndex ) end
|
||||
if bLogStat then EgtOutLog('Result: ' .. ResultList[CurrResultIndex]) end
|
||||
CycleCount = CycleCount + 1
|
||||
end
|
||||
CurrResultIndex = StartingPoint + EgtIf( CycleIndex % 2 == 0, (CycleIndex / 2) * OscillationStep, -( ( CycleIndex + 1) / 2) * OscillationStep )
|
||||
CycleIndex = CycleIndex + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- lancio calcolo
|
||||
EgtStartCounter()
|
||||
local StartingResult = floor( #Parts * 0.3)
|
||||
if bLogStat then EgtOutLog('StartingResult: ' .. StartingResult ) end
|
||||
--local Step = floor( #Parts / 10) * floor( log10( #Parts))
|
||||
local nDividendo = pow( 10, floor( log10( #Parts)) - 1)
|
||||
nDividendo = EgtIf( nDividendo ~= 1, nDividendo, 10)
|
||||
local Step = floor( #Parts / nDividendo) * floor( log10( #Parts))
|
||||
if bLogStat then EgtOutLog('Step: ' .. Step ) end
|
||||
NestSolutionFromSP( StartingResult, Step)
|
||||
if Step > 1 then
|
||||
NestSolutionFromSP( StartingResult, 1)
|
||||
end
|
||||
|
||||
-- se esiste un MachGorup precedente
|
||||
local nPreviousNestIndex = 0
|
||||
local nLastMachGroupId = EgtGetLastMachGroup()
|
||||
if nLastMachGroupId then
|
||||
nPreviousNestIndex = EgtGetInfo( nLastMachGroupId, "NestIndex", 'i')
|
||||
end
|
||||
for nMachineIndex = 1, #NEST.MACHINELIST do
|
||||
local sMachineName = NEST.MACHINELIST[nMachineIndex]
|
||||
-- imposto macchina corrente
|
||||
EgtSetCurrMachine( sMachineName)
|
||||
-- elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
-- creo gruppi di lavorazione per risultato
|
||||
for nMachGroupIndex = 1, #BestResult do
|
||||
local CurrMachGroup = BestResult[nMachGroupIndex]
|
||||
-- creo gruppo di lavorazione
|
||||
local MachGroupName = NewMachGroupName()
|
||||
nMachGroup = EgtAddMachGroup( MachGroupName)
|
||||
EgtSetInfo( nMachGroup, "NestIndex", nPreviousNestIndex + nMachGroupIndex)
|
||||
EgtSetInfo( nMachGroup, "BARLEN", CurrMachGroup.BarLen)
|
||||
EgtSetInfo( nMachGroup, "MATERIAL", NEST.MATERIAL)
|
||||
EgtSetInfo( nMachGroup, "AUTONEST", 1)
|
||||
-- scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione
|
||||
EgtSetInfo( nMachGroup, "PRODID", NEST.PRODID)
|
||||
EgtSetInfo( nMachGroup, "PATTID", nMachGroup)
|
||||
-- Disegno i pezzi
|
||||
for i = 1, #CurrMachGroup.Parts do
|
||||
local CurrPart = CurrMachGroup.Parts[ i]
|
||||
-- creo pezzo copia
|
||||
local nPartDuploId = EgtDuploNew( CurrPart.PartId)
|
||||
EgtSetInfo( nMachGroup, "PART" .. CurrPart.Index, nPartDuploId .. "," .. CurrPart.PosX)
|
||||
-- se esiste lista etichette
|
||||
local sTagList = ''
|
||||
if #NEST.MACHINELIST == 1 then
|
||||
sTagList = EgtGetInfo( CurrPart.PartId, 'LuxTagList')
|
||||
else
|
||||
sTagList = EgtGetInfo( CurrPart.PartId, 'LuxTagList' .. nMachineIndex)
|
||||
if not sTagList or #sTagList <= 0 then
|
||||
sTagList = EgtGetInfo( CurrPart.PartId, 'LuxTagList')
|
||||
EgtSetInfo( CurrPart.PartId, 'LuxTagList' .. nMachineIndex, sTagList)
|
||||
end
|
||||
end
|
||||
if sTagList and #sTagList then
|
||||
-- elimino eventuali liste etichette da duplo
|
||||
EgtRemoveInfo( nPartDuploId, 'LuxTagList')
|
||||
for nRemoveTagMachineIndex = 1, nMachineIndex - 1 do
|
||||
EgtRemoveInfo( nPartDuploId, 'LuxTagList' .. nRemoveTagMachineIndex)
|
||||
end
|
||||
-- recupero liste etichette usate e non
|
||||
local TagTypeList = EgtSplitString( sTagList, ';')
|
||||
local UnusedTagList = {}
|
||||
local UsedTagList = {}
|
||||
if #TagTypeList == 1 then
|
||||
UnusedTagList = EgtSplitString( sTagList, ',')
|
||||
else
|
||||
if TagTypeList[1] and #TagTypeList[1] > 0 then
|
||||
UnusedTagList = EgtSplitString( TagTypeList[1], ',')
|
||||
end
|
||||
if TagTypeList[2] and #TagTypeList[2] > 0 then
|
||||
UsedTagList = EgtSplitString( TagTypeList[2], ',')
|
||||
end
|
||||
end
|
||||
local nAssignedTagIndex = #UnusedTagList
|
||||
local sAssignedTag = UnusedTagList[nAssignedTagIndex]
|
||||
-- creo stringa per info etichette aggiornata
|
||||
local sNewTagList = ''
|
||||
for nUnusedTagIndex = 1, nAssignedTagIndex - 1 do
|
||||
sNewTagList = sNewTagList .. UnusedTagList[nUnusedTagIndex] .. EgtIf( nUnusedTagIndex < nAssignedTagIndex - 1, ',', '')
|
||||
end
|
||||
sNewTagList = sNewTagList .. ';' .. UnusedTagList[nAssignedTagIndex] .. EgtIf( #UsedTagList > 0, ',', '')
|
||||
for nUsedTagIndex = 1, #UsedTagList do
|
||||
sNewTagList = sNewTagList .. UsedTagList[nUsedTagIndex] .. EgtIf( nUsedTagIndex < #UsedTagList, ',', '')
|
||||
end
|
||||
-- assegno etichetta a nuovo duplo
|
||||
EgtSetInfo( nPartDuploId, 'LuxTag', sAssignedTag)
|
||||
if #NEST.MACHINELIST == 1 then
|
||||
EgtSetInfo( CurrPart.PartId, 'LuxTagList', sNewTagList)
|
||||
else
|
||||
EgtSetInfo( CurrPart.PartId, 'LuxTagList' .. nMachineIndex, sNewTagList)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
EgtResetCurrMachGroup()
|
||||
end
|
||||
|
||||
-- creo grezzi per ogni gruppo di lavorazione
|
||||
local nRawCnt = 0
|
||||
local nRawTot = ResultList[BestResultIndex]
|
||||
_G.BEAM = {}
|
||||
BEAM.FILE = NEST.FILE
|
||||
--BEAM.MACHINE = NEST.MACHINE
|
||||
BEAM.FLAG = 6 -- CREATE_PANEL
|
||||
BEAM.BASEDIR = NEST.BASEDIR
|
||||
nMachGroup = EgtGetFirstMachGroup()
|
||||
while nMachGroup do
|
||||
local nNextMachGroup = EgtGetNextMachGroup( nMachGroup)
|
||||
EgtSetCurrMachGroup( nMachGroup)
|
||||
if EgtGetInfo( nMachGroup, "AUTONEST",'i') == 1 then
|
||||
EgtRemoveInfo( nMachGroup, "AUTONEST")
|
||||
EgtSetInfo( nMachGroup, "UPDATEUI", 1)
|
||||
local bOk, sErr = pcall( dofile, BEAM.BASEDIR .. "\\BatchProcessNew.lua")
|
||||
if not bOk then
|
||||
EgtOutLog( 'Error in BatchProcessNew.lua call (' .. ( sErr or '') ..')')
|
||||
end
|
||||
nRawCnt = nRawCnt + 1
|
||||
-- aggiorno interfaccia
|
||||
EgtProcessEvents( 200 + ( nRawCnt / nRawTot * 100), 0)
|
||||
end
|
||||
nMachGroup = nNextMachGroup
|
||||
end
|
||||
|
||||
EgtResetCurrMachGroup()
|
||||
|
||||
NEST.ERR = 0
|
||||
|
||||
EgtOutLog( ' +++ BeamNestProcess completed')
|
||||
@@ -0,0 +1,477 @@
|
||||
-- BeamNestProcess.lua by Egaltech s.r.l. 2023/01/15
|
||||
-- Gestione nesting automatico travi
|
||||
-- 2022/10/05 Piccole modifiche per far funzionare correttamente i compilati.
|
||||
-- 2022/10/06 Corretto bug che moltiplicava i pezzi se erano presenti più grezzi della stessa sezione.
|
||||
-- 2023/01/15 Piccole correzioni.
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Per test
|
||||
--NEST = {}
|
||||
--NEST.FILE = 'c:\\TechnoEssetre7\\EgtData\\Prods\\0010\\Bar_10_1.btl'
|
||||
--NEST.MACHINE = 'Essetre-90480019_MW'
|
||||
--NEST.FLAG = 3
|
||||
|
||||
local sLog = ' +++ BeamNestProcess : ' .. NEST.FILE .. ', ' .. NEST.MACHINE .. ', ' .. LEN[1]
|
||||
EgtOutLog( sLog)
|
||||
|
||||
-- flag per abilitare statistiche in log
|
||||
local bLogStat = false
|
||||
|
||||
-- Cancello file di log specifico
|
||||
local sLogFile = EgtChangePathExtension( NEST.FILE, '.txt')
|
||||
EgtEraseFile( sLogFile)
|
||||
|
||||
-- Funzioni per scrittura su file di log specifico
|
||||
local function WriteErrToLogFile( nErr, sMsg, nRot, nCutId, nTaskId)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'ERR=' .. tostring( nErr) .. '\n')
|
||||
hFile:write( sMsg .. '\n')
|
||||
hFile:write( 'ROT=' .. tostring( nRot or 0) .. '\n')
|
||||
hFile:write( 'CUTID=' .. tostring( nCutId or 0) .. '\n')
|
||||
hFile:write( 'TASKID=' .. tostring( nTaskId or 0) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
local function WriteTimeToLogFile( dTime)
|
||||
local hFile = io.open( sLogFile, 'a')
|
||||
hFile:write( 'TIME=' .. EgtNumToString( dTime) .. '\n')
|
||||
hFile:close()
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo errore
|
||||
local function PostErrView( nErr, sMsg)
|
||||
if nErr ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (err=' .. tostring( nErr) .. ')', 'ERRORS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per gestire visualizzazione dopo warning
|
||||
local function PostWarnView( nWarn, sMsg)
|
||||
if nWarn ~= 0 and ( NEST.FLAG == 1 or NEST.FLAG == 2 or NEST.FLAG == 5) then
|
||||
EgtSetView( SCE_VD.ISO_SW, false)
|
||||
EgtZoom( SCE_ZM.ALL)
|
||||
EgtOutBox( sMsg, 'BatchProcess (wrn=' .. tostring( nWarn) .. ')', 'WARNINGS')
|
||||
end
|
||||
end
|
||||
|
||||
-- Funzione per aggiornare dati ausiliari
|
||||
local function UpdateAuxData( sAuxFile)
|
||||
local bModif = false
|
||||
-- Se definito LOAD90, aggiorno
|
||||
local sLoad90 = EgtGetStringFromIni( 'AuxData', 'LOAD90', '', sAuxFile)
|
||||
if sLoad90 ~= '' then
|
||||
local BtlInfoId = EgtGetFirstNameInGroup( GDB_ID.ROOT, 'BtlInfo') or GDB_ID.NULL
|
||||
EgtSetInfo( BtlInfoId, 'LOAD90', sLoad90)
|
||||
bModif = true
|
||||
end
|
||||
return bModif
|
||||
end
|
||||
|
||||
local function PartsToFill( Parts)
|
||||
local nToFill = 0
|
||||
for i = 1, #Parts do
|
||||
if Parts[i].Cnt > 0 then
|
||||
nToFill = nToFill + Parts[i].Cnt
|
||||
end
|
||||
end
|
||||
return nToFill
|
||||
end
|
||||
|
||||
local function ExecMaximumFilling( Raw, Parts)
|
||||
-- Inizializzo maximum filler
|
||||
EgtMaxFillerStart()
|
||||
-- Inserisco i pezzi
|
||||
for i = 1, #Parts do
|
||||
EgtMaxFillerAddPart( i, Parts[i].Len, Parts[i].DispLen or Parts[i].Len, Parts[i].Cnt or 1)
|
||||
end
|
||||
-- Eseguo l'ottimizzazione
|
||||
EgtMaxFillerCompute( Raw.LenToFill, Raw.StartGap, Raw.MidGap, Raw.EndGap, Raw.SortType)
|
||||
-- Recupero i risultati
|
||||
local nFilledParts, nDiffParts, dTotFillRatio = EgtMaxFillerGetResults()
|
||||
local OneRes = {}
|
||||
for i = 0, nDiffParts - 1 do
|
||||
local nPartId, nCount = EgtMaxFillerGetOneResult( i)
|
||||
table.insert( OneRes, { Id=nPartId, Count=nCount})
|
||||
end
|
||||
--return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Time=dTime, Data=OneRes}
|
||||
return { FilledParts=nFilledParts, DiffParts=nDiffParts, FillRatio=dTotFillRatio, Data=OneRes}
|
||||
end
|
||||
|
||||
-- Funzione per trovare nome MachGroup
|
||||
local function NewMachGroupName()
|
||||
local nMachGroupId = EgtGetFirstMachGroup()
|
||||
if not nMachGroupId then return 1 end
|
||||
local nMaxMachGroup = 0
|
||||
while nMachGroupId do
|
||||
sMachGroupName = EgtGetMachGroupName(nMachGroupId)
|
||||
local nMachGroupName = tonumber(sMachGroupName)
|
||||
if nMachGroupName > nMaxMachGroup then
|
||||
nMaxMachGroup = nMachGroupName
|
||||
end
|
||||
nMachGroupId = EgtGetNextMachGroup(nMachGroupId)
|
||||
end
|
||||
return nMaxMachGroup + 1
|
||||
end
|
||||
|
||||
local function TotRawCount(Raws)
|
||||
local nTotRaws = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
nTotRaws = nTotRaws + Raws[RawIndex].Count
|
||||
end
|
||||
return nTotRaws
|
||||
end
|
||||
|
||||
local function TotPartLen(Parts)
|
||||
local nTotPartLen = 0
|
||||
for PartIndex = 1, #Parts do
|
||||
nTotPartLen = nTotPartLen + ( Parts[PartIndex].Len * Parts[PartIndex].Cnt)
|
||||
end
|
||||
return nTotPartLen
|
||||
end
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( NEST.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
|
||||
-- Imposto la macchina corrente e verifico sia abilitata per la lavorazione delle Travi
|
||||
EgtSetCurrMachine( NEST.MACHINE)
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamData.lua') then
|
||||
NEST.ERR = 12
|
||||
NEST.MSG = 'Error not configured for beam machine : ' .. sMachine
|
||||
WriteErrToLogFile( NEST.ERR, NEST.MSG)
|
||||
PostErrView( NEST.ERR, NEST.MSG)
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Inizializzo contatori errori e avvisi
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
|
||||
-- Grezzi
|
||||
local Raws = {}
|
||||
-- creo tabella dei grezzi
|
||||
for nIndex, nLen in pairs( LEN) do
|
||||
Raws[tonumber(nIndex)] = {LenToFill = nLen, StartGap = NEST.STARTOFFSET, MidGap = NEST.OFFSET, EndGap = 0, SortType = -1}
|
||||
end
|
||||
for nIndex, nQty in pairs( QTY) do
|
||||
Raws[tonumber(nIndex)].Count = nQty
|
||||
end
|
||||
-- cerco il grezzo con la lunghezza maggiore, epurata dello start gap
|
||||
local maxRawLenToFillNoStartGap = 0
|
||||
for RawIndex = 1, #Raws do
|
||||
if Raws[RawIndex].Count > 0 then
|
||||
maxRawLenToFillNoStartGap = max( maxRawLenToFillNoStartGap, Raws[RawIndex].LenToFill - Raws[RawIndex].StartGap)
|
||||
end
|
||||
end
|
||||
|
||||
-- Pezzi
|
||||
local Parts = {}
|
||||
-- ciclo su pezzi per aggiungerli al nesting
|
||||
local dTotLen = 0
|
||||
for nPartId, nCount in pairs( PART) do
|
||||
-- recupero lunghezza pezzo
|
||||
local Len = EgtGetInfo( nPartId, "L", 'd')
|
||||
local DispLen = EgtIf( Len <= 1000, 2000, 0) --EgtIf( Len <= 2000, max( 2000, 6000 - Len), 0)
|
||||
-- aggiungo il pezzo solo se ci sta nel grezzo più lungo a disposizione
|
||||
if Len < maxRawLenToFillNoStartGap then
|
||||
for nCntIndex = 1 , nCount do
|
||||
table.insert( Parts, {Id = nPartId, Len = Len, DispLen = DispLen, Cnt = 1})
|
||||
dTotLen = dTotLen + Len
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- lunghezza totale pezzi
|
||||
local dTotPartLen = TotPartLen( Parts)
|
||||
-- calcolo media delle barre necessarie
|
||||
local NeededRawsForType = {}
|
||||
for RawIndex = 1, #Raws do
|
||||
NeededRawsForType[RawIndex] = min( ceil( dTotPartLen / Raws[RawIndex].LenToFill), Raws[RawIndex].Count)
|
||||
end
|
||||
local RawQtySum = 0
|
||||
for NeededRawIndex = 1, #NeededRawsForType do
|
||||
RawQtySum = RawQtySum + NeededRawsForType[NeededRawIndex]
|
||||
end
|
||||
local MediumRawQty = ceil( RawQtySum / #NeededRawsForType)
|
||||
if MediumRawQty > 1 then
|
||||
MediumRawQty = MediumRawQty - 1
|
||||
end
|
||||
|
||||
-- lista dei risultati
|
||||
local ResultList = {}
|
||||
local BestResult = nil
|
||||
local BestResultIndex = nil
|
||||
-- riordino lista pezzi per lunghezza
|
||||
table.sort( Parts, function( B1, B2) return B1.Len < B2.Len end)
|
||||
|
||||
local function NestSolutionByIndex( Index)
|
||||
|
||||
-- creo copia lista raw
|
||||
local TempRaws = {}
|
||||
for TempRawIndex = 1, #Raws do
|
||||
table.insert(TempRaws, {LenToFill = Raws[TempRawIndex].LenToFill, StartGap = Raws[TempRawIndex].StartGap, MidGap = Raws[TempRawIndex].MidGap, EndGap = Raws[TempRawIndex].EndGap, SortType = Raws[TempRawIndex].SortType, Count = Raws[TempRawIndex].Count})
|
||||
end
|
||||
|
||||
-- recupero pezzi corti
|
||||
local ShortList = {}
|
||||
local LongList = {}
|
||||
|
||||
for PartIndex = 1, #Parts do
|
||||
if PartIndex <= Index then
|
||||
table.insert( ShortList, Parts[PartIndex])
|
||||
else
|
||||
table.insert( LongList, Parts[PartIndex])
|
||||
end
|
||||
Parts[PartIndex].Cnt = 1
|
||||
end
|
||||
-- numero di pezzi piccoli per barra
|
||||
local ShortCount = Index
|
||||
local ShortForRaw = floor( ShortCount / MediumRawQty)
|
||||
local ExtraShortForRaw = 0
|
||||
if MediumRawQty > 0 then
|
||||
ExtraShortForRaw = fmod( ShortCount, MediumRawQty)
|
||||
end
|
||||
-- creo lista pezzi corti singoli
|
||||
local SingleShortList = {}
|
||||
for ShortIndex = 1, #ShortList do
|
||||
for ShortCount = 1, ShortList[ShortIndex].Cnt do
|
||||
table.insert( SingleShortList, {Id = ShortList[ShortIndex].Id, Len = ShortList[ShortIndex].Len, DispLen = ShortList[ShortIndex].DispLen, Cnt = 1})
|
||||
end
|
||||
end
|
||||
-- li divido per le barre previste
|
||||
local RawsShortList = {}
|
||||
local RawIndex = 0
|
||||
local ShortRawIndex = 0
|
||||
for ShortIndex = 1, #SingleShortList do
|
||||
if ShortRawIndex > 0 then
|
||||
table.insert( RawsShortList[RawIndex], SingleShortList[ShortIndex])
|
||||
ShortRawIndex = ShortRawIndex - 1
|
||||
else
|
||||
table.insert( RawsShortList, {SingleShortList[ShortIndex]})
|
||||
RawIndex = RawIndex + 1
|
||||
ShortRawIndex = ShortForRaw + EgtIf( RawIndex <= ExtraShortForRaw, 1, 0) - 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Ciclo fino ad esaurimento pezzi o barre
|
||||
local dTotPartInRawLen = 0
|
||||
local nRawTot = 0
|
||||
local dRawTotLen = 0
|
||||
local dTime = 0
|
||||
local nCycle = 1
|
||||
local CurrResult = {}
|
||||
while TotRawCount( TempRaws) > 0 and PartsToFill( Parts) > 0 do
|
||||
|
||||
-- creo lista con pezzi lunghi e pezzi corti di questo Cycle
|
||||
local PartsToNest = {}
|
||||
for PartIndex = 1, #LongList do
|
||||
table.insert( PartsToNest, LongList[PartIndex])
|
||||
end
|
||||
for CycleIndex = 1, #RawsShortList do
|
||||
if CycleIndex <= nCycle then
|
||||
for PartIndex = 1, #RawsShortList[CycleIndex] do
|
||||
table.insert( PartsToNest, RawsShortList[CycleIndex][PartIndex])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se non ci sono pezzi da nestare, esco
|
||||
if PartsToFill( PartsToNest) <= 0 then
|
||||
break
|
||||
end
|
||||
-- Eseguo ottimizzazione per ogni lunghezza di barra
|
||||
local Results = {}
|
||||
for RawIndex = 1, #TempRaws do
|
||||
if TempRaws[RawIndex].Count > 0 then
|
||||
Results[RawIndex] = ExecMaximumFilling( TempRaws[RawIndex], PartsToNest)
|
||||
else
|
||||
Results[RawIndex] = { FillRatio = 0.001, LenToFill = 1000, DiffParts = 0}
|
||||
end
|
||||
end
|
||||
-- verifico quale e' quella con meno scarto
|
||||
local nMinWasteRawIndex = GDB_ID.NULL
|
||||
local dMinWaste = 100000
|
||||
for ResultIndex = 1, #Results do
|
||||
if Results[ResultIndex] then
|
||||
local dWaste = (1 - Results[ResultIndex].FillRatio) * TempRaws[ResultIndex].LenToFill
|
||||
if Results[ResultIndex].DiffParts > 0 and dWaste < dMinWaste then
|
||||
dMinWaste = dWaste
|
||||
nMinWasteRawIndex = ResultIndex
|
||||
end
|
||||
end
|
||||
end
|
||||
-- verifico se ci sono pezzi
|
||||
if nMinWasteRawIndex > 0 and Results[nMinWasteRawIndex] and Results[nMinWasteRawIndex].DiffParts > 0 then
|
||||
-- riporto barra e pezzi nel risultato corrente
|
||||
local CurrBar = { BarLen = TempRaws[nMinWasteRawIndex].LenToFill, Parts = {}}
|
||||
local CurrX = TempRaws[nMinWasteRawIndex].StartGap
|
||||
local nInfoIndex = 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartIndex = Results[nMinWasteRawIndex].Data[i].Id
|
||||
local PartId = PartsToNest[PartIndex].Id
|
||||
local dLen = PartsToNest[PartIndex].Len
|
||||
for j = 1, Results[nMinWasteRawIndex].Data[i].Count do
|
||||
-- creo pezzo copia
|
||||
CurrPart = { Index = nInfoIndex, PartId = PartId, PosX = CurrX}
|
||||
table.insert( CurrBar.Parts, CurrPart)
|
||||
CurrX = CurrX + dLen + TempRaws[nMinWasteRawIndex].MidGap
|
||||
nInfoIndex = nInfoIndex + 1
|
||||
end
|
||||
end
|
||||
table.insert( CurrResult, CurrBar)
|
||||
dTotPartInRawLen = dTotPartInRawLen + ( Results[nMinWasteRawIndex].FillRatio * TempRaws[nMinWasteRawIndex].LenToFill)
|
||||
nRawTot = nRawTot + 1
|
||||
dRawTotLen = dRawTotLen + TempRaws[nMinWasteRawIndex].LenToFill
|
||||
-- Aggiorno per prossima iterazione
|
||||
TempRaws[nMinWasteRawIndex].Count = TempRaws[nMinWasteRawIndex].Count - 1
|
||||
for i = 1, Results[nMinWasteRawIndex].DiffParts do
|
||||
local PartId = Results[nMinWasteRawIndex].Data[i].Id
|
||||
PartsToNest[PartId].Cnt = PartsToNest[PartId].Cnt - Results[nMinWasteRawIndex].Data[i].Count
|
||||
end
|
||||
else
|
||||
-- se non sono riuscito ad inserire alcun pezzo esco dal ciclo perche' non ci sono pezzi inseribili
|
||||
break
|
||||
end
|
||||
nCycle = nCycle + 1
|
||||
end
|
||||
-- riporto risultato in lista
|
||||
ResultList[Index] = dTotPartInRawLen
|
||||
if not BestResult or not BestResultIndex or
|
||||
( dTotPartInRawLen > ResultList[BestResultIndex] + 0.02 or ( abs( dTotPartInRawLen - ResultList[BestResultIndex]) < 0.02 and dRawTotLen < BestResult.RawTotLen - 0.02)) then
|
||||
BestResult = CurrResult
|
||||
BestResult.RawTotLen = dRawTotLen
|
||||
BestResultIndex = Index
|
||||
end
|
||||
end
|
||||
|
||||
local CycleCount = 0
|
||||
|
||||
local MinTime = 10 + pow( 3, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MinTime: ' .. MinTime ) end
|
||||
local MaxTime = 30 + pow( 7, ceil( log10( #Parts)) - 1)
|
||||
if bLogStat then EgtOutLog('MaxTime: ' .. MaxTime ) end
|
||||
local TargetRatio = 0.98
|
||||
local dTargetRatioLen = TargetRatio * dTotLen
|
||||
if bLogStat then EgtOutLog('TargetRatioLen: ' .. dTargetRatioLen ) end
|
||||
local CurrTime = 0
|
||||
|
||||
local function NestSolutionFromSP( StartingPoint, OscillationStep)
|
||||
-- ciclo sulle possibilita' da un punto di origine con uno step fisso
|
||||
local CurrResultIndex = StartingPoint
|
||||
NestSolutionByIndex( StartingPoint)
|
||||
if OscillationStep == 0 then return end
|
||||
local CycleIndex = 1
|
||||
local nOutOfBoundary = 0
|
||||
while nOutOfBoundary ~= 3 do
|
||||
CurrTime = EgtStopCounter() / 1000
|
||||
if bLogStat then EgtOutLog('CurrTime: ' .. CurrTime ) end
|
||||
if bLogStat then EgtOutLog('BestRatio: ' .. dTotLen / BestResult.RawTotLen ) end
|
||||
-- se e' passato il tempo massimo, o e' passato il tempo minimo, ha inserito tutti i pezzi e la percentuale di utilizzo del materiale e' maggiore della soglia
|
||||
if CurrTime > MaxTime or ( CurrTime > MinTime and ResultList[BestResultIndex] > dTotLen - 0.1 and ( dTotLen / BestResult.RawTotLen ) >= TargetRatio) then
|
||||
if bLogStat then EgtOutLog('Brake') end
|
||||
break
|
||||
end
|
||||
local bCurrOutOfBoundary = false
|
||||
if CurrResultIndex < 0 then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 2 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 1
|
||||
end
|
||||
end
|
||||
if CurrResultIndex > #Parts then
|
||||
bCurrOutOfBoundary = true
|
||||
if nOutOfBoundary == 1 then
|
||||
nOutOfBoundary = 3
|
||||
else
|
||||
nOutOfBoundary = 2
|
||||
end
|
||||
end
|
||||
if not bCurrOutOfBoundary and not ResultList[CurrResultIndex] then
|
||||
NestSolutionByIndex( CurrResultIndex)
|
||||
if bLogStat then EgtOutLog('CurrResultIndex: ' .. CurrResultIndex ) end
|
||||
if bLogStat then EgtOutLog('Result: ' .. ResultList[CurrResultIndex]) end
|
||||
CycleCount = CycleCount + 1
|
||||
end
|
||||
CurrResultIndex = StartingPoint + EgtIf( CycleIndex % 2 == 0, (CycleIndex / 2) * OscillationStep, -( ( CycleIndex + 1) / 2) * OscillationStep )
|
||||
CycleIndex = CycleIndex + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- lancio calcolo
|
||||
EgtStartCounter()
|
||||
local StartingResult = floor( #Parts * 0.3)
|
||||
if bLogStat then EgtOutLog('StartingResult: ' .. StartingResult ) end
|
||||
--local Step = floor( #Parts / 10) * floor( log10( #Parts))
|
||||
local nDividendo = pow( 10, floor( log10( #Parts)) - 1)
|
||||
nDividendo = EgtIf( nDividendo ~= 1, nDividendo, 10)
|
||||
local Step = floor( #Parts / nDividendo) * floor( log10( #Parts))
|
||||
if bLogStat then EgtOutLog('Step: ' .. Step ) end
|
||||
NestSolutionFromSP( StartingResult, Step)
|
||||
if Step > 1 then
|
||||
NestSolutionFromSP( StartingResult, 1)
|
||||
end
|
||||
|
||||
-- creo gruppi di lavorazione per risultato
|
||||
for MachGroupIndex = 1, #BestResult do
|
||||
local CurrMachGroup = BestResult[ MachGroupIndex]
|
||||
-- creo gruppo di lavorazione
|
||||
local MachGroupName = NewMachGroupName()
|
||||
nMachGroup = EgtAddMachGroup( MachGroupName)
|
||||
EgtSetInfo( nMachGroup, "BARLEN", CurrMachGroup.BarLen)
|
||||
EgtSetInfo( nMachGroup, "MATERIAL", NEST.MATERIAL)
|
||||
EgtSetInfo( nMachGroup, "AUTONEST", 1)
|
||||
-- scrivo dati per variabili P di comunicazione con la macchina in gruppo di lavorazione
|
||||
EgtSetInfo( nMachGroup, "PRODID", NEST.PRODID)
|
||||
EgtSetInfo( nMachGroup, "PATTID", nMachGroup)
|
||||
-- Disegno i pezzi
|
||||
for i = 1, #CurrMachGroup.Parts do
|
||||
local CurrPart = CurrMachGroup.Parts[ i]
|
||||
-- creo pezzo copia
|
||||
local nPartDuploId = EgtDuploNew( CurrPart.PartId)
|
||||
EgtSetInfo( nMachGroup, "PART" .. CurrPart.Index, nPartDuploId .. "," .. CurrPart.PosX)
|
||||
end
|
||||
end
|
||||
|
||||
-- creo grezzi per ogni gruppo di lavorazione
|
||||
local nRawCnt = 0
|
||||
local nRawTot = ResultList[BestResultIndex]
|
||||
_G.BEAM = {}
|
||||
BEAM.FILE = NEST.FILE
|
||||
BEAM.MACHINE = NEST.MACHINE
|
||||
BEAM.FLAG = 6 -- CREATE_PANEL
|
||||
BEAM.BASEDIR = NEST.BASEDIR
|
||||
nMachGroup = EgtGetFirstMachGroup()
|
||||
while nMachGroup do
|
||||
local nNextMachGroup = EgtGetNextMachGroup( nMachGroup)
|
||||
EgtSetCurrMachGroup( nMachGroup)
|
||||
if EgtGetInfo( nMachGroup, "AUTONEST",'i') == 1 then
|
||||
EgtRemoveInfo( nMachGroup, "AUTONEST")
|
||||
EgtSetInfo( nMachGroup, "UPDATEUI", 1)
|
||||
local bOk, sErr = pcall( dofile, BEAM.BASEDIR .. "\\BatchProcessNew.lua")
|
||||
if not bOk then
|
||||
EgtOutLog( 'Error in BatchProcessNew.lua call (' .. ( sErr or '') ..')')
|
||||
end
|
||||
nRawCnt = nRawCnt + 1
|
||||
-- aggiorno interfaccia
|
||||
EgtProcessEvents( 200 + ( nRawCnt / nRawTot * 100), 0)
|
||||
end
|
||||
nMachGroup = nNextMachGroup
|
||||
end
|
||||
|
||||
EgtResetCurrMachGroup()
|
||||
|
||||
NEST.ERR = 0
|
||||
|
||||
EgtOutLog( ' +++ BeamNestProcess completed')
|
||||
@@ -0,0 +1,396 @@
|
||||
-- Process.lua by Egalware s.r.l. 2024/04/02
|
||||
-- Gestione calcolo disposizione e lavorazioni per Travi
|
||||
-- Si opera sulla macchina corrente
|
||||
-- 2024/04/02 PRIMA VERSIONE
|
||||
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
-- Imposto direttorio libreria specializzata per Travi
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\LuaLibs\\?.lua')
|
||||
-- Imposto direttorio strategie. N.B. Le strategie dovranno essere caricate con il nome del direttorio padre
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\Strategies\\Standard\\?.lua')
|
||||
EgtAddToPackagePath( BEAM.BASEDIR .. '\\StrategyLibs\\?.lua')
|
||||
|
||||
-- Verifico che la macchina corrente sia abilitata per la lavorazione delle Travi
|
||||
local sMachDir = EgtGetCurrMachineDir()
|
||||
if not sMachDir then
|
||||
EgtOutBox( 'Errore nel caricamento della macchina corrente', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
if not EgtExistsFile( sMachDir .. '\\Beam\\BeamDataNew.lua') then
|
||||
EgtOutBox( 'La macchina corrente non è configurata per lavorare travi', 'Lavora Travi', 'ERROR')
|
||||
return
|
||||
end
|
||||
|
||||
-- Elimino direttori altre macchine e imposto direttorio macchina corrente per ricerca librerie
|
||||
EgtRemoveBaseMachineDirFromPackagePath()
|
||||
EgtAddToPackagePath( sMachDir .. '\\Beam\\?.lua')
|
||||
|
||||
-- Segnalazione avvio
|
||||
EgtOutLog( '*** Beam Process Start ***', 1)
|
||||
|
||||
-- Carico le librerie
|
||||
_G.package.loaded.BasicCustomerStrategies = nil
|
||||
_G.package.loaded.BeamExec = nil
|
||||
_G.package.loaded.BeamLib = nil
|
||||
_G.package.loaded.DiceCut = nil
|
||||
_G.package.loaded.FaceData = nil
|
||||
_G.package.loaded.FeatureLib = nil
|
||||
_G.package.loaded.Identity = nil
|
||||
_G.package.loaded.Logs = nil
|
||||
_G.package.loaded.MachiningLib = nil
|
||||
_G.package.loaded.PreSimulationLib = nil
|
||||
_G.package.loaded.LeadInOutLib = nil
|
||||
-- strategie di base sempre presenti
|
||||
_G.package.loaded['HEADCUT\\HEADCUT'] = nil
|
||||
_G.package.loaded['TAILCUT\\TAILCUT'] = nil
|
||||
-- libreria macchina
|
||||
_G.package.loaded.BeamDataNew = nil
|
||||
-- libreria calcolo tempo esecuzione
|
||||
_G.package.loaded.TimeLib = nil
|
||||
|
||||
-- TODO controllare se c'è un modo migliore per resettare librerie delle strategie caricate precedentemente
|
||||
-- Per ottimizzare potremmo anche ciclare solo fino al numero di strategie raggiunto per il momento.
|
||||
-- Infatti difficile ci siano 9999 strategie.
|
||||
-- reset strategie caricate come librerie
|
||||
for i = 1, 9999 do
|
||||
local idSTRTemp = EgtReplaceString( EgtNumToString( i/10000, -4), '0.', '')
|
||||
local sLibraryToReload = "STR" .. idSTRTemp .. "\\STR" .. idSTRTemp
|
||||
if _G.package.loaded[sLibraryToReload] then
|
||||
_G.package.loaded[sLibraryToReload] = nil
|
||||
end
|
||||
end
|
||||
local vtCoreStrategiesNames = EgtFindAllFiles( BEAM.BASEDIR .. '\\StrategyLibs\\*.lua')
|
||||
for i = 1, #vtCoreStrategiesNames do
|
||||
local sCurrentName = EgtSplitString( vtCoreStrategiesNames[i], '.')[1]
|
||||
if _G.package.loaded[sCurrentName] then
|
||||
_G.package.loaded[sCurrentName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Variabili globali
|
||||
PARTS = {} -- tabella contenente tutte le informazioni di ogni pezzo
|
||||
|
||||
-- Carico i dati globali
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
-- carico librerie
|
||||
local BeamExec = require( 'BeamExec')
|
||||
local BeamLib = require( 'BeamLib')
|
||||
|
||||
-- Variabili di modulo
|
||||
local dRawW
|
||||
local dRawH
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Recupero le travi selezionate ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessInputData()
|
||||
|
||||
-- Recupero le travi selezionate
|
||||
local nId = EgtGetFirstSelectedObj()
|
||||
while nId do
|
||||
local nPartId = EgtGetParent( EgtGetParent( nId or GDB_ID.NULL) or GDB_ID.NULL)
|
||||
if nPartId then
|
||||
local bFound = false
|
||||
for i = 1, #PARTS do
|
||||
if PARTS[i].id == nPartId then
|
||||
bFound = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not bFound then
|
||||
table.insert( PARTS, { nInd = #PARTS + 1, id = nPartId, sName = ( EgtGetName( nPartId) or ( 'Id=' .. tonumber( nPartId)))})
|
||||
end
|
||||
end
|
||||
nId = EgtGetNextSelectedObj()
|
||||
end
|
||||
if #PARTS == 0 then
|
||||
EgtOutBox( 'Non sono state selezionate travi', 'Lavora Travi', 'ERROR')
|
||||
return false
|
||||
else
|
||||
local sOut = ''
|
||||
for i = 1, #PARTS do
|
||||
sOut = sOut .. PARTS[i].sName .. ', '
|
||||
end
|
||||
sOut = sOut:sub( 1, -3)
|
||||
EgtOutLog( 'Travi selezionate : ' .. sOut, 1)
|
||||
end
|
||||
|
||||
-- Ne recupero e verifico le dimensioni
|
||||
for i = 1, #PARTS do
|
||||
local Ls = EgtGetFirstNameInGroup( PARTS[i].id, 'Box')
|
||||
local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
if not b3Solid then
|
||||
EgtOutBox( 'Box non definito per la trave ' .. PARTS[i].sName, 'Lavora Travi', 'ERROR')
|
||||
return false
|
||||
else
|
||||
PARTS[i].b3PartOriginal = b3Solid
|
||||
end
|
||||
end
|
||||
dRawW = PARTS[1].b3PartOriginal:getDimY()
|
||||
dRawH = PARTS[1].b3PartOriginal:getDimZ()
|
||||
local vBeamErr = {}
|
||||
for i = 2, #PARTS do
|
||||
local dDimW = PARTS[i].b3PartOriginal:getDimY()
|
||||
local dDimH = PARTS[i].b3PartOriginal:getDimZ()
|
||||
if ( abs( dDimW - dRawW) > 10 * GEO.EPS_SMALL or abs( dDimH - dRawH) > 10 * GEO.EPS_SMALL) and
|
||||
( abs( dDimH - dRawW) > 10 * GEO.EPS_SMALL or abs( dDimW - dRawH) > 10 * GEO.EPS_SMALL) then
|
||||
table.insert( vBeamErr, i)
|
||||
end
|
||||
end
|
||||
if #vBeamErr > 0 then
|
||||
local sOut = 'Rimosse travi con sezioni diverse dalla prima :\n'
|
||||
for i = #vBeamErr, 1, -1 do
|
||||
sOut = sOut .. PARTS[vBeamErr[i]].sName .. '\n'
|
||||
EgtDeselectPartObjs( PARTS[vBeamErr[i]].id)
|
||||
table.remove( PARTS, vBeamErr[i])
|
||||
end
|
||||
EgtOutLog( sOut, 1)
|
||||
EgtOutBox( sOut, 'Lavora Travi', 'INFO')
|
||||
EgtDraw()
|
||||
return false
|
||||
end
|
||||
EgtDeselectAll()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetDataConfig()
|
||||
-- recupero utensili dal magazzino
|
||||
BeamExec.GetToolsFromDB()
|
||||
-- TODO da gestire eventuali errori bloccanti
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Inserimento delle travi nel grezzo ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessBeams()
|
||||
-- Determinazione minimo grezzo scaricabile
|
||||
BeamExec.CalcMinUnloadableRaw( dRawW, dRawH)
|
||||
|
||||
-- Lunghezza totale delle travi
|
||||
local dTotLen = 0
|
||||
for i = 1, #PARTS - 1 do
|
||||
dTotLen = dTotLen + PARTS[i].b3PartOriginal:getDimX()
|
||||
end
|
||||
dTotLen = dTotLen + max( PARTS[#PARTS].b3PartOriginal:getDimX(), BeamData.dMinRaw)
|
||||
local dAddLen = BeamData.OVM_HEAD + ( #PARTS - 1) * BeamData.OVM_MID
|
||||
EgtOutLog( 'Ltot : '..EgtNumToString( dTotLen, 1) .. ' Lagg : '..EgtNumToString( dAddLen, 1)..' MinUnloadRaw : '.. EgtNumToString( BeamData.dMinRaw + BeamData.OVM_MID, 1), 1)
|
||||
|
||||
-- Richiedo lunghezza del grezzo, sovramateriale di testa, forzatura verticale e ordinamento automatico secondo la lunghezza
|
||||
local vsVal = EgtDialogBox( 'Lavora Travi' .. ' (Ltot='..EgtNumToString( dTotLen + dAddLen + 0.5, 0)..
|
||||
', Lmax='..EgtNumToString( BeamData.MAX_RAW, 0)..',MinUlr='..EgtNumToString( BeamData.dMinRaw + BeamData.OVM_MID, 0)..')',
|
||||
--{'Lunghezza grezzo', EgtNumToString( BeamData.STD_RAW, 0)}, -- TODO RIPRISTINARE
|
||||
{'Lunghezza grezzo', EgtNumToString( 0)},
|
||||
{'Sovramateriale di testa', EgtNumToString( BeamData.OVM_HEAD, 0)},
|
||||
{'Offset intermedio', EgtNumToString( BeamData.OVM_MID, 0)},
|
||||
{'Forza sezione verticale', ' CB:true,*false'},
|
||||
{'Ordina per lunghezza', ' CB:true,*false'},
|
||||
{'Calcolo Lavorazioni', ' CB:*Da progetto,Ricalcolo standard,Ricalcolo IA'})
|
||||
if not vsVal then
|
||||
EgtDraw()
|
||||
return
|
||||
end
|
||||
local dRawL = EgtEvalNumExpr( vsVal[1])
|
||||
if not dRawL then
|
||||
local sOut = 'Lunghezza grezzo errata : ' .. vsVal[1]
|
||||
EgtOutLog( sOut)
|
||||
EgtOutBox( sOut, 'Lavora Travi', 'WARNING')
|
||||
EgtDraw()
|
||||
return false
|
||||
end
|
||||
if dRawL < GEO.EPS_SMALL then dRawL = dTotLen + dAddLen + 0.5 end
|
||||
dRawL = min( dRawL, BeamData.MAX_RAW)
|
||||
local dOvmHead = EgtEvalNumExpr( vsVal[2])
|
||||
if not dOvmHead then
|
||||
local sOut = 'Sovramateriale di testa errato : ' .. vsVal[2]
|
||||
EgtOutLog( sOut)
|
||||
EgtOutBox( sOut, 'Lavora Travi', 'WARNING')
|
||||
EgtDraw()
|
||||
return false
|
||||
end
|
||||
local dOvmMid = EgtEvalNumExpr( vsVal[3])
|
||||
if not dOvmMid then
|
||||
local sOut = 'Offset intermedio : ' .. vsVal[3]
|
||||
EgtOutLog( sOut)
|
||||
EgtOutBox( sOut, 'Lavora Travi', 'WARNING')
|
||||
EgtDraw()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Sistemo sezione barra con travi
|
||||
local bVert = ( vsVal[4] == 'true')
|
||||
if bVert then
|
||||
if dRawW > dRawH then dRawW, dRawH = dRawH, dRawW end
|
||||
end
|
||||
EgtOutLog( 'Lraw : ' .. EgtNumToString( dRawL, 1) .. ' Lovm : '.. EgtNumToString( dOvmHead, 1), 1)
|
||||
|
||||
-- Verifico sezione barra non troppo grande
|
||||
if not BeamData.MAX_WIDTH2 or not BeamData.MAX_HEIGHT2 then
|
||||
if ( dRawW > BeamData.MAX_WIDTH + 10 * GEO.EPS_SMALL or dRawH > BeamData.MAX_HEIGHT + 10 * GEO.EPS_SMALL) then
|
||||
local sOut = 'Sezione (' .. EgtNumToString( dRawW, 2) .. ' x ' .. EgtNumToString( dRawH, 2) .. ') ' ..
|
||||
'oltre i limiti della macchina (' .. EgtNumToString( BeamData.MAX_WIDTH, 2) .. ' x ' .. EgtNumToString( BeamData.MAX_HEIGHT, 2) .. ') '
|
||||
EgtOutLog( sOut)
|
||||
EgtOutBox( sOut, 'Lavora Travi', 'WARNING')
|
||||
EgtDraw()
|
||||
return false
|
||||
end
|
||||
else
|
||||
if ( dRawW > BeamData.MAX_WIDTH + 10 * GEO.EPS_SMALL or dRawH > BeamData.MAX_HEIGHT + 10 * GEO.EPS_SMALL) and
|
||||
( dRawW > BeamData.MAX_WIDTH2 + 10 * GEO.EPS_SMALL or dRawH > BeamData.MAX_HEIGHT2 + 10 * GEO.EPS_SMALL) then
|
||||
local sOut = 'Sezione (' .. EgtNumToString( dRawW, 2) .. ' x ' .. EgtNumToString( dRawH, 2) .. ') ' ..
|
||||
'oltre i limiti della macchina (' .. EgtNumToString( BeamData.MAX_WIDTH, 2) .. ' x ' .. EgtNumToString( BeamData.MAX_HEIGHT, 2) .. ') ' ..
|
||||
'e (' .. EgtNumToString( BeamData.MAX_WIDTH2, 2) .. ' x ' .. EgtNumToString( BeamData.MAX_HEIGHT2, 2) .. ')'
|
||||
EgtOutLog( sOut)
|
||||
EgtOutBox( sOut, 'Lavora Travi', 'WARNING')
|
||||
EgtDraw()
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Verifico sezione barra non troppo piccola
|
||||
if dRawW < BeamData.MIN_WIDTH - 10 * GEO.EPS_SMALL or dRawH < BeamData.MIN_HEIGHT - 10 * GEO.EPS_SMALL then
|
||||
local sOut = 'Sezione (' .. EgtNumToString( dRawW, 2) .. ' x ' .. EgtNumToString( dRawH, 2) .. ') ' ..
|
||||
'sotto i limiti della macchina (' .. EgtNumToString( BeamData.MIN_WIDTH, 2) .. ' x ' .. EgtNumToString( BeamData.MIN_HEIGHT, 2) .. ')'
|
||||
EgtOutLog( sOut)
|
||||
EgtOutBox( sOut, 'Lavora Travi', 'WARNING')
|
||||
EgtDraw()
|
||||
return false
|
||||
end
|
||||
|
||||
-- Se richiesto, ordino le travi in senso di lunghezza crescente
|
||||
local bOrd = ( vsVal[5] == 'true')
|
||||
if bOrd then
|
||||
table.sort( PARTS, function( B1, B2)
|
||||
if abs( B1.b3PartOriginal:getDimX() - B2.b3PartOriginal:getDimX()) < 1 then
|
||||
return B1.nInd < B2.nInd
|
||||
else
|
||||
return B1.b3PartOriginal:getDimX() < B2.b3PartOriginal:getDimX()
|
||||
end
|
||||
end)
|
||||
end
|
||||
do
|
||||
local sOut = ''
|
||||
for i = 1, #PARTS do
|
||||
sOut = sOut .. PARTS[i].sName .. ', '
|
||||
end
|
||||
sOut = sOut:sub( 1, -3)
|
||||
EgtOutLog( 'Travi ordinate : ' .. sOut, 1)
|
||||
end
|
||||
|
||||
-- Sistemo le travi nel grezzo
|
||||
local bOk, sErr = BeamExec.ProcessBeams( dRawW, dRawH, dRawL, dOvmHead, dOvmMid, PARTS, nil, false)
|
||||
if not bOk then
|
||||
EgtOutLog( sErr)
|
||||
EgtOutBox( sErr, 'Lavora Travi', 'ERROR')
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Inserimento delle lavorazioni nelle travi ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MyProcessFeatures()
|
||||
|
||||
BeamExec.GetProcessings( PARTS, false)
|
||||
BeamExec.GetCombinationMatrix( PARTS, false)
|
||||
BeamExec.ProcessMachinings( PARTS, false)
|
||||
local nErrCnt = 0
|
||||
local nWarnCnt = 0
|
||||
local sOutput = ''
|
||||
for i = 1, #RESULT do
|
||||
local sMsg = ''
|
||||
if RESULT[i].sType == 'Feature' then
|
||||
sMsg = RESULT[i].ChosenStrategy.sInfo
|
||||
elseif RESULT[i].sType == 'Part' then
|
||||
sMsg = RESULT[i].sMsg
|
||||
end
|
||||
sMsg = string.gsub( sMsg or '', '\n', ' ', 10)
|
||||
sMsg = string.gsub( sMsg or '', '\r', ' ', 10)
|
||||
-- trovata almeno una strategia e feature lavorata completamente
|
||||
if RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Completed' then
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg or '')
|
||||
|
||||
-- trovata almeno una strategia ma nessuna applicabile oppure non trovata alcuna strategia
|
||||
elseif RESULT[i].sType == 'Feature'
|
||||
and ( ( RESULT[i].ChosenStrategy.sStatus == 'Not-Applicable')
|
||||
or ( not RESULT[i].ChosenStrategy.sStrategyName)) then
|
||||
|
||||
nErrCnt = nErrCnt + 1
|
||||
if #sMsg == 0 then
|
||||
sMsg = 'No applicable strategy found'
|
||||
end
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
else
|
||||
-- segnalazione scarico pezzo standard, incompleto o a caduta
|
||||
if RESULT[i].sType == 'Part' and ( RESULT[i].nErr == -100 or RESULT[i].nErr == -101 or RESULT[i].nErr == -102) then
|
||||
-- nulla da segnalare
|
||||
|
||||
-- feature incompleta e altro
|
||||
elseif RESULT[i].sType == 'Feature' and RESULT[i].ChosenStrategy.sStatus == 'Not-Completed' then
|
||||
nWarnCnt = nWarnCnt + 1
|
||||
sMsg = 'Incomplete : Completion index ' .. RESULT[i].ChosenStrategy.dCompletionIndex .. '/5\n' .. sMsg
|
||||
sOutput = sOutput .. string.format( '[%d,%d] %s\n', RESULT[i].idCut, RESULT[i].idTask, sMsg)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- cancello gruppo temporaneo
|
||||
local idTempGroup = BeamLib.GetTempGroup()
|
||||
EgtErase( idTempGroup)
|
||||
|
||||
if #sOutput > 0 then EgtOutLog( sOutput) end
|
||||
if nErrCnt > 0 then
|
||||
EgtOutBox( sOutput, 'Lavora Travi', 'ERRORS')
|
||||
return false
|
||||
elseif nWarnCnt > 0 then
|
||||
EgtOutBox( sOutput, 'Lavora Travi', 'WARNINGS')
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- *** Esecuzione ***
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- calcolo tempo esecuzione
|
||||
TIMER:start()
|
||||
EgtOutLog( ' Execution timer started')
|
||||
|
||||
-- script principale
|
||||
|
||||
if not MyProcessInputData() then return end
|
||||
|
||||
-- recupero parametri generali da progetto
|
||||
BeamExec.GetGeneralParameters()
|
||||
|
||||
-- creo un gruppo temporaneo dove finiranno tutte le entità che non bisogna salvare, alla fine lo si cancella
|
||||
BeamLib.CreateTempGroup()
|
||||
|
||||
if not MyProcessBeams() then return end
|
||||
|
||||
if not GetDataConfig() then return end
|
||||
|
||||
-- Abilito Vmill
|
||||
EgtSetInfo( EgtGetCurrMachGroup(), 'Vm', '1')
|
||||
|
||||
MyProcessFeatures()
|
||||
|
||||
-- log tempi di esecuzione
|
||||
if EgtGetDebugLevel() >= 3 then
|
||||
TIMER:logAllElapsed()
|
||||
end
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
# DataBeamNEW
|
||||
|
||||
|
||||
|
||||
## Getting started
|
||||
|
||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
||||
|
||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
||||
|
||||
## Add your files
|
||||
|
||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
||||
|
||||
```
|
||||
cd existing_repo
|
||||
git remote add origin https://gitlab.steamware.net/egalware-cadcam/lua/databeamnew.git
|
||||
git branch -M main
|
||||
git push -uf origin main
|
||||
```
|
||||
|
||||
## Integrate with your tools
|
||||
|
||||
- [ ] [Set up project integrations](https://gitlab.steamware.net/egalware-cadcam/lua/databeamnew/-/settings/integrations)
|
||||
|
||||
## Collaborate with your team
|
||||
|
||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
||||
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
||||
|
||||
## Test and Deploy
|
||||
|
||||
Use the built-in continuous integration in GitLab.
|
||||
|
||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
||||
|
||||
***
|
||||
|
||||
# Editing this README
|
||||
|
||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
||||
|
||||
## Suggestions for a good README
|
||||
|
||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
||||
|
||||
## Name
|
||||
Choose a self-explaining name for your project.
|
||||
|
||||
## Description
|
||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
||||
|
||||
## Badges
|
||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
||||
|
||||
## Visuals
|
||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
||||
|
||||
## Installation
|
||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
||||
|
||||
## Usage
|
||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
||||
|
||||
## Support
|
||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
||||
|
||||
## Roadmap
|
||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
||||
|
||||
## Contributing
|
||||
State if you are open to contributions and what your requirements are for accepting them.
|
||||
|
||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
||||
|
||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
||||
|
||||
## Authors and acknowledgment
|
||||
Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
|
||||
## Project status
|
||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
||||
@@ -0,0 +1,32 @@
|
||||
-- Rotate.lua by Egaltech s.r.l. 2017/11/04
|
||||
-- Gestione rotazione di una Trave
|
||||
|
||||
-- Intestazioni
|
||||
require( 'EgtBase')
|
||||
_ENV = EgtProtectGlobal()
|
||||
EgtEnableDebug( false)
|
||||
|
||||
|
||||
-- recupero il pezzo del primo oggetto selezionato
|
||||
local nId = EgtGetFirstSelectedObj()
|
||||
local nPartId = EgtGetParent( EgtGetParent( nId or GDB_ID.NULL) or GDB_ID.NULL)
|
||||
if not nPartId or not EgtIsPart( nPartId) then
|
||||
EgtOutBox( 'Nessuna trave selezionata', 'Rotate Trave', 'ERROR')
|
||||
return
|
||||
end
|
||||
|
||||
-- recupero il box del pezzo
|
||||
local Ls = EgtGetFirstNameInGroup( nPartId, 'Box')
|
||||
local b3Solid = EgtGetBBoxGlob( Ls or GDB_ID.NULL, GDB_BB.STANDARD)
|
||||
if not b3Solid then
|
||||
local sName = EgtGetName( nPartId) or ( 'Id=' .. tonumber( nPartId))
|
||||
EgtOutBox( 'Box non definito per la trave ' .. sName, 'Rotate Trave', 'ERROR')
|
||||
return
|
||||
end
|
||||
|
||||
-- eseguo rotazione di 90 gradi attorno asse X
|
||||
local ptRot = b3Solid:getMin() + Vector3d( 0, b3Solid:getDimZ() / 2, b3Solid:getDimZ() / 2)
|
||||
EgtRotate( nPartId, ptRot, X_AX(), 90, GDB_RT.GLOB)
|
||||
EgtDraw()
|
||||
|
||||
-- end
|
||||
@@ -0,0 +1,893 @@
|
||||
|
||||
[
|
||||
{
|
||||
"sName":"Cut",
|
||||
"nPrc": 10,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
},
|
||||
{ "sName": "Bevel-1-Through",
|
||||
"sImage": "ConfigStrategy\\Bevel-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
},
|
||||
{ "sName": "HeadCut",
|
||||
"sImage": "ConfigStrategy\\HeadCut.png",
|
||||
"StrategyList" : [ { "sStrategyId": "HEADCUT" } ]
|
||||
},
|
||||
{ "sName": "TailCut",
|
||||
"sImage": "ConfigStrategy\\TailCut.png",
|
||||
"StrategyList" : [ { "sStrategyId": "TAILCUT" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Longitudinal Cut",
|
||||
"nPrc": 10,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Bevel-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Double Cut",
|
||||
"nPrc": 11,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\DoubleCut.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Ridge or Valley Cut",
|
||||
"nPrc": 12,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\RidgeValleyCut.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Saw Cut",
|
||||
"nPrc": 13,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Bevel-1-Through",
|
||||
"sImage": "ConfigStrategy\\Bevel-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Slot",
|
||||
"nPrc": 16,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Front Slot",
|
||||
"nPrc": 17,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Birds Mouth",
|
||||
"nPrc": 20,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Hip or Valley Rafter Notch",
|
||||
"nPrc": 25,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "RafterNotch-5-Through",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Ridge Lap",
|
||||
"nPrc": 30,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "RidgeLap-3-Through",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0012"} ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
},
|
||||
{ "sName": "DoubleBevel-2-Through",
|
||||
"sImage": "ConfigStrategy\\DoubleBevel-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Lap Joint",
|
||||
"nPrc": 30,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Notch/Rabbet",
|
||||
"nPrc": 32,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Block Haus",
|
||||
"nPrc": 33,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "BlockHouse.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Notch",
|
||||
"nPrc": 34,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"French Ridge Lap",
|
||||
"nPrc": 35,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\FrenchRidgeLap.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Chamfer",
|
||||
"nPrc": 36,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Chamfer.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Block Haus Half Lap",
|
||||
"nPrc": 37,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\BlockHouseHalfLap.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Block Haus Front",
|
||||
"nPrc": 38,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\BlockHouseFront.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Pocket",
|
||||
"nPrc": 39,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Drilling",
|
||||
"nPrc": 40,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Drilling.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0011" }, { "sStrategyId": "STR0013" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Tenon",
|
||||
"nPrc": 50,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Tenon.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0006" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Mortise",
|
||||
"nPrc": 50,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
},
|
||||
{ "sName": "Pocket-Round",
|
||||
"sImage": "ConfigStrategy\\Pocket-Round.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0008" } ]
|
||||
},
|
||||
{ "sName": "Pocket-Round-Front",
|
||||
"sImage": "ConfigStrategy\\MortiseFront.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0008" } ]
|
||||
},
|
||||
{ "sName": "Pocket-Round-Through",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0008" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Front Mortise",
|
||||
"nPrc": 51,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Pocket-5-Blind",
|
||||
"sImage": "ConfigStrategy\\Pocket-5-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-4-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-4-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Through",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Tunnel-4-Through",
|
||||
"sImage": "ConfigStrategy\\Tunnel-4-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0003" }, { "sStrategyId": "STR0004" } ]
|
||||
},
|
||||
{ "sName": "Groove-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Groove-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-3-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-3-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" } ]
|
||||
},
|
||||
{ "sName": "Bevel-2-Blind",
|
||||
"sImage": "ConfigStrategy\\Bevel-2-Blind.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010" } ]
|
||||
},
|
||||
{ "sName": "Rabbet-2-Through",
|
||||
"sImage": "ConfigStrategy\\Rabbet-2-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" }, { "sStrategyId": "STR0010"} ]
|
||||
},
|
||||
{ "sName": "Cut-1-Through",
|
||||
"sImage": "ConfigStrategy\\Cut-1-Through.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0005" } ]
|
||||
},
|
||||
{ "sName": "Pocket-Round",
|
||||
"sImage": "ConfigStrategy\\Pocket-Round.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0008" } ]
|
||||
},
|
||||
{ "sName": "Pocket-Round-Front",
|
||||
"sImage": "ConfigStrategy\\MortiseFront.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0008" } ]
|
||||
},
|
||||
{ "sName": "Pocket-Round-Through",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0008" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"House",
|
||||
"nPrc": 52,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"House Mortise",
|
||||
"nPrc": 53,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Dovetail Tenon",
|
||||
"nPrc": 55,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\DovetailTenon.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0001" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Dovetail Mortise",
|
||||
"nPrc": 55,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\DovetailMortise.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0007" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Dovetail Mortise Front",
|
||||
"nPrc": 56,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\DovetailMortiseFront.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0007" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Marking",
|
||||
"nPrc": 60,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Text.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0014" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Text",
|
||||
"nPrc": 61,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Text.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0014" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Scarf Simple",
|
||||
"nPrc": 70,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ScarfSimple.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Scarf Joint",
|
||||
"nPrc": 71,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ScarfJoint.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0009" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Step Joint",
|
||||
"nPrc": 80,
|
||||
"nGrp": 1,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\StepJoint.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0010"} ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Step Joint Notch",
|
||||
"nPrc": 80,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\StepJointNotch.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0002" }, { "sStrategyId": "STR0010"} ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Planing",
|
||||
"nPrc": 90,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Planing.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Front Profile",
|
||||
"nPrc": 100,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ProfileFront.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Head Concave Profile",
|
||||
"nPrc": 101,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ProfileHeadConcave.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Head Convex Profile",
|
||||
"nPrc": 102,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ProfileHeadConvex.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Head Cambered Profile",
|
||||
"nPrc": 103,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ProfileHeadCambered.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Round Arch",
|
||||
"nPrc": 104,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\RoundArch.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Head Profile",
|
||||
"nPrc": 106,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ProfileHead.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Sphere",
|
||||
"nPrc": 107,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Triangle Cut",
|
||||
"nPrc": 120,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\TriangleCut.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"TyroleanDovetail",
|
||||
"nPrc": 136,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\TyroleanDovetail.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Dovetail",
|
||||
"nPrc": 138,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\Dovetail.png",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Free Contour",
|
||||
"nPrc": 250,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "ConfigStrategy\\ProfileHead.png",
|
||||
"StrategyList" : [ { "sStrategyId": "STR0015" } ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Outline",
|
||||
"nPrc": 251,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Aperture",
|
||||
"nPrc": 252,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Variant",
|
||||
"nPrc": 900,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName":"Decor",
|
||||
"nPrc": 959,
|
||||
"nGrp": 0,
|
||||
"TopologyList" : [
|
||||
{ "sName": "Feature",
|
||||
"sImage": "",
|
||||
"StrategyList" : [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
[
|
||||
{
|
||||
"nGroup": "PIECE LOADING",
|
||||
"sName": "GEN_sPiecesLoadingPosition",
|
||||
"sNameNge": "GEN_PIECES_LOADING",
|
||||
"sValue": "BTL_POSITION",
|
||||
"sDescriptionShort": "Part loading position",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "BTL_POSITION",
|
||||
"sDescriptionShort": "Loading position from BTL, no pre-rotation",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "STD_PRE_ROTATION",
|
||||
"sDescriptionShort": "Get Best loading position from 0° and 180°",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "FULL_PRE_ROTATION",
|
||||
"sDescriptionShort": "Get Best loading position in each piece rotation",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nGroup": "PIECE LOADING",
|
||||
"sName": "GEN_bAllowPieceInversion",
|
||||
"sNameNge": "ADMIT_INVERSION",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Allow piece inversion",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"nGroup": "PIECE LOADING",
|
||||
"sName": "GEN_bGetAlternativesNesting2D",
|
||||
"sNameNge": "GET_ALTERNATIVES_NEST2D",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Enable material optimization function in nesting",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINE",
|
||||
"sName": "GEN_sPieceRotation",
|
||||
"sNameNge": "GEN_PIECE_ROTATION",
|
||||
"sValue": "IF_NECESSARY",
|
||||
"sDescriptionShort": "Part rotating acceptability",
|
||||
"sDescriptionLong": "Acceptability of rotating the part between machining steps",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "NOT_ALLOWED",
|
||||
"sDescriptionShort": "Rotation not allowed",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "IF_NECESSARY",
|
||||
"sDescriptionShort": "Rotation allowed only if strictly necessary",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "NO_CONSTRAINT",
|
||||
"sDescriptionShort": "Rotation easily acceptable / no constraint",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINE",
|
||||
"sName": "GEN_sMachiningStrategy",
|
||||
"sNameNge": "GEN_MACHINING_STRATEGY",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Machining Strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Quality and time equally prioritized",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "FASTEST",
|
||||
"sDescriptionShort": "Fastest",
|
||||
"sDescriptionLong": "Prefer fastest strategies",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "HIGH_QUALITY",
|
||||
"sDescriptionShort": "High quality",
|
||||
"sDescriptionLong": "Prefer high-quality strategies",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_nMaxReProcessCycles",
|
||||
"sNameNge": "MAX_REPROCESS_CYCLES",
|
||||
"sValue": "1",
|
||||
"sDescriptionShort": "Max number of reprocessing cycles",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "10"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_bReduceBladePath",
|
||||
"sNameNge": "REDUCE_BLADE_PATH",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Use entire blade diameter to shorten path",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_dMaxWasteLength",
|
||||
"sNameNge": "GEN_MAX_WASTE_LENGTH",
|
||||
"sValue": "300",
|
||||
"sDescriptionShort": "Maximum length for dropped waste",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_dMaxWasteVolume",
|
||||
"sNameNge": "GEN_MAX_WASTE_VOLUME",
|
||||
"sValue": "6000000",
|
||||
"sDescriptionShort": "Maximum volume for dropped waste",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"nGroup": "MACHINING STRATEGY",
|
||||
"sName": "GEN_dMaxDimDice",
|
||||
"sNameNge": "GEN_MAX_DIM_DICE",
|
||||
"sValue": "150",
|
||||
"sDescriptionShort": "Maximum dice dimension",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"sStrategyId": "HEADCUT",
|
||||
"sStrategyName": "HEADCUT",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dDepthChamfer",
|
||||
"sNameNge": "DEPTH_CHAMFER",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Depth Chamfer",
|
||||
"sDescriptionLong": "Depth of the V-Mill to execute chamfers on cut-edges",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bForceChainSaw",
|
||||
"sNameNge": "FORCE_CHAIN",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Force to use chain saw",
|
||||
"sDescriptionLong": "Force to use chain saw",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bExecutePreCut",
|
||||
"sNameNge": "EXEC_PRECUT",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Force to add PreCuts",
|
||||
"sDescriptionLong": "Autocam will apply a machining on the theoretical zero, to avoid collision if the theoretical piece length doesn't correspond to the real length",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bFinishWithMill",
|
||||
"sNameNge": "MILL_FINISH",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Finish with mill",
|
||||
"sDescriptionLong": "Use a mill to finish the surface if split with chain saw",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
-- Strategia: HEADCUT
|
||||
-- Descrizione
|
||||
-- HeadCut
|
||||
-- Feature: HeadCut
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local SPLITCUT = require( 'SPLITCUT')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local HEADCUT = {}
|
||||
local Strategy = {}
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MakeChamfer()
|
||||
-- TODO funzionalità da aggiungere
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function HEADCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.SplitStrategy = {}
|
||||
Strategy.Result = {}
|
||||
Strategy.Machining = {}
|
||||
Strategy.Result.sInfo = ''
|
||||
local OptionalParameters = { bForceChainSaw = Strategy.Parameters.bForceChainSaw, bReduceBladePath = Strategy.Parameters.bReduceBladePath,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength, dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume }
|
||||
OptionalParameters.sRestLengthSideForPreSimulation = 'Head'
|
||||
OptionalParameters.bCannotSplitRestLength = true
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
-- si setta che è taglio di testa
|
||||
Strategy.bIsHeadCut = true
|
||||
-- quando si aggiunge la lavorazione, si cambia il nome della feature
|
||||
if bAddMachining then
|
||||
-- si forza il nome della feature
|
||||
EgtSetName( Proc.id, 'StartCut')
|
||||
end
|
||||
|
||||
-- se abilitato, faccio tagli di PRECUT a zero (come SPLIT)
|
||||
if Strategy.Parameters.bExecutePreCut then
|
||||
Strategy.SplitStrategy, Strategy.Result = SPLITCUT.GetMachining( Proc, Part, OptionalParameters)
|
||||
-- se non faccio tagli PRECUT, imposto tabella Result direttamente. Non serve verificare che riesca a rimuovere il materiale extra
|
||||
-- if not Strategy.SplitStrategy or #Strategy.SplitStrategy == 0 then
|
||||
-- Strategy.Result.sInfo = 'PreCut on head not possible'
|
||||
-- end
|
||||
if Strategy.Result.sStatus ~= 'Completed' then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Precut Head not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dMRR = 1
|
||||
-- TODO di quale utensile si deve impostare la qualità qui?
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'SAWBLADE')
|
||||
|
||||
-- se coincide con inizio grezzo, non va fatto
|
||||
if abs( Proc.b3Box:getCenter():getX() - Part.b3Raw:getMax():getX()) < 10 * GEO.EPS_SMALL then
|
||||
return true, Strategy.Result
|
||||
end
|
||||
|
||||
-- se devo applicare le lavorazioni
|
||||
if bAddMachining then
|
||||
-- inserimento smussi su spigoli del taglio
|
||||
if Strategy.Parameters.bMakeChamfer then
|
||||
MakeChamfer()
|
||||
end
|
||||
|
||||
local MachiningsToAdd = {}
|
||||
local bExecutePrecutOnly = false
|
||||
-- se abilitato, faccio tagli di PRECUT a zero (come SPLIT)
|
||||
if Strategy.Parameters.bExecutePreCut then
|
||||
bExecutePrecutOnly = Part.dHeadOverMaterial < 20
|
||||
|
||||
if Strategy.SplitStrategy and #Strategy.SplitStrategy > 0 then
|
||||
for i = 1, #Strategy.SplitStrategy do
|
||||
local TempList = {}
|
||||
TempList = Strategy.SplitStrategy[i]
|
||||
if bExecutePrecutOnly then
|
||||
TempList.dLongitudinalOffset = 0
|
||||
else
|
||||
TempList.bIsPreCut = true
|
||||
TempList.dLongitudinalOffset = Part.dHeadOverMaterial
|
||||
end
|
||||
|
||||
table.insert( MachiningsToAdd, TempList)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not bExecutePrecutOnly then
|
||||
|
||||
-- si recuperano gli estremi del box del materiale di testa da togliere
|
||||
local b3PartWithHead = BeamLib.GetPartBoxWithHeadTail( Part, 'Head')
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMax():getX() - 1, Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( b3PartWithHead:getMax():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
|
||||
local OptionalParametersBladeToWaste = {}
|
||||
OptionalParametersBladeToWaste.b3BoxDicing = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
OptionalParametersBladeToWaste.dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume
|
||||
OptionalParametersBladeToWaste.dMaxWasteLength = Strategy.Parameters.dMaxWasteLength
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
OptionalParametersBladeToWaste.sRestLengthSideForPreSimulation = 'Head'
|
||||
OptionalParametersBladeToWaste.bCannotSplitRestLength = true
|
||||
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
-- se taglio non riuscito, si riprova con il riduci percorso forzato (collisione possibile in separazione pezzi alti)
|
||||
if ( not Strategy.Machining) or ( #Strategy.Machining == 0) then
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = true
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
end
|
||||
if Strategy.Machining and #Strategy.Machining > 0 then
|
||||
for i = 1, #Strategy.Machining do
|
||||
local TempList = {}
|
||||
TempList = Strategy.Machining[i]
|
||||
table.insert( MachiningsToAdd, TempList)
|
||||
end
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Head machining not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
-- aggiungo lavorazioni trovate alla lista generale
|
||||
for i = 1, #MachiningsToAdd do
|
||||
MachiningsToAdd[i].sStage = 'Head'
|
||||
MachiningLib.AddMachinings( Proc, MachiningsToAdd[i], MachiningsToAdd[i].AuxiliaryData)
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
else
|
||||
return nil, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return HEADCUT
|
||||
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"sStrategyId": "STR0001",
|
||||
"sStrategyName": "DoveTail Tenon",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dOverMatOnLength",
|
||||
"sNameNge": "OVM_LENGTH",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on tenon length",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOverMatOnRadius",
|
||||
"sNameNge": "OVM_RADIUS",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on tenon width",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "nMaxMillingPaths",
|
||||
"sNameNge": "MAX_PATHS",
|
||||
"sValue": "3",
|
||||
"sDescriptionShort": "Maximum number of milling passes",
|
||||
"sDescriptionLong": "Maximum number of milling passes. If more passes are required, pocketing is performed",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bUseDTToolOnPocketing",
|
||||
"sNameNge": "ALLOW_DT_POCKET",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Use DoveTail tool to pocket",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCuttingStrategy",
|
||||
"sNameNge": "EXEC_TENON_SURF",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Cutting Strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BLADE_FORCED",
|
||||
"sDescriptionShort": "Blade only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "MILL_FORCED",
|
||||
"sDescriptionShort": "Mill only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "CHAINSAW_FORCED",
|
||||
"sDescriptionShort": "ChainSaw only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sPocketingList",
|
||||
"sNameNge": "POCK_DTTENON_SURF_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the tenon cut surface",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "DOVETAIL_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the dovetail tenon",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
-- Strategia: STR0001
|
||||
-- Descrizione
|
||||
-- Lama + fresa CodaDiRondine per tenone
|
||||
-- Feature: 55,1
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0001 = {}
|
||||
local Strategy = {}
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetSCC( Machining)
|
||||
local nSCC
|
||||
|
||||
if Machining.vtToolDirection:getX() > 0 then
|
||||
nSCC = MCH_SCC.ADIR_XP
|
||||
else
|
||||
nSCC = MCH_SCC.ADIR_XM
|
||||
end
|
||||
|
||||
return nSCC
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetTenonStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
Machining.Milling = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
Machining.Cutting = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
Machining.Pocketing = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING)
|
||||
local Result = {}
|
||||
Result.Milling = {}
|
||||
Result.Cutting = {}
|
||||
Result.Pocketing = {}
|
||||
local ToolSearchParameters = {}
|
||||
|
||||
-- scelta automatica lavorazione. Non viene mai scelta la motosega
|
||||
if Strategy.Parameters.sCuttingStrategy == 'AUTO' then
|
||||
-- creo piano di taglio sulla testa del tenone
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idTenonCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
end
|
||||
-- se non possibile di lama si prova con fresa
|
||||
if not Machining.Cutting or Result.Cutting.sStatus ~= 'Completed' then
|
||||
Machining.bCuttingWithMill = true
|
||||
end
|
||||
-- lavorazione forzata con utensile lama
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'BLADE_FORCED' then
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idTenonCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
else
|
||||
Machining.Cutting.bIsApplicable = false
|
||||
end
|
||||
-- lavorazione forzata con utensile fresa
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'MILL_FORCED' then
|
||||
Machining.bCuttingWithMill = true
|
||||
-- lavorazione forzata con utensile motosega
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'CHAINSAW_FORCED' then
|
||||
-- DA FARE!!
|
||||
end
|
||||
|
||||
-- === ricerca utensile per svuotare taglio iniziale, se taglio non possibile ===
|
||||
if Machining.bCuttingWithMill and ( not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit) then
|
||||
ToolSearchParameters = {}
|
||||
|
||||
-- TODO SISTEMARE!!! qui la svuotatura non deve limitare l'elevazione se aperta da tutti i lati. In futuro si deve passare 0 come elevazione
|
||||
ToolSearchParameters.dElevation = EgtSurfTmFacetElevationInBBox( Strategy.idTenonCutPlane, 0, Part.b3Part, true, GDB_ID.ROOT)
|
||||
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Machining.Cutting.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
|
||||
-- TODO anche il test sul ResidualDepth va tolto
|
||||
if Machining.Cutting.ToolInfo.nToolIndex and ( Machining.Cutting.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL) then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Cutting.ToolInfo.nToolIndex
|
||||
Result.Cutting.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
Machining.Cutting.sStatus = 'Completed'
|
||||
Machining.Cutting.Steps = {}
|
||||
Machining.Cutting.LeadIn = {}
|
||||
Machining.Cutting.nType = MCH_MY.POCKETING
|
||||
Machining.Cutting.nSubType = MCH_POCK_SUB.SPIRALIN
|
||||
Machining.Cutting.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Machining.Cutting.Steps.dStep = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dStep
|
||||
Machining.Cutting.Steps.dSideStep = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.Cutting.nToolIndex = Machining.Cutting.ToolInfo.nToolIndex
|
||||
Machining.Cutting.LeadIn.dTangentDistance = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Machining.Cutting.LeadIn.dElevation = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Machining.Cutting.sDepth = 0
|
||||
Machining.Cutting.Geometry = {{ Strategy.idTenonCutPlane, 0}}
|
||||
Machining.Cutting.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
-- tempo di svuotatura
|
||||
Result.Cutting.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining.Cutting, Part)
|
||||
end
|
||||
end
|
||||
|
||||
-- === ricerca utensile per lavorare tenone coda di rondine ===
|
||||
Machining.Milling.bIsApplicable = false
|
||||
-- se tenone in testa oppure se di coda ma è possibile lavorare dopo separazione
|
||||
if not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit then
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dTenonLength
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
ToolSearchParameters.sMillShape = 'DOVETAIL'
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Machining.Milling.ToolInfo = {}
|
||||
Machining.Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Machining.Milling.ToolInfo.nToolIndex then
|
||||
Machining.Milling.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Result.Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
-- l'utensile a coda di rondine deve per forza riuscire a lavorare tutto, altrimenti errore
|
||||
if Machining.Milling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Result.Milling.sStatus = 'Completed'
|
||||
-- aggiungo geometria e imposto tutti i dati
|
||||
Machining.Milling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Machining.Milling.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Machining.Milling.nType = MCH_MY.MILLING
|
||||
Machining.Milling.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
Machining.Milling.sDepth = min( -Machining.Milling.ToolInfo.dResidualDepth, 0)
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Machining.Milling.LeadIn = {}
|
||||
Machining.Milling.LeadOut = {}
|
||||
Machining.Milling.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.Milling.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.Milling.LeadIn.dTangentDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadIn.dPerpDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.Milling.LeadOut.dTangentDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadOut.dPerpDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.Milling.dLengthToMachine = Proc.FeatureInfo.dTenonPathLength
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.Milling.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
Machining.Milling.bInvert = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Machining.Milling.nWorkside = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
|
||||
Machining.Milling.sUserNotes = EgtSetVal( 'MaxElev', EgtNumToString( Proc.FeatureInfo.dTenonLength, 1)) .. ';'
|
||||
|
||||
Machining.Milling.nSCC = GetSCC( Machining.Milling)
|
||||
|
||||
-- passate con sovramateriale
|
||||
Machining.nMillingPathsNeeded = ceil( Proc.FeatureInfo.dTenonMaxDist / TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep)
|
||||
Machining.Milling.AuxiliaryData = {}
|
||||
Machining.Milling.AuxiliaryData.Clones = {}
|
||||
for i = Machining.nMillingPathsNeeded, 1, -1 do
|
||||
-- il primo è il passaggio più esterno
|
||||
local nIndexClones = Machining.nMillingPathsNeeded - i + 1
|
||||
-- suddivido step in base al numero passate da fare
|
||||
local dRealSideStep = floor( Proc.FeatureInfo.dTenonMaxDist / Machining.nMillingPathsNeeded)
|
||||
-- cambia solo sovrmateriale radiale
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones] = {}
|
||||
-- ultima passata con sovramateriale impostato
|
||||
if i == 1 then
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = Strategy.Parameters.dOverMatOnRadius
|
||||
else
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * dRealSideStep
|
||||
end
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
-- TODO sostituire con applicazione della lavorazione?
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
local idGeomMaxOffset = EgtCopyGlob( Proc.FeatureInfo.idAddAuxGeom, Part.idTempGroup)
|
||||
EgtOffsetCurve( idGeomMaxOffset, Machining.Milling.AuxiliaryData.Clones[1].dRadialOffset + TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2, Part.idTempGroup)
|
||||
local vtCurveStart = EgtSV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local vtCurveEnd = EgtEV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local ptCurveStart = EgtSP( idGeomMaxOffset, GDB_ID.ROOT) + -vtCurveStart * Machining.Milling.LeadIn.dTangentDistance + ( Proc.FeatureInfo.vtTenonN ^ -vtCurveStart) * Machining.Milling.LeadIn.dPerpDistance
|
||||
local ptCurveEnd = EgtEP( idGeomMaxOffset, GDB_ID.ROOT) + vtCurveEnd * Machining.Milling.LeadOut.dTangentDistance + ( vtCurveEnd ^ Proc.FeatureInfo.vtTenonN) * Machining.Milling.LeadOut.dPerpDistance
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveStart, false, GDB_RT.GLOB)
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveEnd, true, GDB_RT.GLOB)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomMaxOffset, Proc.FeatureInfo.vtTenonN, Machining.Milling.nSCC, TOOLS[Machining.Milling.ToolInfo.nToolIndex])
|
||||
if bOutOfStroke then
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
|
||||
-- tempo di svuotatura
|
||||
Result.Milling.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining.Milling, Part)
|
||||
else
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- === ricerca utensile di svuotatura (se richiesto e se è andata a buon fine la coda di rondine) ===
|
||||
if Machining.Milling.bIsApplicable then
|
||||
if Machining.nMillingPathsNeeded <= Strategy.Parameters.nMaxMillingPaths then
|
||||
Machining.Pocketing.bNotNeeded = true
|
||||
Machining.Pocketing.dMRR = Machining.Milling.dMRR
|
||||
-- serve svuotatura
|
||||
else
|
||||
-- se ammessa svuotatura con utensile DoveTail, copio i dati
|
||||
if Strategy.Parameters.bUseDTToolOnPocketing then
|
||||
Machining.Pocketing.bIsApplicable = true
|
||||
Machining.Pocketing.ToolInfo = Machining.Milling.ToolInfo
|
||||
Machining.Pocketing.dMRR = Machining.Milling.dMRR
|
||||
-- altrimenti serve cercarne un altro
|
||||
else
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dTenonLength
|
||||
ToolSearchParameters.vtToolDirection = Proc.vtTenonN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Machining.Pocketing.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Machining.Pocketing.ToolInfo.nToolIndex then
|
||||
Machining.Pocketing.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Pocketing.ToolInfo.nToolIndex
|
||||
Result.Pocketing.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
if Machining.Pocketing.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Result.Pocketing.sStatus = 'Completed'
|
||||
Result.Pocketing.dCompletionPercentage = 100
|
||||
else
|
||||
Result.Pocketing.sStatus = 'Not-Completed'
|
||||
Result.Pocketing.sInfo = 'Tenon not complete, left ' .. ceil( Machining.Pocketing.ToolInfo.dResidualDepth) .. 'mm'
|
||||
Result.Pocketing.dCompletionPercentage = ( 1 - Machining.Pocketing.ToolInfo.dResidualDepth / Proc.dDTLength) * 100
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Machining, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetFeatureRotationIndex( Proc)
|
||||
local nVoteIndex
|
||||
|
||||
-- se fatto con testa sopra
|
||||
if TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bTop then
|
||||
if Proc.FeatureInfo.vtTenonN:getZ() < 0 then
|
||||
nVoteIndex = 2
|
||||
elseif Proc.FeatureInfo.vtTenonN:getZ() > abs( Proc.FeatureInfo.vtTenonN:getY()) then
|
||||
nVoteIndex = 4
|
||||
else
|
||||
nVoteIndex = 3
|
||||
end
|
||||
-- se fatto con testa sotto
|
||||
elseif TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bBottom then
|
||||
if Proc.FeatureInfo.vtTenonN:getZ() > 0 then
|
||||
nVoteIndex = 2
|
||||
elseif Proc.FeatureInfo.vtTenonN:getZ() < - abs( Proc.FeatureInfo.vtTenonN:getY()) then
|
||||
nVoteIndex = 4
|
||||
else
|
||||
nVoteIndex = 3
|
||||
end
|
||||
end
|
||||
|
||||
return nVoteIndex
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO vedere se leggere direttamente la quality dell'utensile e mediarle nel caso di utensile doppio
|
||||
local function GetTenonMachiningResult( Proc, Result)
|
||||
local TotalResult = {}
|
||||
-- setto il risultato in base agli utensili trovati
|
||||
-- lavorazione completa
|
||||
if Strategy.Machining.Milling.bIsApplicable and Strategy.Machining.Cutting.bIsApplicable then
|
||||
TotalResult.sStatus = Result.Milling.sStatus
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
TotalResult.dMRR = ( Result.Milling.dMRR + Result.Cutting.dMRR) / 2
|
||||
if Strategy.Machining.nMillingPathsNeeded > Strategy.Parameters.nMaxMillingPaths then
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
||||
else
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
end
|
||||
TotalResult.nFeatureRotationIndex = GetFeatureRotationIndex( Proc)
|
||||
TotalResult.dTimeToMachine = Result.Milling.dTimeToMachine + Result.Cutting.dTimeToMachine
|
||||
TotalResult.sInfo = ''
|
||||
-- lavorazione incompleta
|
||||
elseif Strategy.Machining.Cutting.bIsApplicable then
|
||||
TotalResult.sStatus = 'Not-Completed'
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 50)
|
||||
TotalResult.dMRR = Result.Cutting.dMRR
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
TotalResult.sInfo = 'Tenon not completed'
|
||||
TotalResult.dTimeToMachine = Result.Cutting.dTimeToMachine
|
||||
-- strategia non applicabile, manca il taglio di lama sulla lunghezza del tenone
|
||||
else
|
||||
TotalResult = FeatureLib.GetStrategyResultNotApplicable( 'Error on Tenon cutting')
|
||||
end
|
||||
return TotalResult
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0001.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machining = {}
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.dTimeToMachine = 0
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
local Results = {}
|
||||
|
||||
-- controllo conformità offset tenone
|
||||
Strategy.Parameters.dOverMatOnRadius = EgtClamp( Strategy.Parameters.dOverMatOnRadius, -5, 5)
|
||||
Strategy.Parameters.dOverMatOnLength = EgtClamp( Strategy.Parameters.dOverMatOnRadius, -5, 5)
|
||||
|
||||
-- calcolo se la lavorazione del tenone può essere spostata dopo taglio di coda
|
||||
local dLengthOnX = Proc.b3Box:getDimX()
|
||||
Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
||||
|
||||
-- aggiunta superficie di taglio sulla lunghezza del tenone
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
local ptCenterAddSurf = Proc.FeatureInfo.ptTenonCenter + ( Proc.FeatureInfo.vtTenonN * Strategy.Parameters.dOverMatOnLength)
|
||||
Strategy.idTenonCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, ptCenterAddSurf, Proc.FeatureInfo.vtTenonN, Part.b3Part, GDB_RT.GLOB)
|
||||
|
||||
Strategy.Machining, Results = GetTenonStrategy( Proc, Part)
|
||||
|
||||
Strategy.Result = GetTenonMachiningResult( Proc, Results)
|
||||
|
||||
|
||||
-- applicazione delle lavorazioni
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- taglio in lunghezza sul tenone
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
-- se cutting da fare come svuotatura
|
||||
if Strategy.Machining.bCuttingWithMill then
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting)
|
||||
|
||||
-- taglio di lama
|
||||
else
|
||||
for i = 1, #Strategy.Machining.Cutting do
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machining.Cutting[i].sStage = 'AfterTail'
|
||||
end
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- passaggio sul profilo
|
||||
if Strategy.Machining.Milling.bIsApplicable then
|
||||
-- se molti passaggi richiesti, si fa svuotatura
|
||||
-- TODO in attesa delle svuotature, si fanno passaggi senza limiti sul numero massimo. Poi togliere il FALSE nella condizione.
|
||||
if false and Strategy.Machining.nMillingPathsNeeded > Strategy.Parameters.nMaxMillingPaths then
|
||||
-- TODO. SERVONO NUOVE SVUOTATURE!!!!
|
||||
else
|
||||
-- aggiunge lavorazione
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Milling, Strategy.Machining.Milling.AuxiliaryData)
|
||||
end
|
||||
|
||||
-- si controllano le ultime 5 facce della feature
|
||||
local nIndFace = -1
|
||||
for i = 1, 5 do
|
||||
if abs( Proc.FeatureInfo.vtTenonN * EgtSurfTmFacetNormVersor( Proc.id, Proc.nFct-i, GDB_ID.ROOT)) < GEO.EPS_ANG_SMALL then
|
||||
nIndFace = Proc.nFct-i
|
||||
end
|
||||
end
|
||||
-- controllo se serve passaggio di finitura in caso il tenone non cominci dal bordo della trave (P14 > 0)
|
||||
if nIndFace > 0 then
|
||||
-- verifico che entrambi i punti iniziale e finale della curva no giacciano in uno dei piani limite del pezzo, quindi se è un lato aperto
|
||||
local ptIni = EgtSP( Proc.FeatureInfo.idAddAuxGeom, GDB_RT.GLOB)
|
||||
local ptFin = EgtEP( Proc.FeatureInfo.idAddAuxGeom, GDB_RT.GLOB)
|
||||
-- se entrambi i punti non sono sul limite pezzo
|
||||
if not( BeamLib.IsPointOnBoxLimit( ptIni, Part.b3Part) or BeamLib.IsPointOnBoxLimit( ptFin, Part.b3Part)) then
|
||||
-- cerco utensile
|
||||
local ToolSearchParameters = {}
|
||||
local FinishMach = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dTenonLength
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'MillingFinish')
|
||||
FinishMach.ToolInfo = {}
|
||||
FinishMach.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if FinishMach.ToolInfo.nToolIndex then
|
||||
|
||||
-- aggiungo geometria e imposto tutti i dati
|
||||
FinishMach.Geometry = {{ Proc.id, Proc.nFct-1}}
|
||||
FinishMach.nToolIndex = FinishMach.ToolInfo.nToolIndex
|
||||
FinishMach.nType = MCH_MY.MILLING
|
||||
FinishMach.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
FinishMach.sDepth = 'TH'
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
FinishMach.LeadIn = {}
|
||||
FinishMach.LeadOut = {}
|
||||
FinishMach.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
FinishMach.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
FinishMach.LeadIn.dTangentDistance = TOOLS[FinishMach.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
FinishMach.LeadIn.dPerpDistance = TOOLS[FinishMach.ToolInfo.nToolIndex].dSideStep
|
||||
FinishMach.LeadOut.dTangentDistance = TOOLS[FinishMach.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
FinishMach.LeadOut.dPerpDistance = TOOLS[FinishMach.ToolInfo.nToolIndex].dSideStep
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
FinishMach.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
FinishMach.bInvert = EgtIf( TOOLS[FinishMach.ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
FinishMach.nWorkside = EgtIf( TOOLS[FinishMach.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
|
||||
FinishMach.sUserNotes = EgtSetVal( 'MaxElev', EgtNumToString( Proc.FeatureInfo.dTenonLength, 1)) .. ';'
|
||||
|
||||
FinishMach.nSCC = GetSCC( FinishMach)
|
||||
|
||||
-- imposto utilizzo faccia (--TODO verificare se serve riconoscere il lato specifico)
|
||||
local nFaceUse
|
||||
if Proc.FeatureInfo.vtTenonN:getX() > -GEO.EPS_SMALL then
|
||||
nFaceUse = MCH_MILL_FU.PARAL_LEFT
|
||||
else
|
||||
nFaceUse = MCH_MILL_FU.PARAL_RIGHT
|
||||
end
|
||||
FinishMach.nFaceuse = nFaceUse
|
||||
|
||||
-- aggiunge lavorazione
|
||||
bAreAllMachiningsAdded = bAreAllMachiningsAdded and MachiningLib.AddMachinings( Proc, FinishMach)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0001
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"sStrategyId": "STR0002",
|
||||
"sStrategyName": "Pocketing",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dMaxCornerRadius",
|
||||
"sNameNge": "MAX_CORNER_RADIUS",
|
||||
"sValue": "15",
|
||||
"sDescriptionShort": "Max radius left on corners",
|
||||
"sDescriptionLong": "Radius-limit left by the tool at each corner of the feature",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bAntiSplint",
|
||||
"sNameNge": "ANTISPLINT",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Use Anti-Splint strategy",
|
||||
"sDescriptionLong": "The strategy will apply blade cuts on corner to avoid wood splint",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dExtendAfterTail",
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOpenMinSafe",
|
||||
"sNameNge": "OPENMINSAFE",
|
||||
"sValue": "10",
|
||||
"sDescriptionShort": "Minimum approach distance on open sides",
|
||||
"sDescriptionLong": "Minimum approach distance on open sides",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sPocketingList",
|
||||
"sNameNge": "POCK_LAPJOINT",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to pocket the feature",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,724 @@
|
||||
-- Strategia: STR0002
|
||||
-- Descrizione
|
||||
-- Svuotatura tasca
|
||||
-- Feature tipo LapJoint
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO
|
||||
-- 1 - Inserire antischeggia (fresa o lama)
|
||||
-- 2 - Modalità svuotatura con fresa grande e spigoli con fresa piccola
|
||||
-- 3 - Smusso a V
|
||||
-- 4 - Finitura con motosega (se la fresa non completa)
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0002 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function IsTopologyOk( Proc)
|
||||
if Proc.Topology.sName == 'Pocket-5-Blind' or
|
||||
Proc.Topology.sName == 'RafterNotch-5-Through' or
|
||||
Proc.Topology.sName == 'Tunnel-4-Through' or
|
||||
Proc.Topology.sName == 'Groove-4-Blind' or
|
||||
Proc.Topology.sName == 'Groove-3-Through' or
|
||||
Proc.Topology.sName == 'Groove-3-Blind' or
|
||||
Proc.Topology.sName == 'Bevel-3-Blind' or
|
||||
Proc.Topology.sName == 'Rabbet-2-Through' or
|
||||
Proc.Topology.sName == 'Bevel-2-Blind' or
|
||||
Proc.Topology.sName == 'DoubleBevel-2-Through' or
|
||||
Proc.Topology.sName == 'VGroove-2-Through' or
|
||||
Proc.Topology.sName == 'Cut-1-Through' or
|
||||
Proc.Topology.sName == 'Bevel-1-Through' then
|
||||
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetSCC( Proc, Pocketing)
|
||||
local nSCC
|
||||
|
||||
if Pocketing.vtToolDirection:getY() > 0 then
|
||||
nSCC = MCH_SCC.ADIR_YP
|
||||
else
|
||||
nSCC = MCH_SCC.ADIR_YM
|
||||
end
|
||||
|
||||
return nSCC
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CalcMachinedPercentage( Proc, Machining)
|
||||
-- se non ci sono lavorazioni esco subito
|
||||
if Machining.sTypeMachining == 'None' then
|
||||
return 0
|
||||
end
|
||||
|
||||
local dTotalPercentage = 0
|
||||
local dPercentageBottom = 0
|
||||
|
||||
if Machining[1].bIsApplicable then
|
||||
dTotalPercentage = ( Machining[1].dElevation - Machining[1].ToolInfo.dResidualDepth) / Machining[1].dElevation
|
||||
dPercentageBottom = dTotalPercentage
|
||||
end
|
||||
if Machining[2].bIsApplicable then
|
||||
local dAbsPercentage = ( Machining[2].dElevation - Machining[2].ToolInfo.dResidualDepth) / Machining[2].dElevation
|
||||
dTotalPercentage = dTotalPercentage + ( 1 - dTotalPercentage) * dAbsPercentage
|
||||
end
|
||||
if Machining[3].bIsApplicable then
|
||||
local dAbsPercentage
|
||||
if Machining[3].bMachAppliedToTunnelFace then
|
||||
dAbsPercentage = ( Machining[3].dElevation - Machining[3].ToolInfo.dResidualDepth - Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation) / Machining[3].dElevation
|
||||
else
|
||||
dAbsPercentage = ( Machining[3].dElevation - Machining[3].ToolInfo.dResidualDepth) / Machining[3].dElevation
|
||||
end
|
||||
dTotalPercentage = dTotalPercentage + ( 1 - dPercentageBottom) * dAbsPercentage
|
||||
end
|
||||
if Machining[4].bIsApplicable then
|
||||
local dAbsPercentage
|
||||
if Machining[3].bMachAppliedToTunnelFace then
|
||||
dAbsPercentage = ( Machining[4].dElevation - Machining[4].ToolInfo.dResidualDepth - Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation) / Machining[4].dElevation
|
||||
else
|
||||
dAbsPercentage = ( Machining[4].dElevation - Machining[4].ToolInfo.dResidualDepth) / Machining[4].dElevation
|
||||
end
|
||||
dTotalPercentage = dTotalPercentage + ( 1 - dPercentageBottom) * dAbsPercentage
|
||||
end
|
||||
|
||||
return dTotalPercentage * 100
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO va gestita meglio la decisione delle facce da lavorare
|
||||
local function GetBestPocketingStrategy( Proc, Part)
|
||||
-- imposto parametri di ricerca utensile in base a topologia
|
||||
local Machining = {}
|
||||
local Milling = {}
|
||||
local ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
Machining.sTypeMachining = 'None' -- Bottom-Side1-Side2\ Bottom-Bottom2\ Bottom-Side1\ Bottom-Side2\ Side1-Side2\ Bottom\ Side1 \ Side2 \ None
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
||||
|
||||
-- caso speciale Tunnel che non ha faccia bottom
|
||||
if Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
local dFaceLength = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dLMinRectangle
|
||||
local dFaceWidth = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dWMinRectangle
|
||||
ToolSearchParameters.sType = 'MILL_STD'
|
||||
ToolSearchParameters.dMaxToolDiameter = min( Strategy.Parameters.dMaxCornerRadius * 2, dFaceLength, dFaceWidth)
|
||||
elseif Proc.Topology.sName == 'RafterNotch-5-Through' then
|
||||
ToolSearchParameters.sType = 'MILL_STD'
|
||||
ToolSearchParameters.dMaxToolDiameter = min( Strategy.Parameters.dMaxCornerRadius * 2, Proc.FeatureInfo.dFaceLength / 2)
|
||||
-- imposto dati per cercare la fresa migliore
|
||||
elseif Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
local dFaceWidth, dFaceLength
|
||||
if Proc.MainFaces.BottomFaces[1].MainEdges then
|
||||
dFaceWidth = Proc.MainFaces.BottomFaces[1].MainEdges.LongEdges[1].dLength
|
||||
dFaceLength = Proc.MainFaces.BottomFaces[1].MainEdges.SideEdges[1].dLength
|
||||
else
|
||||
dFaceWidth = Proc.MainFaces.BottomFaces[1].dWMinRectangle
|
||||
dFaceLength = Proc.MainFaces.BottomFaces[1].dLMinRectangle
|
||||
end
|
||||
ToolSearchParameters.sType = 'MILL_STD'
|
||||
ToolSearchParameters.dMaxToolDiameter = min( Strategy.Parameters.dMaxCornerRadius * 2, dFaceLength, dFaceWidth)
|
||||
-- cerco fresa che può anche non lavorare di testa
|
||||
elseif Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
local dFaceLength
|
||||
if Proc.MainFaces.BottomFaces[2].MainEdges then
|
||||
dFaceLength = Proc.MainFaces.BottomFaces[2].MainEdges.BottomEdge.dLength
|
||||
else
|
||||
dFaceLength = Proc.MainFaces.BottomFaces[2].dLMinRectangle
|
||||
end
|
||||
ToolSearchParameters.sType = 'MILL_NOTIP'
|
||||
ToolSearchParameters.dMaxToolDiameter = min( Strategy.Parameters.dMaxCornerRadius * 2, dFaceLength)
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' or Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
local dFaceLength
|
||||
if Proc.MainFaces.BottomFaces[1].MainEdges then
|
||||
dFaceLength = Proc.MainFaces.BottomFaces[1].MainEdges.SideEdges[1].dLength
|
||||
else
|
||||
dFaceLength = Proc.MainFaces.BottomFaces[1].dLMinRectangle
|
||||
end
|
||||
ToolSearchParameters.sType = 'MILL_NOTIP'
|
||||
ToolSearchParameters.dMaxToolDiameter = dFaceLength
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' then
|
||||
ToolSearchParameters.sType = 'MILL_NOTIP'
|
||||
ToolSearchParameters.dMaxToolDiameter = Strategy.Parameters.dMaxCornerRadius * 2
|
||||
elseif Proc.Topology.sName == 'Rabbet-2-Through'
|
||||
or Proc.Topology.sName == 'Bevel-2-Blind'
|
||||
or Proc.Topology.sName == 'DoubleBevel-2-Through'
|
||||
or Proc.Topology.sName == 'VGroove-2-Through'
|
||||
or Proc.Topology.sName == 'Cut-1-Through'
|
||||
or Proc.Topology.sName == 'Bevel-1-Through' then
|
||||
|
||||
ToolSearchParameters.sType = 'MILL_NOTIP'
|
||||
ToolSearchParameters.dMaxToolDiameter = 9999
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
-- ===== RICERCA UTENSILE =====
|
||||
-- cerco utensile per lavorare faccia Bottom
|
||||
Milling.bIsApplicable = false
|
||||
if Proc.Topology.sName ~= 'Tunnel-4-Through' then
|
||||
-- TODO in caso che la faccia crei un piano asportando tutto il materiale, si potrebbe forzare elevazione a zero e scegliere quindi fresa di diametro maggiore.
|
||||
-- Il discorso non vale se la feature viene spezzata o se non ancora separata, in quanto ci sarebbe comunque del materiale da considerare nell'elevazione.
|
||||
-- In quel caso, un 'Bevel-1-Through' è come se fosse un 'Bevel-2-Blind', quindi l'elevazione deve essere considerata.
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.BottomFaces[1].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.BottomFaces[1].vtN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.idFaceToMachine = Proc.MainFaces.BottomFaces[1].id
|
||||
Milling.bAddAntiSplint = Strategy.Parameters.bAntiSplint
|
||||
Milling.idProc = Proc.id
|
||||
Milling.vtFaceNormal = Proc.MainFaces.BottomFaces[1].vtN
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[1].dElevation
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
-- se faccia singola e feature lavorata in unica lavorazione si può sempre affondare
|
||||
if Proc.Topology.sName == 'Cut-1-Through'
|
||||
or Proc.Topology.sName == 'Bevel-1-Through' then
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
local bIsSplitFeature = false
|
||||
if #FeatureSplittingPoints > 0 then
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
if not bIsSplitFeature then
|
||||
Milling.ToolInfo.dResidualDepth = 0
|
||||
end
|
||||
end
|
||||
Milling.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
end
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
|
||||
-- caso speciale 'Rabbet-2-Through' seconda faccia principale
|
||||
Milling = {}
|
||||
Milling.bIsApplicable = false
|
||||
if Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' or
|
||||
Proc.Topology.sName == 'DoubleBevel-2-Through' or Proc.Topology.sName == 'VGroove-2-Through' then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.BottomFaces[2].vtN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.vtFaceNormal = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.BottomFaces[2].id
|
||||
Milling.bAddAntiSplint = Strategy.Parameters.bAntiSplint
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
Milling.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
end
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
|
||||
-- cerco utensile per lavorare di fianco 1
|
||||
Milling = {}
|
||||
Milling.bIsApplicable = false
|
||||
if Proc.Topology.sName ~= 'DoubleBevel-2-Through'
|
||||
and Proc.Topology.sName ~= 'Pocket-5-Blind' and Proc.Topology.sName ~= 'RafterNotch-5-Through' then
|
||||
|
||||
if Proc.Topology.sName == 'Groove-4-Blind' then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.BottomFaces[2].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
elseif Proc.Topology.sName == 'Groove-3-Blind' or Proc.Topology.sName == 'Bevel-3-Blind' then
|
||||
if Proc.MainFaces.LongFaces and Proc.MainFaces.LongFaces[1] then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.LongFaces[1].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.LongFaces[1].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.LongFaces[1].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.LongFaces[1].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.LongFaces[1].dElevation
|
||||
elseif Proc.MainFaces.BottomFaces[2] then
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.BottomFaces[2].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.BottomFaces[2].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.BottomFaces[2].dElevation
|
||||
end
|
||||
elseif Proc.MainFaces.TunnelAddedFaces then -- 'Tunnel-4-Through', 'Groove-3-Through', 'Rabbet-2-Through', 'VGroove-2-Through', 'Bevel-2-Blind'
|
||||
-- se lavoro di fianco, devo comunque rispettare il raggio massimo
|
||||
ToolSearchParameters.dMaxToolDiameter = min( ToolSearchParameters.dMaxToolDiameter, Strategy.Parameters.dMaxCornerRadius * 2)
|
||||
ToolSearchParameters.dElevation = ( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation * 2) + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].id
|
||||
Milling.idProc = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.id
|
||||
Milling.dElevation = ( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation * 2) + BeamData.MILL_OVERLAP
|
||||
Milling.bMachAppliedToTunnelFace = true
|
||||
else
|
||||
ToolSearchParameters.vtToolDirection = nil
|
||||
end
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
Milling.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
-- se la faccia tunnel è troppo piccola non si lavora
|
||||
if Milling.bMachAppliedToTunnelFace then
|
||||
local dLongestEdgeLength = 0
|
||||
for i = 1, #Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges do
|
||||
if Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength > dLongestEdgeLength + 10 * GEO.EPS_SMALL then
|
||||
dLongestEdgeLength = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength
|
||||
end
|
||||
end
|
||||
if dLongestEdgeLength < TOOLS[Milling.ToolInfo.nToolIndex].dDiameter then
|
||||
Milling.bIsApplicable = false
|
||||
ParametersMRR = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
|
||||
-- cerco utensile per lavorare di fianco 2
|
||||
Milling = {}
|
||||
Milling.bIsApplicable = false
|
||||
if Proc.Topology.sName ~= 'DoubleBevel-2-Through'
|
||||
and Proc.Topology.sName ~= 'Pocket-5-Blind'
|
||||
and Proc.Topology.sName ~= 'RafterNotch-5-Through'
|
||||
and Proc.Topology.sName ~= 'Groove-4-Blind'
|
||||
and Proc.Topology.sName ~= 'Bevel-3-Blind' then
|
||||
|
||||
if Proc.MainFaces.TunnelAddedFaces then -- Tunnel-4-Through, Groove-3-Through, Rabbet-2-Through, VGroove-2-Through, 'Bevel-2-Blind'
|
||||
-- se lavoro di fianco, devo comunque rispettare il raggio massimo
|
||||
ToolSearchParameters.dMaxToolDiameter = min( ToolSearchParameters.dMaxToolDiameter, Strategy.Parameters.dMaxCornerRadius * 2)
|
||||
ToolSearchParameters.dElevation = ( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation * 2) + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = -Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].vtN
|
||||
Milling.vtFaceNormal = -Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].id
|
||||
Milling.idProc = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.id
|
||||
Milling.dElevation = ( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation * 2) + BeamData.MILL_OVERLAP
|
||||
Milling.bToolInvert = true
|
||||
Milling.bMachAppliedToTunnelFace = true
|
||||
elseif #Proc.MainFaces.SideFaces > 0 then -- 'Groove-3-Blind'
|
||||
ToolSearchParameters.dElevation = Proc.MainFaces.SideFaces[1].dElevation
|
||||
ToolSearchParameters.vtToolDirection = Proc.MainFaces.SideFaces[1].vtN
|
||||
Milling.vtFaceNormal = Proc.MainFaces.SideFaces[1].vtN
|
||||
Milling.idFaceToMachine = Proc.MainFaces.SideFaces[1].id
|
||||
Milling.idProc = Proc.id
|
||||
Milling.dElevation = Proc.MainFaces.SideFaces[1].dElevation
|
||||
else
|
||||
ToolSearchParameters.vtToolDirection = nil
|
||||
end
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
Milling.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
-- se la faccia tunnel è troppo piccola non si lavora
|
||||
if Milling.bMachAppliedToTunnelFace then
|
||||
local dLongestEdgeLength = 0
|
||||
for i = 1, #Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges do
|
||||
if Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength > dLongestEdgeLength + 10 * GEO.EPS_SMALL then
|
||||
dLongestEdgeLength = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].Edges[i].dLength
|
||||
end
|
||||
end
|
||||
if dLongestEdgeLength < TOOLS[Milling.ToolInfo.nToolIndex].dDiameter then
|
||||
Milling.bIsApplicable = false
|
||||
ParametersMRR = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
|
||||
-- ===== SCELTA LAVORAZIONI =====
|
||||
-- TODO per DoubleBevel-2-Through si potrebbe lavorare la faccia tunnel su ogni faccia. Bisogna calcolarla!!
|
||||
-- caso speciale DoubleBevel-2-Through bisogna lavorare entrambe le bottom
|
||||
if Proc.Topology.sName == 'DoubleBevel-2-Through' then
|
||||
-- se entrambe applicabili significa che è completo
|
||||
if Machining[1].bIsApplicable and Machining[2].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Bottom-Bottom2'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
Strategy.Result.dMRR = Machining[1].dMRR + Machining[2].dMRR / 2
|
||||
Machining[1].ToolInfo.dResidualDepth = 0
|
||||
Machining[2].ToolInfo.dResidualDepth = 0
|
||||
return Machining
|
||||
else
|
||||
local dMachinedPrercentage = 0
|
||||
-- se applicabile solo Bottom
|
||||
if Machining[1].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Bottom'
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
Machining[1].ToolInfo.dResidualDepth = 0
|
||||
Strategy.Result.dMRR = Machining[1].dMRR
|
||||
dMachinedPrercentage = ( Machining[1].dElevation / ( Machining[1].dElevation + Machining[2].dElevation)) * 100
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
-- se applicabile solo Bottom2
|
||||
elseif Machining[2].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Bottom2'
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
Machining[2].ToolInfo.dResidualDepth = 0
|
||||
Strategy.Result.dMRR = Machining[2].dMRR
|
||||
dMachinedPrercentage = ( Machining[2].dElevation / ( Machining[1].dElevation + Machining[2].dElevation)) * 100
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
end
|
||||
Strategy.Result.sInfo = 'Machining not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
end
|
||||
return Machining
|
||||
-- se bottom completa tutto
|
||||
elseif Machining[1].bIsApplicable and Machining[1].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Machining.sTypeMachining = 'Bottom'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
Strategy.Result.dMRR = Machining[1].dMRR
|
||||
Machining[1].ToolInfo.dResidualDepth = 0
|
||||
Machining[3].bIsApplicable = false
|
||||
Machining[4].bIsApplicable = false
|
||||
-- caso speciale in cui si devono lavorare due facce
|
||||
if ( Proc.nFct == 2 and Proc.AdjacencyMatrix[1][2] >= -89.9)
|
||||
and Machining[2].bIsApplicable and Machining[2].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
|
||||
Machining.sTypeMachining = 'Bottom-Bottom2'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
Strategy.Result.dMRR = Machining[1].dMRR + Machining[2].dMRR / 2
|
||||
Machining[2].ToolInfo.dResidualDepth = 0
|
||||
else
|
||||
Machining[2].bIsApplicable = false
|
||||
end
|
||||
return Machining
|
||||
-- caso speciale 'Rabbet-2-Through' che ha la seconda faccia come se fosse una seconda bottom
|
||||
elseif ( Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' or Proc.Topology.sName == 'VGroove-2-Through' )
|
||||
and Machining[2].bIsApplicable and Machining[2].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Machining.sTypeMachining = 'Bottom2'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
Strategy.Result.dMRR = Machining[2].dMRR
|
||||
Machining[2].ToolInfo.dResidualDepth = 0
|
||||
Machining[1].bIsApplicable = false
|
||||
Machining[3].bIsApplicable = false
|
||||
Machining[4].bIsApplicable = false
|
||||
return Machining
|
||||
-- se la 3 completa tutto
|
||||
elseif Machining[3].bIsApplicable and Machining[3].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Machining.sTypeMachining = 'Side1'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
-- si cambia qualità perchè è rimasto il raggio sullo spigolo. E' giusto considerare non completo?
|
||||
if Proc.Topology.sName == 'Groove-3-Through' or Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' or Proc.Topology.sName == 'VGroove-2-Through' then
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'SEMI')
|
||||
end
|
||||
Strategy.Result.dMRR = Machining[3].dMRR
|
||||
if Proc.MainFaces.TunnelAddedFaces then
|
||||
Machining[3].ToolInfo.dResidualDepth = -( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation + BeamData.MILL_OVERLAP)
|
||||
else
|
||||
Machining[3].ToolInfo.dResidualDepth = 0
|
||||
end
|
||||
Machining[1].bIsApplicable = false
|
||||
Machining[2].bIsApplicable = false
|
||||
Machining[4].bIsApplicable = false
|
||||
return Machining
|
||||
-- se la 4 completa tutto
|
||||
elseif Machining[4].bIsApplicable and Machining[4].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Machining.sTypeMachining = 'Side2'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
-- si cambia qualità perchè è rimasto il raggio sullo spigolo. E' giusto considerare non completo?
|
||||
if Proc.Topology.sName == 'Groove-3-Through' or Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' or Proc.Topology.sName == 'VGroove-2-Through' then
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'SEMI')
|
||||
end
|
||||
Strategy.Result.dMRR = Machining[4].dMRR
|
||||
if Proc.MainFaces.TunnelAddedFaces then
|
||||
Machining[4].ToolInfo.dResidualDepth = -( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation + BeamData.MILL_OVERLAP)
|
||||
else
|
||||
Machining[4].ToolInfo.dResidualDepth = 0
|
||||
end
|
||||
Machining[1].bIsApplicable = false
|
||||
Machining[2].bIsApplicable = false
|
||||
Machining[3].bIsApplicable = false
|
||||
return Machining
|
||||
-- se tunnel 3+4 completa tutto
|
||||
elseif Proc.MainFaces.TunnelAddedFaces and Machining[3].bIsApplicable and Machining[4].bIsApplicable and
|
||||
Machining[3].ToolInfo.dResidualDepth + Machining[4].ToolInfo.dResidualDepth < (Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation * 2) + BeamData.MILL_OVERLAP then
|
||||
Machining.sTypeMachining = 'Side1-Side2'
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
-- si suddivide l'extra lavorabile sulle due frese
|
||||
local dExtraMachDepth = ( Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation * 2 - Machining[3].ToolInfo.dResidualDepth - Machining[4].ToolInfo.dResidualDepth - BeamData.MILL_OVERLAP) / 2
|
||||
Machining[3].ToolInfo.dResidualDepth = Machining[3].ToolInfo.dResidualDepth - Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation + dExtraMachDepth
|
||||
Machining[4].ToolInfo.dResidualDepth = Machining[4].ToolInfo.dResidualDepth - Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation + dExtraMachDepth
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
-- si cambia qualità perchè è rimasto il raggio sullo spigolo. E' giusto considerare non completo?
|
||||
if Proc.Topology.sName == 'Groove-3-Through' or Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind' or Proc.Topology.sName == 'VGroove-2-Through' then
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'SEMI')
|
||||
end
|
||||
Strategy.Result.dMRR = ( Machining[3].dMRR + Machining[4].dMRR) / 2
|
||||
Machining[1].bIsApplicable = false
|
||||
Machining[2].bIsApplicable = false
|
||||
return Machining
|
||||
end
|
||||
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
Strategy.Result.dMRR = 0
|
||||
if Machining[1].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Bottom'
|
||||
Strategy.Result.dMRR = Machining[1].dMRR
|
||||
end
|
||||
if Machining[2].bIsApplicable then
|
||||
Machining.sTypeMachining = EgtIf( Machining.sTypeMachining == 'None', 'Bottom2', Machining.sTypeMachining .. '-Bottom2')
|
||||
Strategy.Result.dMRR = ( Strategy.Result.dMRR + Machining[2].dMRR) / EgtIf( Strategy.Result.dMRR == 0, 1, 2)
|
||||
end
|
||||
if Machining[3].bIsApplicable then
|
||||
if Proc.MainFaces.TunnelAddedFaces then
|
||||
Machining[3].ToolInfo.dResidualDepth = Machining[3].ToolInfo.dResidualDepth - Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation + BeamData.MILL_OVERLAP
|
||||
end
|
||||
Machining.sTypeMachining = EgtIf( Machining.sTypeMachining == 'None', 'Side1', Machining.sTypeMachining .. '-Side1')
|
||||
Strategy.Result.dMRR = ( Strategy.Result.dMRR + Machining[3].dMRR) / EgtIf( Strategy.Result.dMRR == 0, 1, 2)
|
||||
end
|
||||
if Machining[4].bIsApplicable then
|
||||
if Proc.MainFaces.TunnelAddedFaces then
|
||||
Machining[4].ToolInfo.dResidualDepth = Machining[4].ToolInfo.dResidualDepth - Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.Faces[1].dElevation + BeamData.MILL_OVERLAP
|
||||
end
|
||||
Machining.sTypeMachining = EgtIf( Machining.sTypeMachining == 'None', 'Side2', Machining.sTypeMachining .. '-Side2')
|
||||
Strategy.Result.dMRR = ( Strategy.Result.dMRR + Machining[4].dMRR) / EgtIf( Strategy.Result.dMRR == 0, 1, 2)
|
||||
end
|
||||
|
||||
local dMachinedPrercentage = CalcMachinedPercentage( Proc, Machining)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Machining not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
|
||||
-- se non ho trovato neanche una lavorazione
|
||||
if Machining.sTypeMachining == 'None' then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Mill not found')
|
||||
end
|
||||
|
||||
return Machining
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetSplitSurfaces( Proc, Part, bAddMachining)
|
||||
local vAddId = {}
|
||||
local vAddIdTunnel = {}
|
||||
local idAddGroup
|
||||
if bAddMachining then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
local nOriginalTmIdTunnel = GDB_ID.NULL
|
||||
if Proc.MainFaces.TunnelAddedFaces then
|
||||
nOriginalTmIdTunnel = Proc.MainFaces.TunnelAddedFaces.MiddleFaceTm.id
|
||||
end
|
||||
|
||||
-- recupero punti di spezzatura - da destra a sinistra
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
|
||||
if #FeatureSplittingPoints == 0 then
|
||||
local nAddId = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, idAddGroup) or GDB_ID.NULL
|
||||
table.insert( vAddId, nAddId)
|
||||
table.insert( vAddIdTunnel, nAddIdTunnel)
|
||||
else
|
||||
for i = 1, #FeatureSplittingPoints do
|
||||
local nAddId = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, idAddGroup) or GDB_ID.NULL
|
||||
if i == 1 then
|
||||
-- prima superficie, va tagliata solo a sinistra
|
||||
local ptSplit = FeatureSplittingPoints[i] + Vector3d( -BeamData.MILL_OVERLAP / 2, 0, 0)
|
||||
EgtCutSurfTmPlane( nAddId, ptSplit, -X_AX(), true, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( nAddIdTunnel, ptSplit, -X_AX(), true, GDB_RT.GLOB)
|
||||
else
|
||||
-- taglio della superficie corrente - lato sinistro
|
||||
local ptSplit = FeatureSplittingPoints[i] + Vector3d( -BeamData.MILL_OVERLAP / 2, 0, 0)
|
||||
EgtCutSurfTmPlane( nAddId, ptSplit, -X_AX(), true, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( nAddIdTunnel, ptSplit, -X_AX(), true, GDB_RT.GLOB)
|
||||
-- taglio della superficie corrente - lato destro
|
||||
ptSplit = FeatureSplittingPoints[i - 1] + Vector3d( BeamData.MILL_OVERLAP / 2, 0, 0)
|
||||
EgtCutSurfTmPlane( nAddId, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( nAddIdTunnel, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
end
|
||||
table.insert( vAddId, nAddId)
|
||||
table.insert( vAddIdTunnel, nAddIdTunnel)
|
||||
end
|
||||
-- taglio ultima superficie, va tagliata solo a destra
|
||||
local nAddId = EgtCopyGlob( Proc.id, idAddGroup) or GDB_ID.NULL
|
||||
local nAddIdTunnel = EgtCopyGlob( nOriginalTmIdTunnel, idAddGroup) or GDB_ID.NULL
|
||||
local ptSplit = FeatureSplittingPoints[#FeatureSplittingPoints] + Vector3d( BeamData.MILL_OVERLAP / 2, 0, 0)
|
||||
EgtCutSurfTmPlane( nAddId, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
EgtCutSurfTmPlane( nAddIdTunnel, ptSplit, X_AX(), true, GDB_RT.GLOB)
|
||||
table.insert( vAddId, nAddId)
|
||||
table.insert( vAddIdTunnel, nAddIdTunnel)
|
||||
end
|
||||
|
||||
return vAddId, vAddIdTunnel
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO rimuovere il calcolo MRR dove non serve, è fatto tutto alla fine.
|
||||
function STR0002.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machining = {}
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.dTimeToMachine = 0
|
||||
|
||||
-- se la lavorazione ostacola il pinzaggio, non posso farla
|
||||
if not IsTopologyOk( Proc) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not implemented'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
-- se la lavorazione ostacola il pinzaggio, non posso farla, serve una lavorazioen che lasci il testimone
|
||||
if MachiningLib.IsFeatureHinderingClamping( Proc, Part) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not applicable ( Feature hinders clamping)'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
local ToolInfo = {}
|
||||
local Pocketing = {}
|
||||
|
||||
Strategy.Machining = GetBestPocketingStrategy( Proc, Part)
|
||||
|
||||
if Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
local vAddId = {}
|
||||
local vAddIdTunnel = {}
|
||||
|
||||
-- recupero superficie, se necessario trimmata sugli spezzoni
|
||||
vAddId, vAddIdTunnel = GetSplitSurfaces( Proc, Part, bAddMachining)
|
||||
|
||||
-- si applicano le lavorazioni
|
||||
for i = 1, #vAddId do
|
||||
for j = 1, #Strategy.Machining do
|
||||
if Strategy.Machining[j].bIsApplicable then
|
||||
Pocketing = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING)
|
||||
Pocketing.Steps = {}
|
||||
Pocketing.LeadIn = {}
|
||||
Pocketing.nType = MCH_MY.POCKETING
|
||||
Pocketing.nSubType = EgtIf( Proc.Topology.sName == 'Pocket-5-Blind' or Proc.Topology.sName == 'Tunnel-4-Through', MCH_POCK_SUB.SPIRALOUT, MCH_POCK_SUB.SPIRALIN)
|
||||
Pocketing.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Pocketing.Steps.dStep = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dStep
|
||||
Pocketing.Steps.dSideStep = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dSideStep
|
||||
Pocketing.nToolIndex = Strategy.Machining[j].ToolInfo.nToolIndex
|
||||
Pocketing.LeadIn.dTangentDistance = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dDiameter / 2
|
||||
Pocketing.LeadIn.dElevation = TOOLS[Strategy.Machining[j].ToolInfo.nToolIndex].dDiameter / 2
|
||||
Pocketing.sDepth = -Strategy.Machining[j].ToolInfo.dResidualDepth
|
||||
Pocketing.dResidualDepth = Strategy.Machining[j].ToolInfo.dResidualDepth
|
||||
-- TODO vedere se questo parametro con svuotature nuove si può rimuovere
|
||||
Pocketing.dOpenMinSafe = Strategy.Parameters.dOpenMinSafe
|
||||
-- il quarto ciclo è la lavorazione opposta sulla faccia Tunnel
|
||||
if Strategy.Machining[j].bToolInvert then
|
||||
Pocketing.bToolInvert = true
|
||||
end
|
||||
-- eventuali antischeggia
|
||||
if Strategy.Machining[j].bAddAntiSplint then
|
||||
local OptionalParametersAntiSplint = {
|
||||
bIsSplitFeature = ( #vAddId > 1),
|
||||
dExtendAfterTail = Strategy.Parameters.dExtendAfterTail
|
||||
}
|
||||
local AntiSplints = AntiSplintOnFace.Make( Proc, Part, Proc.Faces[ Strategy.Machining[j].idFaceToMachine + 1], OptionalParametersAntiSplint)
|
||||
local bAreAllAntisplintsApplicable = true
|
||||
for k = 1, #AntiSplints do
|
||||
if AntiSplints[k].bIsApplicable then
|
||||
if bAddMachining then
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, AntiSplints[k])
|
||||
end
|
||||
else
|
||||
bAreAllAntisplintsApplicable = false
|
||||
end
|
||||
end
|
||||
if bAreAllAntisplintsApplicable then
|
||||
-- TODO qui si dovrà distinguere tra antischeggia di lama e di fresa; al momento è solo di lama
|
||||
if Strategy.Result.dQuality == FeatureLib.GetStrategyQuality( 'STD') then
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'BEST')
|
||||
end
|
||||
end
|
||||
end
|
||||
-- se ho una sola trimesh, sto lavorando la Proc direttamente e non ho spezzato. Applico direttamente alla geometria calcolata prima
|
||||
if #vAddId == 1 then
|
||||
Pocketing.Geometry = {{ Strategy.Machining[j].idProc, Strategy.Machining[j].idFaceToMachine}}
|
||||
Pocketing.vtToolDirection = Strategy.Machining[j].vtFaceNormal
|
||||
|
||||
-- TODO controllare parametro danneggiamento ammesso per decidere se spostare dopo taglio seprazione
|
||||
-- se è aperta sulla coda, dico che deve essere fatta dopo la separazione
|
||||
if Proc.AffectedFaces.bLeft then
|
||||
Pocketing.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
Pocketing.nSCC = GetSCC( Proc, Pocketing)
|
||||
Pocketing.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Pocketing, Part)
|
||||
Strategy.Result.dTimeToMachine = Strategy.Result.dTimeToMachine + Pocketing.dTimeToMachine
|
||||
|
||||
if bAddMachining then
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Pocketing)
|
||||
end
|
||||
else
|
||||
-- TODO controllare parametro danneggiamento ammesso per decidere se spostare dopo taglio seprazione
|
||||
-- se è aperta sulla coda, dico che deve essere fatta dopo la separazione
|
||||
if Proc.AffectedFaces.bLeft and i == #vAddId then
|
||||
Pocketing.sStage = 'AfterTail'
|
||||
end
|
||||
for k = 1, Proc.nFct do
|
||||
local vtNSplitFace
|
||||
local nIdTm = EgtIf( Strategy.Machining[j].bMachAppliedToTunnelFace, vAddIdTunnel[i], vAddId[i])
|
||||
Pocketing.ptCenter, vtNSplitFace = EgtSurfTmFacetCenter( nIdTm, k - 1, GDB_ID.ROOT)
|
||||
Pocketing.vtToolDirection = vtNSplitFace or Strategy.Machining[j].vtFaceNormal
|
||||
if Pocketing.bToolInvert then
|
||||
Pocketing.vtToolDirection = -Pocketing.vtToolDirection
|
||||
end
|
||||
if vtNSplitFace and AreSameVectorApprox( vtNSplitFace * EgtIf( Pocketing.bToolInvert, -1, 1), Strategy.Machining[j].vtFaceNormal) then
|
||||
Pocketing.Geometry = {{ nIdTm, k - 1}}
|
||||
|
||||
Pocketing.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Pocketing, Part)
|
||||
Strategy.Result.dTimeToMachine = Strategy.Result.dTimeToMachine + Pocketing.dTimeToMachine
|
||||
|
||||
if bAddMachining then
|
||||
bAreAllMachiningsAdded = bAreAllMachiningsAdded and MachiningLib.AddMachinings( Proc, Pocketing)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- TODO se incompleta il volume non è corretto, ma conta? L'MRR ha senso nelle incomplete??
|
||||
Strategy.Result.dMRR = ( dFeatureVolume / Strategy.Result.dTimeToMachine) / pow( 10, 6)
|
||||
else
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0002
|
||||
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"sStrategyId": "STR0003",
|
||||
"sStrategyName": "Blade plus ChainSaw",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "bFinishWithChainSaw",
|
||||
"sNameNge": "ALLOW_FINISH_CHAINSAW",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Finish with chainsaw if needed",
|
||||
"sDescriptionLong": "Finish with chainsaw if needed",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dExtendAfterTail",
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bForceLongcutBlade",
|
||||
"sNameNge": "USE_LONGCUT_BLADE",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Force ripping blade",
|
||||
"sDescriptionLong": "Force the use of ripping blade, designed for cuts parallel to the grain",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bNotCompleteWithBladeRadius",
|
||||
"sNameNge": "NOT_COMPLETE_WITH_BLADE_RADIUS",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Not complete with Blade radius imprint left",
|
||||
"sDescriptionLong": "If the parameter is active, the automatism considers the feature as - not complete - if the blade radius imprint is left",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bUseZigZagMortising",
|
||||
"sNameNge": "USE_ZIGZAG_CHAINSAW",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Use Zig-Zag ChainSaw",
|
||||
"sDescriptionLong": "Enable the parameter to set the Zig-Zag movement on the ChainSaw machining. Deactivate it to use One-Way movement.",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bSortBySegment",
|
||||
"sNameNge": "SORT_BY_SEGMENT",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Sort by segment",
|
||||
"sDescriptionLong": "Sort the machinings according to the piece-segment where the machining has inserted",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCanDamageNextPiece",
|
||||
"sNameNge": "DAMAGE_NEXT_PIECE",
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Damage next piece",
|
||||
"sDescriptionLong": "This option allows you to decide how to consider the next piece in the bar. The software calculates specifics LeadIn/out to respect the parameter. This parameter may change the machining time",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Never damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ONLY_IF_RAWPART",
|
||||
"sDescriptionShort": "Damage only if raw",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ALWAYS",
|
||||
"sDescriptionShort": "Can damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,713 @@
|
||||
-- Strategia: STR0003
|
||||
-- Descrizione
|
||||
-- Lama + motosega per slot
|
||||
-- Feature: tipo lapjoint
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO
|
||||
-- 1 - Gestire lavorazioni da sotto
|
||||
-- 2 - Inserire antischeggia (fresa o lama)
|
||||
-- 3 - Smusso a V
|
||||
-- 4 - Implementare lavorazione di geometrie inclinate
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local FaceByBlade = require( 'FACEBYBLADE')
|
||||
local FaceByChainsaw = require( 'FACEBYCHAINSAW')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0003 = {}
|
||||
local Strategy = {}
|
||||
local Blade = {}
|
||||
local Chainsaw = {}
|
||||
Blade.Result = {}
|
||||
Chainsaw.Result = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function IsTopologyOk( Proc)
|
||||
if Proc.Topology.bAllRightAngles and
|
||||
( Proc.Topology.sName == 'Pocket-5-Blind' or
|
||||
Proc.Topology.sName == 'Groove-4-Blind' or
|
||||
Proc.Topology.sName == 'Tunnel-4-Through') then
|
||||
|
||||
return true
|
||||
|
||||
-- canale ammesso solo se lati paralleli a 2 a 2
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through'
|
||||
and ( AreOppositeVectorApprox( Proc.MainFaces.BottomFaces[1].MainEdges.LongEdges[1].vtN, Proc.MainFaces.BottomFaces[1].MainEdges.LongEdges[2].vtN)) then
|
||||
|
||||
return true
|
||||
|
||||
else
|
||||
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- TODO si può unificare con eguale funzione in STR0004
|
||||
local function SortMachiningsBySegment( MachiningA, MachiningB)
|
||||
if MachiningA.nFeatureSegment > MachiningB.nFeatureSegment then
|
||||
return false
|
||||
elseif MachiningB.nFeatureSegment > MachiningA.nFeatureSegment then
|
||||
return true
|
||||
else
|
||||
if TOOLS[ MachiningA.nToolIndex].sFamily == 'SAWBLADE' and TOOLS[ MachiningB.nToolIndex].sFamily == 'MORTISE' then
|
||||
return true
|
||||
elseif TOOLS[ MachiningA.nToolIndex].sFamily == 'MORTISE' and TOOLS[ MachiningB.nToolIndex].sFamily == 'SAWBLADE' then
|
||||
return false
|
||||
else
|
||||
if MachiningA.sEdgeType == 'Side' and MachiningB.sEdgeType ~= 'Side' then
|
||||
return true
|
||||
elseif MachiningB.sEdgeType == 'Side' and MachiningA.sEdgeType ~= 'Side' then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function SortMachiningsByTool( MachiningA, MachiningB)
|
||||
if TOOLS[ MachiningA.nToolIndex].sFamily == 'SAWBLADE' and TOOLS[ MachiningB.nToolIndex].sFamily == 'MORTISE' then
|
||||
return true
|
||||
elseif TOOLS[ MachiningA.nToolIndex].sFamily == 'MORTISE' and TOOLS[ MachiningB.nToolIndex].sFamily == 'SAWBLADE' then
|
||||
return false
|
||||
else
|
||||
if MachiningA.nFeatureSegment > MachiningB.nFeatureSegment then
|
||||
return false
|
||||
elseif MachiningB.nFeatureSegment > MachiningA.nFeatureSegment then
|
||||
return true
|
||||
else
|
||||
if MachiningA.sEdgeType == 'Side' and MachiningB.sEdgeType ~= 'Side' then
|
||||
return true
|
||||
elseif MachiningB.sEdgeType == 'Side' and MachiningA.sEdgeType ~= 'Side' then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function MergeResults( Result)
|
||||
local SortedResult = {}
|
||||
|
||||
for i = 1, #Result.Side do
|
||||
if Result.Side[i].bIsApplicable then
|
||||
table.insert( SortedResult, Result.Side[i])
|
||||
end
|
||||
end
|
||||
for i = 1, #Result.Bottom do
|
||||
if Result.Bottom[i].bIsApplicable then
|
||||
table.insert( SortedResult, Result.Bottom[i])
|
||||
end
|
||||
end
|
||||
for i = 1, #Result.Opposite do
|
||||
if Result.Opposite[i].bIsApplicable then
|
||||
table.insert( SortedResult, Result.Opposite[i])
|
||||
end
|
||||
end
|
||||
|
||||
return SortedResult
|
||||
end
|
||||
|
||||
|
||||
local function AddResult( Machining, Result)
|
||||
table.insert( Result, {})
|
||||
if not Result.Bottom then
|
||||
Result.Bottom = {}
|
||||
end
|
||||
if not Result.Side then
|
||||
Result.Side = {}
|
||||
end
|
||||
if not Result.Opposite then
|
||||
Result.Opposite = {}
|
||||
end
|
||||
if Machining.sEdgeType == 'Bottom' then
|
||||
table.insert( Result.Bottom, Machining)
|
||||
elseif Machining.sEdgeType == 'Side' then
|
||||
table.insert( Result.Side, Machining)
|
||||
elseif Machining.sEdgeType == 'Opposite' then
|
||||
table.insert( Result.Opposite, Machining)
|
||||
else
|
||||
error('AddResult : unknown edge type')
|
||||
end
|
||||
|
||||
return Result
|
||||
end
|
||||
|
||||
|
||||
local function AddMachinings( Proc, Machinings)
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
for i = 1, #Machinings do
|
||||
if Machinings[i].bIsApplicable then
|
||||
local bIsMachiningAdded
|
||||
bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Machinings[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
Strategy.Result.sInfo = Strategy.Result.sInfo .. '\n' .. Machinings[i].sMessage
|
||||
end
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded
|
||||
end
|
||||
|
||||
|
||||
function Blade.AddResult( Cutting)
|
||||
AddResult( Cutting, Blade.Result)
|
||||
end
|
||||
|
||||
|
||||
function Chainsaw.AddResult( Mortising)
|
||||
AddResult( Mortising, Chainsaw.Result)
|
||||
end
|
||||
|
||||
|
||||
local function GetTotalAreaToMachine( Machinings)
|
||||
local dTotalAreaToMachine = 0
|
||||
|
||||
for i = 1, #Machinings do
|
||||
local Machining = Machinings[i]
|
||||
dTotalAreaToMachine = dTotalAreaToMachine + Machining.dAreaToMachine
|
||||
end
|
||||
|
||||
return dTotalAreaToMachine
|
||||
end
|
||||
|
||||
|
||||
function STR0003.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri da default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.sInfo = ''
|
||||
Blade.Result = {}
|
||||
Chainsaw.Result = {}
|
||||
|
||||
|
||||
-- se arriva una feature senza MainFaces o MainEdges necessari la strategia non è applicabile
|
||||
-- TODO riuniure a IsTopologyOk?
|
||||
if not Proc.MainFaces
|
||||
or not Proc.MainFaces.LongFaces[1]
|
||||
or not Proc.MainFaces.LongFaces[1].MainEdges then
|
||||
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
if not IsTopologyOk( Proc) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. Strategy.sName .. ' not implemented'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- se canale e lati non a 90deg la strategia non è applicabile
|
||||
-- TODO questo è temporaneo finchè non si gestiscono correttamente i lati obliqui per le groove-3-through
|
||||
-- la dPocketHeight è già gestita, ma va allungato il percorso dove c'è l'angolo > 90
|
||||
if Proc.Topology.sName == 'Groove-3-Through' then
|
||||
local BottomFace = Proc.MainFaces.BottomFaces[1]
|
||||
if abs( BottomFace.Edges[1].vtEdge * BottomFace.Edges[2].vtEdge) > 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece - BeamData.CUT_EXTRA, 0)
|
||||
if MachiningLib.CanExtendAfterTail( Strategy.Parameters.sCanDamageNextPiece, Part) then
|
||||
dExtendAfterTail = 10000
|
||||
end
|
||||
|
||||
-- volume della feature
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
local bIsSplitFeature = false
|
||||
if #FeatureSplittingPoints > 0 then
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
|
||||
-- altezza tasca
|
||||
local dPocketHeight = 0
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
dPocketHeight = Proc.MainFaces.SideFaces[1].MainEdges.OppositeEdges[1].dLength
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
local BottomFace = Proc.MainFaces.BottomFaces[1]
|
||||
local frFrame = Frame3d( BottomFace.ptCenter, BottomFace.vtN, BottomFace.MainEdges.LongEdges[1].vtEdge)
|
||||
local b3BottomFace = EgtSurfTmGetFacetBBoxRef( Proc.id, BottomFace.id, GDB_BB.STANDARD, frFrame)
|
||||
dPocketHeight = b3BottomFace:getDimY()
|
||||
else
|
||||
dPocketHeight = Proc.MainFaces.BottomFaces[1].MainEdges.SideEdges[1].dLength
|
||||
end
|
||||
|
||||
-- riferimenti locali per leggibilità e performance
|
||||
local LongFace = Proc.MainFaces.LongFaces[1]
|
||||
local OppositeEdge1 = LongFace.MainEdges.OppositeEdges[1]
|
||||
local OppositeEdge2 = LongFace.MainEdges.OppositeEdges[2]
|
||||
local SideEdge1 = LongFace.MainEdges.SideEdges[1]
|
||||
local SideEdge2 = LongFace.MainEdges.SideEdges[2]
|
||||
local BottomEdge = LongFace.MainEdges.BottomEdge
|
||||
|
||||
-- TODO funzione separata
|
||||
-- TODO è meglio cercare la lama qui e passarla alla FACEBYBLADE, la scelta è più precisa
|
||||
-- lama - calcolo lavorazioni
|
||||
local Cutting = {}
|
||||
-- parametri comuni a tutte le lavorazioni cutting
|
||||
local OptionalParameters = {
|
||||
bForceLongcutBlade = Strategy.Parameters.bForceLongcutBlade,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dPocketHeight = dPocketHeight,
|
||||
bIsSplitFeature = bIsSplitFeature
|
||||
}
|
||||
|
||||
-- primo lato del tunnel o lato di fondo
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
Cutting = FaceByBlade.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
else
|
||||
Cutting = FaceByBlade.Make( Proc, Part, LongFace, BottomEdge, OptionalParameters)
|
||||
end
|
||||
Blade.AddResult( Cutting)
|
||||
|
||||
-- lato opposto del tunnel
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Cutting = FaceByBlade.Make( Proc, Part, LongFace, OppositeEdge2, OptionalParameters)
|
||||
Blade.AddResult( Cutting)
|
||||
|
||||
-- per tutte le altre topologie lavorazione lati aggiuntivi
|
||||
else
|
||||
-- se la lama non è arrivata sul fondo e c'è almeno un lato aperto va lavorato
|
||||
if Blade.Result.Bottom[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
-- eventuale lavorazione di lama - lato della tasca da cui inizia la lavorazione
|
||||
if BottomEdge.bIsStartOpen then
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Cutting = FaceByBlade.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Cutting.dAreaToMachine = Cutting.dDepthToMachine * ( Cutting.dEdgeLength - Blade.Result.Bottom[1].dDepthToMachine)
|
||||
Blade.AddResult( Cutting)
|
||||
end
|
||||
|
||||
-- eventuale lavorazione di lama - lato della tasca in cui finisce la lavorazione
|
||||
if BottomEdge.bIsEndOpen then
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Cutting = FaceByBlade.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Cutting.dAreaToMachine = Cutting.dDepthToMachine * ( Cutting.dEdgeLength - Blade.Result.Bottom[1].dDepthToMachine)
|
||||
Blade.AddResult( Cutting)
|
||||
end
|
||||
|
||||
-- la lama è arrivata sul fondo e tasca passante, non servono ulteriori lavorazioni
|
||||
elseif #( Proc.MainFaces.SideFaces) == 0 then
|
||||
Strategy.Parameters.bFinishWithChainSaw = false
|
||||
Strategy.Parameters.bNotCompleteWithBladeRadius = false
|
||||
end
|
||||
end
|
||||
|
||||
-- lama - lavorazioni raggruppate in unica lista, escluse le lavorazioni non applicabili
|
||||
Blade.Result.Sorted = MergeResults( Blade.Result)
|
||||
|
||||
-- lama - calcolo area lavorata
|
||||
local dAreaToMachineBlade = GetTotalAreaToMachine( Blade.Result.Sorted)
|
||||
|
||||
-- lama - aggiunta eventuali lavorazioni splittate
|
||||
if bIsSplitFeature then
|
||||
Blade.Result.Sorted = MachiningLib.GetSplitMachinings( Blade.Result.Sorted, FeatureSplittingPoints, Part)
|
||||
end
|
||||
|
||||
-- lama - nessuna lavorazione successiva - aggiunta lavorazioni e calcolo risultati
|
||||
if not Strategy.Parameters.bFinishWithChainSaw then
|
||||
|
||||
-- ordinamento
|
||||
if Strategy.Parameters.bSortBySegment then
|
||||
table.sort( Blade.Result.Sorted, SortMachiningsBySegment)
|
||||
else
|
||||
table.sort( Blade.Result.Sorted, SortMachiningsByTool)
|
||||
end
|
||||
|
||||
-- aggiunta lavorazioni
|
||||
local bAreAllMachiningsAdded = true
|
||||
if bAddMachining then
|
||||
bAreAllMachiningsAdded = AddMachinings( Proc, Blade.Result.Sorted)
|
||||
end
|
||||
|
||||
-- calcolo risultati
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( Blade.Result.Sorted)
|
||||
Strategy.Result.dCompletionPercentage = dAreaToMachineBlade / LongFace.dArea * 100
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Strategy.Result.dCompletionPercentage)
|
||||
Strategy.Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Blade.Result.Sorted)
|
||||
Strategy.Result.dMRR = ( dFeatureVolume / Strategy.Result.dTimeToMachine) / pow( 10, 6)
|
||||
if #Blade.Result.Sorted > 0 then
|
||||
if not Strategy.Parameters.bNotCompleteWithBladeRadius and Cutting.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
end
|
||||
-- non ha senso che STR0003 lama+catena sia applicabile se la lama non può lavorare, in quel caso deve essere scelta la STR0004 solo catena
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
Strategy.Parameters.bFinishWithChainSaw = false
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-- TODO funzione separata
|
||||
-- sega a catena - calcolo lavorazioni
|
||||
local Mortising = {}
|
||||
-- parametri comuni a tutte le lavorazioni mortising
|
||||
OptionalParameters = {
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dPocketHeight = dPocketHeight,
|
||||
bIsSplitFeature = bIsSplitFeature
|
||||
}
|
||||
|
||||
if Proc.Topology.sName == 'Groove-4-Blind' or Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
|
||||
-- si lavora solamente l'impronta lama sui lati chiusi
|
||||
if ( Blade.Result.Bottom[1].dResidualDepth < 10 * GEO.EPS_SMALL) and
|
||||
( BottomEdge.dLength > 3 * Blade.Result.Bottom[1].dToolMarkLength - 10 * GEO.EPS_SMALL) then
|
||||
|
||||
if not BottomEdge.bIsStartOpen then
|
||||
OptionalParameters.sSideToMachine = 'Start'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Bottom[1].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, BottomEdge, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * Mortising.dEdgeLength
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
|
||||
if not BottomEdge.bIsEndOpen then
|
||||
OptionalParameters.sSideToMachine = 'End'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Bottom[1].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, BottomEdge, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * Mortising.dEdgeLength
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
|
||||
-- reset parametri opzionali
|
||||
OptionalParameters.sSideToMachine = nil
|
||||
OptionalParameters.dLengthToMachine = nil
|
||||
|
||||
-- si lavora tutto il fondo
|
||||
else
|
||||
OptionalParameters.dMaxElev = Blade.Result.Bottom[1].dResidualDepth + BeamData.CUT_EXTRA
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, BottomEdge, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dMaxElev = nil
|
||||
end
|
||||
|
||||
-- ancora materiale residuo - se possibile si lavora dal lato
|
||||
if Chainsaw.Result.Bottom[#Chainsaw.Result.Bottom].dResidualDepth > 10 * GEO.EPS_SMALL
|
||||
and #Proc.MainFaces.SideFaces == 1 then
|
||||
|
||||
-- si lavora solamente l'impronta lama sul fondo
|
||||
if ( #Blade.Result.Side > 0) and Blade.Result.Side[1].dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
|
||||
if ( BottomEdge.bIsStartOpen and SideEdge1.dLength > 3 * Blade.Result.Side[1].dToolMarkLength - 10 * GEO.EPS_SMALL) then
|
||||
|
||||
OptionalParameters.sSideToMachine = 'End'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Side[1].dToolMarkLength
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
|
||||
elseif ( BottomEdge.bIsEndOpen and SideEdge2.dLength > 3 * Blade.Result.Side[1].dToolMarkLength - 10 * GEO.EPS_SMALL) then
|
||||
|
||||
OptionalParameters.sSideToMachine = 'Start'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Side[2].dToolMarkLength
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
end
|
||||
|
||||
-- si lavora tutto il lato
|
||||
else
|
||||
local dBladeResidualDepth
|
||||
|
||||
if #Blade.Result.Side > 0 then
|
||||
dBladeResidualDepth = Blade.Result.Side[1].dResidualDepth
|
||||
else
|
||||
dBladeResidualDepth = Blade.Result.Bottom[1].dResidualDepth
|
||||
end
|
||||
|
||||
if BottomEdge.bIsStartOpen then
|
||||
OptionalParameters.dMaxElev = dBladeResidualDepth + BeamData.CUT_EXTRA
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
|
||||
elseif BottomEdge.bIsEndOpen then
|
||||
OptionalParameters.dMaxElev = dBladeResidualDepth + BeamData.CUT_EXTRA
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
end
|
||||
end
|
||||
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
|
||||
if Blade.Result.Bottom[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
-- si lavora tutto il fondo
|
||||
OptionalParameters.dMaxElev = Blade.Result.Bottom[1].dResidualDepth + BeamData.CUT_EXTRA
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, BottomEdge, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dMaxElev = nil
|
||||
|
||||
-- ancora materiale residuo - si lavorano i lati
|
||||
if Chainsaw.Result.Bottom[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
OptionalParameters.bExtendWithCornerRadius = true
|
||||
|
||||
-- si lavora solamente l'impronta lama sul fondo
|
||||
if ( Blade.Result.Side[1].dResidualDepth < 10 * GEO.EPS_SMALL and SideEdge1.dLength > 3 * Blade.Result.Side[1].dToolMarkLength - 10 * GEO.EPS_SMALL) and
|
||||
( Blade.Result.Side[2].dResidualDepth < 10 * GEO.EPS_SMALL and SideEdge2.dLength > 3 * Blade.Result.Side[2].dToolMarkLength - 10 * GEO.EPS_SMALL) then
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge1.dElevation + BeamData.CUT_EXTRA
|
||||
OptionalParameters.sSideToMachine = 'End'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Side[1].dToolMarkLength
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- ancora materiale residuo - si lavora da entrambi i lati
|
||||
if Chainsaw.Result.Side[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
Chainsaw.Result.Side[1].bIsApplicable = false
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge1.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.sSideToMachine = 'End'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Side[1].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge2.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.sSideToMachine = 'Start'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Side[2].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = 0
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- lavorando dai due lati non c'è materiale residuo - si può eliminare la lavorazione del fondo
|
||||
if Chainsaw.Result.Side[2].dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Chainsaw.Result.Bottom[1].bIsApplicable = false
|
||||
end
|
||||
end
|
||||
|
||||
-- si lavora tutto il lato
|
||||
else
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge1.dElevation + BeamData.CUT_EXTRA
|
||||
OptionalParameters.dMaxElev = Blade.Result.Side[1].dResidualDepth + BeamData.CUT_EXTRA
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- ancora materiale residuo - si lavora da entrambi i lati
|
||||
if Chainsaw.Result.Side[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
Chainsaw.Result.Side[1].bIsApplicable = false
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge1.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.dMaxElev = Blade.Result.Side[1].dResidualDepth + BeamData.CUT_EXTRA
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge2.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.dMaxElev = Blade.Result.Side[2].dResidualDepth + BeamData.CUT_EXTRA
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = 0
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- lavorando dai due lati non c'è materiale residuo - si può disabilitare la lavorazione del fondo
|
||||
if Chainsaw.Result.Side[2].dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Chainsaw.Result.Bottom[1].bIsApplicable = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
OptionalParameters.bExtendWithCornerRadius = true
|
||||
|
||||
-- si lavora solamente l'impronta lama sul lato opposto
|
||||
if ( Blade.Result.Opposite[1].dResidualDepth < 10 * GEO.EPS_SMALL and OppositeEdge1.dLength > 3 * Blade.Result.Opposite[1].dToolMarkLength - 10 * GEO.EPS_SMALL) and
|
||||
( Blade.Result.Opposite[2].dResidualDepth < 10 * GEO.EPS_SMALL and OppositeEdge2.dLength > 3 * Blade.Result.Opposite[2].dToolMarkLength - 10 * GEO.EPS_SMALL) then
|
||||
|
||||
OptionalParameters.dLengthToMachine = max(
|
||||
Blade.Result.Opposite[1].dToolMarkLength,
|
||||
Blade.Result.Opposite[2].dToolMarkLength
|
||||
)
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge1.dElevation + BeamData.CUT_EXTRA
|
||||
OptionalParameters.sSideToMachine = 'Start'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * Mortising.dEdgeLength
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.sSideToMachine = 'End'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = 0
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- se lavorando solo da un lato rimane materiale residuo, si lavora da entrambi
|
||||
if Chainsaw.Result.Opposite[1].dResidualDepth > 10 * GEO.EPS_SMALL
|
||||
or Chainsaw.Result.Opposite[2].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
Chainsaw.Result.Opposite[1].bIsApplicable = false
|
||||
Chainsaw.Result.Opposite[2].bIsApplicable = false
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge1.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.sSideToMachine = 'Start'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Opposite[1].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * Mortising.dEdgeLength
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.sSideToMachine = 'End'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Opposite[1].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = 0
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge2.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.sSideToMachine = 'Start'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Opposite[2].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * Mortising.dEdgeLength
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.sSideToMachine = 'End'
|
||||
OptionalParameters.dLengthToMachine = Blade.Result.Opposite[2].dToolMarkLength
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = 0
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
|
||||
-- si lavora tutto il lato
|
||||
else
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge1.dElevation + BeamData.CUT_EXTRA
|
||||
OptionalParameters.dMaxElev = Blade.Result.Opposite[1].dResidualDepth + BeamData.CUT_EXTRA
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
if Chainsaw.Result.Opposite[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
Chainsaw.Result.Opposite[1].bIsApplicable = false
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge1.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.dMaxElev = Blade.Result.Opposite[1].dResidualDepth + BeamData.CUT_EXTRA
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge2.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
OptionalParameters.dMaxElev = Blade.Result.Opposite[2].dResidualDepth + BeamData.CUT_EXTRA
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge2, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- sega a catena - lavorazioni raggruppate in unica lista
|
||||
Chainsaw.Result.Sorted = MergeResults( Chainsaw.Result)
|
||||
|
||||
-- sega a catena - calcolo area lavorata
|
||||
local dAreaToMachineChainsaw = GetTotalAreaToMachine( Chainsaw.Result.Sorted)
|
||||
|
||||
-- sega a catena - aggiunta eventuali lavorazioni splittate
|
||||
if bIsSplitFeature then
|
||||
Chainsaw.Result.Sorted = MachiningLib.GetSplitMachinings( Chainsaw.Result.Sorted, FeatureSplittingPoints, Part)
|
||||
end
|
||||
|
||||
-- tutte le lavorazioni di tutti gli utensili in unica lista
|
||||
local Result = {}
|
||||
for i = 1, #Blade.Result.Sorted do
|
||||
table.insert( Result, Blade.Result.Sorted[i])
|
||||
end
|
||||
for i = 1, #Chainsaw.Result.Sorted do
|
||||
table.insert( Result, Chainsaw.Result.Sorted[i])
|
||||
end
|
||||
|
||||
-- ordinamento
|
||||
if Strategy.Parameters.bSortBySegment then
|
||||
table.sort( Result, SortMachiningsBySegment)
|
||||
else
|
||||
table.sort( Result, SortMachiningsByTool)
|
||||
end
|
||||
|
||||
-- aggiunta lavorazioni per tutti gli utensili
|
||||
local bAreAllMachiningsAdded = true
|
||||
if bAddMachining then
|
||||
bAreAllMachiningsAdded = AddMachinings( Proc, Result)
|
||||
end
|
||||
|
||||
-- calcolo risultati
|
||||
Strategy.Result.dCompletionPercentage = max( dAreaToMachineBlade, dAreaToMachineChainsaw) / LongFace.dArea * 100
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Strategy.Result.dCompletionPercentage)
|
||||
if #Result > 0 then
|
||||
if Strategy.Result.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
end
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( Result)
|
||||
Strategy.Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Result)
|
||||
Strategy.Result.dMRR = ( dFeatureVolume / Strategy.Result.dTimeToMachine) / pow( 10, 6)
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0003
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"sStrategyId": "STR0004",
|
||||
"sStrategyName": "ChainSaw",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "bUseZigZagMortising",
|
||||
"sNameNge": "USE_ZIGZAG_CHAINSAW",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Use Zig-Zag ChainSaw",
|
||||
"sDescriptionLong": "Enable the parameter to set the Zig-Zag movement on the ChainSaw machining. Deactivate it to use One-Way movement.",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dExtendAfterTail",
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCanDamageNextPiece",
|
||||
"sNameNge": "DAMAGE_NEXT_PIECE",
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Damage next piece",
|
||||
"sDescriptionLong": "This option allows you to decide how to consider the next piece in the bar. The software calculates specifics LeadIn/out to respect the parameter. This parameter may change the machining time",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Never damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ONLY_IF_RAWPART",
|
||||
"sDescriptionShort": "Damage only if raw",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ALWAYS",
|
||||
"sDescriptionShort": "Can damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
-- Strategia: STR0004
|
||||
-- Descrizione
|
||||
-- motosega per slot
|
||||
-- Feature: tipo lapjoint
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO
|
||||
-- 1 - Inserire antischeggia (fresa o lama)
|
||||
-- 2 - Smusso a V
|
||||
-- 3 - Implementare lavorazione di geometrie inclinate
|
||||
-- 4 - Gestire lavorazioni da sotto (ove possibile, in generale la motosega non lavora da sotto)
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local FaceByChainsaw = require( 'FACEBYCHAINSAW')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0004 = {}
|
||||
local Strategy = {}
|
||||
local Chainsaw = {}
|
||||
Chainsaw.Result = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
local function IsTopologyOk( Proc)
|
||||
if Proc.Topology.bAllRightAngles and
|
||||
( Proc.Topology.sName == 'Pocket-5-Blind' or
|
||||
Proc.Topology.sName == 'Groove-3-Through' or
|
||||
Proc.Topology.sName == 'Groove-4-Blind' or
|
||||
Proc.Topology.sName == 'Tunnel-4-Through') then
|
||||
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- TODO si può unificare con Sorting generale
|
||||
local function SortMachiningsBySegment( MachiningA, MachiningB)
|
||||
if MachiningA.nFeatureSegment > MachiningB.nFeatureSegment then
|
||||
return false
|
||||
elseif MachiningB.nFeatureSegment > MachiningA.nFeatureSegment then
|
||||
return true
|
||||
else
|
||||
if MachiningA.sEdgeType == 'Side' and MachiningB.sEdgeType ~= 'Side' then
|
||||
return true
|
||||
elseif MachiningB.sEdgeType == 'Side' and MachiningA.sEdgeType ~= 'Side' then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function AddResult( Machining, Result)
|
||||
table.insert( Result, {})
|
||||
if not Result.Bottom then
|
||||
Result.Bottom = {}
|
||||
end
|
||||
if not Result.Side then
|
||||
Result.Side = {}
|
||||
end
|
||||
if not Result.Opposite then
|
||||
Result.Opposite = {}
|
||||
end
|
||||
if Machining.sEdgeType == 'Bottom' then
|
||||
table.insert( Result.Bottom, Machining)
|
||||
elseif Machining.sEdgeType == 'Side' then
|
||||
table.insert( Result.Side, Machining)
|
||||
elseif Machining.sEdgeType == 'Opposite' then
|
||||
table.insert( Result.Opposite, Machining)
|
||||
else
|
||||
error('AddResult : unknown edge type')
|
||||
end
|
||||
|
||||
return Result
|
||||
end
|
||||
|
||||
|
||||
function Chainsaw.AddResult( Mortising)
|
||||
AddResult( Mortising, Chainsaw.Result)
|
||||
end
|
||||
|
||||
|
||||
local function GetTotalAreaToMachine( Machinings)
|
||||
local dTotalAreaToMachine = 0
|
||||
|
||||
for i = 1, #Machinings do
|
||||
local Machining = Machinings[i]
|
||||
dTotalAreaToMachine = dTotalAreaToMachine + Machining.dAreaToMachine
|
||||
end
|
||||
|
||||
return dTotalAreaToMachine
|
||||
end
|
||||
|
||||
|
||||
function STR0004.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri da default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.sInfo = ''
|
||||
Chainsaw.Result = {}
|
||||
|
||||
if not IsTopologyOk( Proc) then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- calcolo estensione oltre la coda
|
||||
local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece - BeamData.CUT_EXTRA, 0)
|
||||
if MachiningLib.CanExtendAfterTail( Strategy.Parameters.sCanDamageNextPiece, Part) then
|
||||
dExtendAfterTail = 10000
|
||||
end
|
||||
|
||||
-- volume della feature
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
local bIsSplitFeature = false
|
||||
if #FeatureSplittingPoints > 0 then
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
|
||||
-- se arriva una feature senza MainFaces o MainEdges necessari la strategia non è applicabile
|
||||
-- TODO riuniure a IsTopologyOk?
|
||||
if not Proc.MainFaces
|
||||
or not Proc.MainFaces.LongFaces[1]
|
||||
or not Proc.MainFaces.LongFaces[1].MainEdges then
|
||||
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Topology')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- altezza tasca
|
||||
local dPocketHeight = 0
|
||||
if Proc.Topology.sFamily == 'Tunnel' then
|
||||
dPocketHeight = Proc.MainFaces.SideFaces[1].MainEdges.OppositeEdges[1].dLength
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
local BottomFace = Proc.MainFaces.BottomFaces[1]
|
||||
local frFrame = Frame3d( BottomFace.ptCenter, BottomFace.vtN, BottomFace.MainEdges.LongEdges[1].vtEdge)
|
||||
local b3BottomFace = EgtSurfTmGetFacetBBoxRef( Proc.id, BottomFace.id, GDB_BB.STANDARD, frFrame)
|
||||
dPocketHeight = b3BottomFace:getDimY()
|
||||
else
|
||||
dPocketHeight = Proc.MainFaces.BottomFaces[1].MainEdges.SideEdges[1].dLength
|
||||
end
|
||||
|
||||
-- riferimenti locali per leggibilità e performance
|
||||
local LongFace = Proc.MainFaces.LongFaces[1]
|
||||
local OppositeEdge1 = LongFace.MainEdges.OppositeEdges[1]
|
||||
local OppositeEdge2 = LongFace.MainEdges.OppositeEdges[2]
|
||||
local SideEdge1 = LongFace.MainEdges.SideEdges[1]
|
||||
local SideEdge2 = LongFace.MainEdges.SideEdges[2]
|
||||
local BottomEdge = LongFace.MainEdges.BottomEdge
|
||||
|
||||
-- calcolo lavorazioni
|
||||
local Mortising = {}
|
||||
-- parametri comuni a tutte le lavorazioni
|
||||
OptionalParameters = {
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dPocketHeight = dPocketHeight,
|
||||
bIsSplitFeature = bIsSplitFeature
|
||||
}
|
||||
|
||||
-- TODO aggiungere verifica finecorsa e nel caso cambio lato
|
||||
if Proc.Topology.sName == 'Groove-4-Blind' or Proc.Topology.sName == 'Pocket-5-Blind' then
|
||||
|
||||
-- si lavora tutto il fondo
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, BottomEdge, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- materiale residuo - se possibile si lavora dal lato
|
||||
if ( Chainsaw.Result.Bottom[#Chainsaw.Result.Bottom].dResidualDepth > 10 * GEO.EPS_SMALL
|
||||
or not Chainsaw.Result.Bottom[#Chainsaw.Result.Bottom].bIsApplicable)
|
||||
and #Proc.MainFaces.SideFaces == 1 then
|
||||
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
local dLengthAlreadyMachined = 0
|
||||
if Chainsaw.Result.Bottom[1].bIsApplicable then
|
||||
dLengthAlreadyMachined = Chainsaw.Result.Bottom[1].dDepthToMachine
|
||||
end
|
||||
|
||||
if BottomEdge.bIsStartOpen then
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - dLengthAlreadyMachined)
|
||||
elseif BottomEdge.bIsEndOpen then
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - dLengthAlreadyMachined)
|
||||
end
|
||||
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
|
||||
elseif Proc.Topology.sName == 'Groove-3-Through' then
|
||||
|
||||
-- si lavora tutto il fondo
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, BottomEdge, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- materiale residuo - si lavorano i lati
|
||||
if ( Chainsaw.Result.Bottom[1].dResidualDepth > 10 * GEO.EPS_SMALL or
|
||||
not Chainsaw.Result.Bottom[#Chainsaw.Result.Bottom].bIsApplicable) then
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge1.dElevation + BeamData.CUT_EXTRA
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- ancora materiale residuo - si lavora da entrambi i lati
|
||||
if Chainsaw.Result.Side[1].dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
|
||||
Chainsaw.Result.Side[1].bIsApplicable = false
|
||||
|
||||
OptionalParameters.bExtendWithCornerRadius = true
|
||||
OptionalParameters.dDepthToMachine = SideEdge1.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge1, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dDepthToMachine = SideEdge2.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, SideEdge2, OptionalParameters)
|
||||
Mortising.dAreaToMachine = Mortising.dDepthToMachine * ( Mortising.dEdgeLength - Chainsaw.Result.Bottom[1].dDepthToMachine)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- lavorando dai due lati non c'è materiale residuo - si può disabilitare la lavorazione del fondo
|
||||
if Chainsaw.Result.Side[2].dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Chainsaw.Result.Bottom[1].bIsApplicable = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif Proc.Topology.sName == 'Tunnel-4-Through' then
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge1.dElevation + BeamData.CUT_EXTRA
|
||||
OptionalParameters.OppositeToolDirectionMode = 'Enabled'
|
||||
OptionalParameters.bExtendWithCornerRadius = true
|
||||
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
-- se dal lato OppositeEdge1 non è applicabile (solitamente per finecorsa) si prova dal lato opposto
|
||||
if not Chainsaw.Result.Opposite[1].bIsApplicable then
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge2.dElevation + BeamData.CUT_EXTRA
|
||||
Mortising = FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge2, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
|
||||
-- se lavorando solo da un lato rimane materiale residuo, si lavora da entrambi
|
||||
if Chainsaw.Result.Opposite[1].dResidualDepth > 10 * GEO.EPS_SMALL
|
||||
or ( Chainsaw.Result.Opposite[2] and Chainsaw.Result.Opposite[2].dResidualDepth > 10 * GEO.EPS_SMALL) then
|
||||
|
||||
Chainsaw.Result.Opposite[1].bIsApplicable = false
|
||||
if Chainsaw.Result.Opposite[2] then
|
||||
Chainsaw.Result.Opposite[2].bIsApplicable = false
|
||||
end
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge1.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
|
||||
FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge1, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
|
||||
OptionalParameters.dDepthToMachine = OppositeEdge2.dElevation / 2 + BeamData.CUT_EXTRA_MIN
|
||||
|
||||
FaceByChainsaw.Make( Proc, Part, LongFace, OppositeEdge2, OptionalParameters)
|
||||
Chainsaw.AddResult( Mortising)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazioni raggruppate in unica lista
|
||||
Chainsaw.Result.Sorted = {}
|
||||
for i = 1, #Chainsaw.Result.Side do
|
||||
if Chainsaw.Result.Side[i].bIsApplicable then
|
||||
table.insert( Chainsaw.Result.Sorted, Chainsaw.Result.Side[i])
|
||||
end
|
||||
end
|
||||
for i = 1, #Chainsaw.Result.Bottom do
|
||||
if Chainsaw.Result.Bottom[i].bIsApplicable then
|
||||
table.insert( Chainsaw.Result.Sorted, Chainsaw.Result.Bottom[i])
|
||||
end
|
||||
end
|
||||
for i = 1, #Chainsaw.Result.Opposite do
|
||||
if Chainsaw.Result.Opposite[i].bIsApplicable then
|
||||
table.insert( Chainsaw.Result.Sorted, Chainsaw.Result.Opposite[i])
|
||||
end
|
||||
end
|
||||
|
||||
-- aggiunta eventuali lavorazioni splittate
|
||||
if bIsSplitFeature then
|
||||
Chainsaw.Result.Sorted = MachiningLib.GetSplitMachinings( Chainsaw.Result.Sorted, FeatureSplittingPoints, Part)
|
||||
end
|
||||
|
||||
-- ordinamento
|
||||
-- TODO aggiungere ordinamento per utensile
|
||||
table.sort( Chainsaw.Result.Sorted, SortMachiningsBySegment)
|
||||
|
||||
-- calcolo area lavorata
|
||||
local dTotalAreaToMachine = GetTotalAreaToMachine( Chainsaw.Result.Sorted)
|
||||
|
||||
-- aggiunta lavorazioni
|
||||
local bAreAllMachiningsAdded = true
|
||||
for i = 1, #Chainsaw.Result.Sorted do
|
||||
if Chainsaw.Result.Sorted[i].bIsApplicable then
|
||||
if bAddMachining then
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Chainsaw.Result.Sorted[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
Strategy.Result.sInfo = Strategy.Result.sInfo .. '\n' .. Chainsaw.Result.Sorted[i].sMessage
|
||||
end
|
||||
end
|
||||
|
||||
-- calcolo risultati
|
||||
Strategy.Result.dCompletionPercentage = dTotalAreaToMachine / LongFace.dArea * 100
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Strategy.Result.dCompletionPercentage)
|
||||
if #Chainsaw.Result.Sorted > 0 then
|
||||
if Mortising.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
end
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( Chainsaw.Result.Sorted)
|
||||
Strategy.Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Chainsaw.Result.Sorted)
|
||||
Strategy.Result.dMRR = ( dFeatureVolume / Strategy.Result.dTimeToMachine) / pow( 10, 6)
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0004
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"sStrategyId": "STR0005",
|
||||
"sStrategyName": "Blade",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "bForceLongcutBlade",
|
||||
"sNameNge": "USE_LONGCUT_BLADE",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Force ripping blade",
|
||||
"sDescriptionLong": "Force the use of ripping blade, designed for cuts parallel to the grain",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dExtendAfterTail",
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCanDamageNextPiece",
|
||||
"sNameNge": "DAMAGE_NEXT_PIECE",
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Damage next piece",
|
||||
"sDescriptionLong": "This option allows you to decide how to consider the next piece in the bar. The software calculates specifics LeadIn/out to respect the parameter. This parameter may change the machining time",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Never damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ONLY_IF_RAWPART",
|
||||
"sDescriptionShort": "Damage only if raw",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ALWAYS",
|
||||
"sDescriptionShort": "Can damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sCuttingStrategy",
|
||||
"sNameNge": "CUTTING_STRATEGY",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Cutting strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "DROP_WASTE",
|
||||
"sDescriptionShort": "Drop waste",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "KEEP_WASTE_ATTACHED",
|
||||
"sDescriptionShort": "Keep waste attached",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "bDisableDicing",
|
||||
"sNameNge": "DISABLE_DICING",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Disable dicing",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bAllowFastCuts",
|
||||
"sNameNge": "ALLOW_FAST_CUTS",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Prioritize machining speed over quality",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dStripWidth",
|
||||
"sNameNge": "STRIP_WIDTH",
|
||||
"sValue": "5",
|
||||
"sDescriptionShort": "Strip width",
|
||||
"sDescriptionLong": "In case the waste is still kept attached, this is the wigth dimension of the strip",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bFinishWithMill",
|
||||
"sNameNge": "ALLOW_FINISH_MILL",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Clean blade radius with mill",
|
||||
"sDescriptionLong": "Clean blade radius with mill",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMillingOffsetFromSide",
|
||||
"sNameNge": "MILLING_OFFSET_SIDE",
|
||||
"sValue": "1",
|
||||
"sDescriptionShort": "Milling offset from side",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxDimDice",
|
||||
"sSource": "GEN_dMaxDimDice",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
-- Strategia: STR0005
|
||||
-- Descrizione
|
||||
-- lama per taglio facce lasciando codolo o con cubetti
|
||||
-- Feature: cut, longcut, ridgelap, ...
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require( 'BLADETOWASTE')
|
||||
local BladeKeepWaste = require( 'BLADEKEEPWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0005 = {}
|
||||
local Strategy = {}
|
||||
local Blade = {}
|
||||
Blade.Result = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function IsTwoFacesCommonEdgeTooLong( Proc, Part)
|
||||
local bIsTwoFacesCommonEdgeTooLong = false
|
||||
|
||||
-- controlli preventivi
|
||||
if Proc.nFct ~= 2 then
|
||||
error('IsTwoFacesCommonEdgeTooLong : feature must have two faces ')
|
||||
end
|
||||
|
||||
-- ricerca lato in comune
|
||||
local nCommonEdge
|
||||
for i = 1, #Proc.Faces[1].Edges do
|
||||
if Proc.Faces[1].Edges[i].idAdjacentFace > -1 then
|
||||
nCommonEdge = i
|
||||
end
|
||||
end
|
||||
|
||||
-- se due facce, cubetti troppo lunghi in X non si possono fare
|
||||
local ptEdge1, ptEdge2 = Proc.Faces[1].Edges[nCommonEdge].ptStart, Proc.Faces[1].Edges[nCommonEdge].ptEnd
|
||||
local b3BoxEdge = BBox3d( ptEdge1, ptEdge2)
|
||||
local dEdgeLengthOnX = b3BoxEdge:getDimX()
|
||||
if FeatureLib.IsMachiningLong( dEdgeLengthOnX, Part) then
|
||||
bIsTwoFacesCommonEdgeTooLong = true
|
||||
end
|
||||
|
||||
return bIsTwoFacesCommonEdgeTooLong
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0005.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri da default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.sInfo = ''
|
||||
Blade.Result = {}
|
||||
local AuxiliaryData = { bIgnoreNotClampableLength = false}
|
||||
local dTimeToMachine = 0
|
||||
local dMRRBlade = 0
|
||||
local dCompletionPercentage = 0
|
||||
local dQuality = 0
|
||||
local dMRRBladeAddedFace = 0
|
||||
local dCompletionPercentageAddedFace = 0
|
||||
local dQualityAddedFace = 0
|
||||
|
||||
-- più di 3 facce non supportate
|
||||
if Proc.nFct > 3 and ( not Proc.Topology.sFamily == 'DoubleBevel') then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'More than 3 faces not supported')
|
||||
end
|
||||
|
||||
-- estensione oltre la coda
|
||||
local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece, 0)
|
||||
if MachiningLib.CanExtendAfterTail( Strategy.Parameters.sCanDamageNextPiece, Part) then
|
||||
dExtendAfterTail = 10000
|
||||
end
|
||||
|
||||
-- disambiguazione caso 3 facce tipo RidgeLap
|
||||
local idAddedTmFace
|
||||
local nAddedFace
|
||||
if Proc.nFct == 3 and not Proc.Topology.sName == 'Groove-3-Through' then
|
||||
if Proc.AdjacencyMatrix[2][3] < 0 then
|
||||
nAddedFace = 1 - 1
|
||||
elseif Proc.AdjacencyMatrix[1][3] < 0 then
|
||||
nAddedFace = 2 - 1
|
||||
else
|
||||
nAddedFace = 3 - 1
|
||||
end
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
-- faccia aggiuntiva da lavorare
|
||||
idAddedTmFace = EgtCopySurfTmFacet( Proc.id, nAddedFace, nAddGrpId)
|
||||
-- rimozione della terza faccia dalla Proc
|
||||
local idNewProc = EgtCopyGlob( Proc.id, nAddGrpId)
|
||||
EgtSurfTmRemoveFacet( idNewProc, nAddedFace)
|
||||
Proc = FeatureLib.GetProcFromTrimesh( idNewProc, Part, Proc)
|
||||
end
|
||||
|
||||
-- considerazioni necessarie a determinare se lavorare con codolo oppure no
|
||||
local bKeepWasteAttached = ( Strategy.Parameters.sCuttingStrategy == 'KEEP_WASTE_ATTACHED')
|
||||
local bDropWaste = ( Strategy.Parameters.sCuttingStrategy == 'DROP_WASTE')
|
||||
|
||||
local bFeatureHindersClamping = MachiningLib.IsFeatureHinderingClamping( Proc, Part)
|
||||
|
||||
local bIsFeatureLong = FeatureLib.IsMachiningLong( Proc.b3Box:getDimX(), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
||||
local bIsTwoFacesCommonEdgeTooLong = ( ( Proc.Topology and ( Proc.Topology.sName == 'Rabbet-2-Through' or Proc.Topology.sName == 'Bevel-2-Blind')) and IsTwoFacesCommonEdgeTooLong( Proc, Part))
|
||||
|
||||
-- lavorazione con codolo
|
||||
if ( Proc.nFct > 2 and bIsFeatureLong)
|
||||
or ( bFeatureHindersClamping and not bDropWaste)
|
||||
or bKeepWasteAttached then
|
||||
|
||||
local BladeKeepWasteResult
|
||||
local OptionalParameters = { dExtendAfterTail = dExtendAfterTail, dStripWidth = Strategy.Parameters.dStripWidth, bForced = bKeepWasteAttached}
|
||||
AuxiliaryData.bIgnoreNotClampableLength = true
|
||||
Blade.Result, BladeKeepWasteResult = BladeKeepWaste.Make( Proc, Part, OptionalParameters)
|
||||
dTimeToMachine = BladeKeepWasteResult.dTimeToMachine
|
||||
dMRRBlade = BladeKeepWasteResult.dMRR
|
||||
dCompletionPercentage = BladeKeepWasteResult.dCompletionPercentage
|
||||
dQuality = BladeKeepWasteResult.dQuality
|
||||
Strategy.Result.sInfo = BladeKeepWasteResult.sInfo or ''
|
||||
end
|
||||
|
||||
-- lavorazione a cubetti / taglio singolo
|
||||
if #Blade.Result == 0
|
||||
and Proc.nFct < 3
|
||||
and not bKeepWasteAttached
|
||||
and not bIsTwoFacesCommonEdgeTooLong then
|
||||
|
||||
AuxiliaryData.bIgnoreNotClampableLength = false
|
||||
local BladeToWasteResult
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bAllowFastCuts = Strategy.Parameters.bAllowFastCuts,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath,
|
||||
bDisableDicing = Strategy.Parameters.bDisableDicing
|
||||
}
|
||||
Blade.Result, BladeToWasteResult = BladeToWaste.Make( Proc, Part, OptionalParameters)
|
||||
dTimeToMachine = BladeToWasteResult.dTimeToMachine
|
||||
dMRRBlade = BladeToWasteResult.dMRR
|
||||
dCompletionPercentage = BladeToWasteResult.dCompletionPercentage
|
||||
dQuality = BladeToWasteResult.dQuality
|
||||
end
|
||||
|
||||
-- se arrivati qui non è stata ancora applicata alcuna lavorazione, si prova la lavorazione con codolo
|
||||
if #Blade.Result == 0 and not bDropWaste then
|
||||
local BladeKeepWasteResult
|
||||
local OptionalParameters = { dExtendAfterTail = dExtendAfterTail, dStripWidth = Strategy.Parameters.dStripWidth,
|
||||
dMillingOffsetFromSide = Strategy.Parameters.dMillingOffsetFromSide
|
||||
}
|
||||
AuxiliaryData.bIgnoreNotClampableLength = true
|
||||
Blade.Result, BladeKeepWasteResult = BladeKeepWaste.Make( Proc, Part, OptionalParameters)
|
||||
dTimeToMachine = BladeKeepWasteResult.dTimeToMachine
|
||||
dMRRBlade = BladeKeepWasteResult.dMRR
|
||||
dCompletionPercentage = BladeKeepWasteResult.dCompletionPercentage
|
||||
dQuality = BladeKeepWasteResult.dQuality
|
||||
end
|
||||
|
||||
-- lavorazione eventuale terza faccia tipo RidgeLap
|
||||
-- TODO da completare
|
||||
-- TODO va messa per prima????????
|
||||
if idAddedTmFace then
|
||||
local BladeToWasteResult
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail
|
||||
}
|
||||
Blade.Result, BladeToWasteResult = BladeToWaste.Make( idAddedTmFace, Part, OptionalParameters)
|
||||
|
||||
-- TODO calcolo risultati da aggiornare con funzioni nuove
|
||||
dMRRBladeAddedFace = BladeToWasteResult.dMRR
|
||||
dCompletionPercentageAddedFace = BladeToWasteResult.dCompletionPercentage
|
||||
dQualityAddedFace = BladeToWasteResult.dQuality
|
||||
|
||||
dTimeToMachine = dTimeToMachine + BladeToWasteResult.dTimeToMachine
|
||||
-- la faccia aggiuntiva conta per 1/3
|
||||
dMRRBlade = 2/3 * dMRRBlade + 1/3 * dMRRBladeAddedFace
|
||||
dCompletionPercentage = 2/3 * dCompletionPercentage + 1/3 * dCompletionPercentageAddedFace
|
||||
dQuality = 2/3 * dQuality + 1/3 * dQualityAddedFace
|
||||
end
|
||||
|
||||
-- aggiunta lavorazioni
|
||||
local nIsApplicableCount = 0
|
||||
local bAreAllMachiningsAdded = true
|
||||
for i = 1, #Blade.Result do
|
||||
if Blade.Result[i].bIsApplicable then
|
||||
nIsApplicableCount = nIsApplicableCount + 1
|
||||
if bAddMachining then
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Blade.Result[i], AuxiliaryData)
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
Strategy.Result.sInfo = Strategy.Result.sInfo .. '\n' .. Blade.Result[i].sMessage
|
||||
end
|
||||
end
|
||||
-- TODO migliorare calcolo area lavorata; se ho il codolo ha senso l'incompleta? se incompleta con codolo faccio i cubetti??
|
||||
-- TODO settare che il codolo restituisce incompleta tranne quando è forzato
|
||||
if nIsApplicableCount > 0 then
|
||||
if dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
end
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Applicable'
|
||||
end
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
||||
Strategy.Result.dQuality = dQuality
|
||||
Strategy.Result.dTimeToMachine = dTimeToMachine
|
||||
Strategy.Result.dMRR = dMRRBlade
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0005
|
||||
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"sStrategyId": "STR0006",
|
||||
"sStrategyName": "Tenon",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dOverMatOnLength",
|
||||
"sNameNge": "OVM_LENGTH",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on tenon length",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOverMatOnRadius",
|
||||
"sNameNge": "OVM_RADIUS",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on tenon width",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "nMaxMillingPaths",
|
||||
"sNameNge": "MAX_PATHS",
|
||||
"sValue": "3",
|
||||
"sDescriptionShort": "Maximum number of milling passes",
|
||||
"sDescriptionLong": "Maximum number of milling passes. If more passes are required, pocketing is performed",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCuttingStrategy",
|
||||
"sNameNge": "EXEC_TENON_SURF",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Cutting Strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BLADE_FORCED",
|
||||
"sDescriptionShort": "Blade only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "MILL_FORCED",
|
||||
"sDescriptionShort": "Mill only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "CHAINSAW_FORCED",
|
||||
"sDescriptionShort": "ChainSaw only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "TENON_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the tenon",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
-- Strategia: STR0006
|
||||
-- Descrizione
|
||||
-- Lama + fresa tenone
|
||||
-- Feature: 50,1
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require( 'BLADETOWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0006 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetTenonStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
Machining.Milling = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
Machining.Cutting = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
local Result = {}
|
||||
Result.Milling = {}
|
||||
Result.Cutting = {}
|
||||
local ToolSearchParameters = {}
|
||||
|
||||
-- scelta automatica lavorazione. Non viene mai scelta la motosega
|
||||
if Strategy.Parameters.sCuttingStrategy == 'AUTO' then
|
||||
-- creo piano di taglio sulla testa del tenone
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idTenonCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
end
|
||||
-- se non possibile di lama si prova con fresa
|
||||
if not Machining.Cutting or Result.Cutting.sStatus ~= 'Completed' then
|
||||
Machining.bCuttingWithMill = true
|
||||
end
|
||||
-- lavorazione forzata con utensile lama
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'BLADE_FORCED' then
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idTenonCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
end
|
||||
-- lavorazione forzata con utensile fresa
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'MILL_FORCED' then
|
||||
Machining.bCuttingWithMill = true
|
||||
-- lavorazione forzata con utensile motosega
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'CHAINSAW_FORCED' then
|
||||
-- DA FARE!!
|
||||
end
|
||||
|
||||
-- === ricerca utensile per lavorare tenone ===
|
||||
Machining.Milling.bIsApplicable = false
|
||||
-- se tenone in testa oppure se di coda ma è possibile lavorare dopo separazione
|
||||
if not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit then
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dTenonLength
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Machining.Milling.ToolInfo = {}
|
||||
Machining.Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Machining.Milling.ToolInfo.nToolIndex then
|
||||
local bMachIsOk = true
|
||||
if ( Proc.FeatureInfo.vtTenonN:getZ() < 0 and TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bTop) or
|
||||
( Proc.FeatureInfo.vtTenonN:getZ() > 0 and TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bBottom) then
|
||||
-- TODO questo test va sostituito con check collisione asse Z (PreCollision)
|
||||
local dTotalLen = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dLength + TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.dPivot
|
||||
local dHorizSpace = dTotalLen * sqrt( 1 - ( Proc.FeatureInfo.vtTenonN:getZ() * Proc.FeatureInfo.vtTenonN:getZ()))
|
||||
if dHorizSpace - ( TOOLS[Machining.Milling.ToolInfo.nToolIndex].SetupInfo.dCAxisSideEncumbrance / 2) < Proc.b3Box:getDimX() then
|
||||
bMachIsOk = false
|
||||
end
|
||||
end
|
||||
if bMachIsOk then
|
||||
Machining.Milling.bIsApplicable = true
|
||||
-- calcolo passate necessarie
|
||||
if Proc.FeatureInfo.dTenonMaxDist > TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter * 0.8 then
|
||||
Machining.nMillingPathsNeeded = ceil( Proc.FeatureInfo.dTenonMaxDist / TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep)
|
||||
else
|
||||
Machining.nMillingPathsNeeded = 1
|
||||
end
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Result.Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
if Machining.Milling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Result.Milling.sStatus = 'Completed'
|
||||
else
|
||||
Result.Milling.sStatus = 'Not-Completed'
|
||||
Result.Milling.sInfo = 'Tenon not complete, left ' .. ceil( Machining.Milling.ToolInfo.dResidualDepth) .. 'mm'
|
||||
end
|
||||
-- aggiungo geometria
|
||||
Machining.Milling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Machining.Milling.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Machining.Milling.nType = MCH_MY.MILLING
|
||||
Machining.Milling.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
Machining.Milling.sDepth = min( -Machining.Milling.ToolInfo.dResidualDepth, 0)
|
||||
Machining.Milling.dStartSafetyLength = BeamData.COLL_SIC
|
||||
Machining.Milling.Steps = {}
|
||||
-- se servono passate con sovramateriale e lunghezza tenone entro il massimo materiale, si annulla lo step
|
||||
if Machining.nMillingPathsNeeded > 1 and Proc.FeatureInfo.dTenonLength < TOOLS[Machining.Milling.ToolInfo.nToolIndex].dMaxMaterial - BeamData.COLL_SIC then
|
||||
Machining.Milling.Steps.dStep = 0
|
||||
else
|
||||
Machining.Milling.Steps.dStep = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dStep
|
||||
end
|
||||
Machining.Milling.Steps.nStepType = MCH_MILL_ST.ONEWAY
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Machining.Milling.LeadIn = {}
|
||||
Machining.Milling.LeadOut = {}
|
||||
Machining.Milling.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.Milling.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.Milling.LeadIn.dTangentDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadIn.dPerpDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.Milling.LeadOut.dTangentDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadOut.dPerpDistance = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.Milling.dLengthToMachine = Proc.FeatureInfo.dTenonPathLength
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.Milling.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
Machining.Milling.bInvert = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Machining.Milling.nWorkside = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
|
||||
Machining.Milling.sUserNotes = EgtSetVal( 'MaxElev', EgtNumToString( Proc.FeatureInfo.dTenonLength, 1)) .. ';'
|
||||
|
||||
-- SCC : si tiene il motore sempre più verso l'esterno
|
||||
if Proc.AffectedFaces.bLeft then
|
||||
Machining.Milling.nSCC = MCH_SCC.ADIR_XM
|
||||
else
|
||||
Machining.Milling.nSCC = MCH_SCC.ADIR_XP
|
||||
end
|
||||
|
||||
-- passate con sovramateriale
|
||||
Machining.Milling.AuxiliaryData = {}
|
||||
Machining.Milling.AuxiliaryData.Clones = {}
|
||||
for i = Machining.nMillingPathsNeeded, 1, -1 do
|
||||
-- il primo è il passaggio più esterno
|
||||
local nIndexClones = Machining.nMillingPathsNeeded - i + 1
|
||||
-- suddivido step in base al numero passate da fare
|
||||
local dRealSideStep = floor( Proc.FeatureInfo.dTenonMaxDist / Machining.nMillingPathsNeeded)
|
||||
-- cambia solo sovrmateriale radiale
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones] = {}
|
||||
-- ultima passata con sovramateriale impostato
|
||||
if i == 1 then
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = Strategy.Parameters.dOverMatOnRadius
|
||||
else
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * dRealSideStep
|
||||
end
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
-- TODO sostituire con applicazione della lavorazione?
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
local idGeomMaxOffset = EgtCopyGlob( Proc.FeatureInfo.idAddAuxGeom, Part.idTempGroup)
|
||||
EgtOffsetCurve( idGeomMaxOffset, Machining.Milling.AuxiliaryData.Clones[1].dRadialOffset + TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2, Part.idTempGroup)
|
||||
local vtCurveStart = EgtSV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local vtCurveEnd = EgtEV( idGeomMaxOffset, GDB_ID.ROOT)
|
||||
local ptCurveStart = EgtSP( idGeomMaxOffset, GDB_ID.ROOT) + -vtCurveStart * Machining.Milling.LeadIn.dTangentDistance + ( Proc.FeatureInfo.vtTenonN ^ -vtCurveStart) * Machining.Milling.LeadIn.dPerpDistance
|
||||
local ptCurveEnd = EgtEP( idGeomMaxOffset, GDB_ID.ROOT) + vtCurveEnd * Machining.Milling.LeadOut.dTangentDistance + ( vtCurveEnd ^ Proc.FeatureInfo.vtTenonN) * Machining.Milling.LeadOut.dPerpDistance
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveStart, false, GDB_RT.GLOB)
|
||||
EgtAddCurveCompoArcTg( idGeomMaxOffset, ptCurveEnd, true, GDB_RT.GLOB)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomMaxOffset, Proc.FeatureInfo.vtTenonN, Machining.Milling.nSCC, TOOLS[Machining.Milling.ToolInfo.nToolIndex])
|
||||
if bOutOfStroke then
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
|
||||
-- tempo di svuotatura
|
||||
Result.Milling.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining.Milling, Part)
|
||||
end
|
||||
end
|
||||
|
||||
-- se cutting da fare come svuotatura, copio i dati dell'utensile scelto per lavorare il tenone
|
||||
if Machining.bCuttingWithMill and Machining.Milling.bIsApplicable then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
Machining.Cutting.ToolInfo = Machining.Milling.ToolInfo
|
||||
Result.Cutting.dMRR = Result.Milling.dMRR
|
||||
Machining.Cutting.Steps = {}
|
||||
Machining.Cutting.LeadIn = {}
|
||||
Machining.Cutting.nType = MCH_MY.POCKETING
|
||||
Machining.Cutting.nSubType = MCH_POCK_SUB.SPIRALIN
|
||||
Machining.Cutting.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Machining.Cutting.Steps.dStep = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dStep
|
||||
Machining.Cutting.Steps.dSideStep = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.Cutting.nToolIndex = Machining.Cutting.ToolInfo.nToolIndex
|
||||
Machining.Cutting.LeadIn.dTangentDistance = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Machining.Cutting.LeadIn.dElevation = TOOLS[Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Machining.Cutting.sDepth = 0
|
||||
Machining.Cutting.Geometry = {{ Strategy.idTenonCutPlane, 0}}
|
||||
Machining.Cutting.vtToolDirection = Proc.FeatureInfo.vtTenonN
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
-- tempo di svuotatura
|
||||
Result.Cutting.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining.Cutting, Part)
|
||||
end
|
||||
end
|
||||
return Machining, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetFeatureRotationIndex( Proc)
|
||||
local nVoteIndex
|
||||
|
||||
-- se fatto con testa sopra
|
||||
if TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bTop then
|
||||
if Proc.FeatureInfo.vtTenonN:getZ() < 0 then
|
||||
nVoteIndex = 2
|
||||
elseif Proc.FeatureInfo.vtTenonN:getZ() > abs( Proc.FeatureInfo.vtTenonN:getY()) then
|
||||
nVoteIndex = 4
|
||||
else
|
||||
nVoteIndex = 3
|
||||
end
|
||||
-- se fatto con testa sotto
|
||||
elseif TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bBottom then
|
||||
if Proc.FeatureInfo.vtTenonN:getZ() > 0 then
|
||||
nVoteIndex = 2
|
||||
elseif Proc.FeatureInfo.vtTenonN:getZ() < - abs( Proc.FeatureInfo.vtTenonN:getY()) then
|
||||
nVoteIndex = 4
|
||||
else
|
||||
nVoteIndex = 3
|
||||
end
|
||||
end
|
||||
|
||||
return nVoteIndex
|
||||
end
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO vedere se leggere direttamente la quality dell'utensile e mediarle nel caso di utensile doppio
|
||||
local function GetTenonMachiningResult( Proc, Result)
|
||||
local TotalResult = {}
|
||||
-- setto il risultato in base agli utensili trovati
|
||||
-- lavorazione completa
|
||||
if Strategy.Machining.Milling.bIsApplicable and Strategy.Machining.Cutting.bIsApplicable then
|
||||
TotalResult.sStatus = Result.Milling.sStatus
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
TotalResult.dMRR = ( Result.Milling.dMRR + Result.Cutting.dMRR) / 2
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Strategy.Machining.bCuttingWithMill, 'STD', 'FINE'))
|
||||
TotalResult.nFeatureRotationIndex = GetFeatureRotationIndex( Proc)
|
||||
TotalResult.dTimeToMachine = Result.Milling.dTimeToMachine + Result.Cutting.dTimeToMachine
|
||||
TotalResult.sInfo = ''
|
||||
-- lavorazione incompleta
|
||||
elseif Strategy.Machining.Cutting.bIsApplicable then
|
||||
TotalResult.sStatus = 'Not-Completed'
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 50)
|
||||
TotalResult.dMRR = Result.Cutting.dMRR
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Strategy.Machining.bCuttingWithMill, 'MILL', 'SAWBLADE'))
|
||||
TotalResult.sInfo = 'Tenon not completed'
|
||||
TotalResult.dTimeToMachine = Result.Cutting.dTimeToMachine
|
||||
-- strategia non applicabile, manca il taglio di lama sulla lunghezza del tenone
|
||||
else
|
||||
TotalResult = FeatureLib.GetStrategyResultNotApplicable( 'Error on Tenon cutting')
|
||||
end
|
||||
return TotalResult
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0006.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machining = {}
|
||||
Strategy.Result = {}
|
||||
local Results = {}
|
||||
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
-- controllo conformità offset tenone
|
||||
Strategy.Parameters.dOverMatOnRadius = EgtClamp( Strategy.Parameters.dOverMatOnRadius, -5, 5)
|
||||
Strategy.Parameters.dOverMatOnLength = EgtClamp( Strategy.Parameters.dOverMatOnLength, -5, 5)
|
||||
|
||||
-- calcolo se la lavorazione del tenone può essere spostata dopo taglio di coda
|
||||
local dLengthOnX = Proc.b3Box:getDimX()
|
||||
Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
||||
|
||||
-- aggiunta superficie di taglio sulla lunghezza del tenone
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
local ptCenterAddSurf = Proc.FeatureInfo.ptTenonCenter + ( Proc.FeatureInfo.vtTenonN * Strategy.Parameters.dOverMatOnLength)
|
||||
Strategy.idTenonCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, ptCenterAddSurf, Proc.FeatureInfo.vtTenonN, Part.b3Part, GDB_RT.GLOB)
|
||||
|
||||
Strategy.Machining, Results = GetTenonStrategy( Proc, Part)
|
||||
|
||||
Strategy.Result = GetTenonMachiningResult( Proc, Results)
|
||||
|
||||
-- applicazione delle lavorazioni
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- taglio in lunghezza sul tenone
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
OptionalParameters = {}
|
||||
|
||||
-- se cutting da fare come svuotatura
|
||||
if Strategy.Machining.bCuttingWithMill then
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting)
|
||||
|
||||
-- taglio di lama
|
||||
else
|
||||
for i = 1, #Strategy.Machining.Cutting do
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machining.Cutting[i].sStage = 'AfterTail'
|
||||
end
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- passaggio sul profilo
|
||||
if Strategy.Machining.Milling.bIsApplicable then
|
||||
-- se molti passaggi richiesti, si fa svuotatura
|
||||
-- TODO in attesa delle svuotature, si fanno passaggi senza limiti sul numero massimo. Poi togliere il FALSE nella condizione.
|
||||
if false and Strategy.Machining.nMillingPathsNeeded > Strategy.Parameters.nMaxMillingPaths then
|
||||
-- TODO. SERVONO NUOVE SVUOTATURE!!!!
|
||||
else
|
||||
|
||||
local nNearSide -- +3 = Z+, -3 = Z-
|
||||
local bShortPart = ( Part.b3Part:getDimX() < BeamData.LEN_SHORT_PART)
|
||||
if TOOLS[Strategy.Machining.Milling.nToolIndex].SetupInfo.HeadType.bTop then
|
||||
if bShortPart and Proc.FeatureInfo.vtTenonN:getX() < 0 and Proc.FeatureInfo.vtTenonN:getZ() > 0 then
|
||||
nNearSide = -3
|
||||
else
|
||||
nNearSide = 3
|
||||
end
|
||||
else
|
||||
if bShortPart and Proc.FeatureInfo.vtTenonN:getX() < 0 and Proc.FeatureInfo.vtTenonN:getZ() < 0 then
|
||||
nNearSide = 3
|
||||
else
|
||||
nNearSide = -3
|
||||
end
|
||||
end
|
||||
|
||||
BeamLib.PutStartNearestToEdge( Proc.FeatureInfo.idAddAuxGeom, Part.b3Raw, Proc.FeatureInfo.dTenonMaxDist, nNearSide)
|
||||
|
||||
-- aggiunge lavorazione
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Milling, Strategy.Machining.Milling.AuxiliaryData)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0006
|
||||
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"sStrategyId": "STR0007",
|
||||
"sStrategyName": "DoveTail Mortise",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dOverMatOnLength",
|
||||
"sNameNge": "OVM_LENGTH",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on Mortise length",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOverMatOnRadius",
|
||||
"sNameNge": "OVM_RADIUS",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on Mortise width",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "nMaxMillingPaths",
|
||||
"sNameNge": "MAX_PATHS",
|
||||
"sValue": "3",
|
||||
"sDescriptionShort": "Maximum number of milling passes",
|
||||
"sDescriptionLong": "Maximum number of milling passes. If more passes are required, pocketing is performed",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bUseDTToolOnPocketing",
|
||||
"sNameNge": "ALLOW_DT_POCKET",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Use DoveTail tool in case of pocketing",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bAntiSplint",
|
||||
"sNameNge": "ANTI_SPLINT",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Add Anti-Splint",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCuttingStrategy",
|
||||
"sNameNge": "EXEC_MORTISE_SURF",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Cutting Strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BLADE_FORCED",
|
||||
"sDescriptionShort": "Blade only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "MILL_FORCED",
|
||||
"sDescriptionShort": "Mill only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "CHAINSAW_FORCED",
|
||||
"sDescriptionShort": "ChainSaw only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sPocketingList",
|
||||
"sNameNge": "POCK_MORTISE_SURF_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the mortise cut surface",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "DOVETAIL_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the dovetail mortise",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
-- Strategia: STR0007
|
||||
-- Descrizione
|
||||
-- Mortasa a coda di rondine e mortasa frontale a coda di rondine
|
||||
-- Feature: 55/56,0
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local PreSimulationLib = require( 'PreSimulationLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0007 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetSCC( Machining)
|
||||
local nSCC
|
||||
|
||||
if Machining.vtToolDirection:getX() > 0 then
|
||||
nSCC = MCH_SCC.ADIR_XP
|
||||
else
|
||||
nSCC = MCH_SCC.ADIR_XM
|
||||
end
|
||||
|
||||
return nSCC
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function GetMortiseStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
Machining.Milling = {}
|
||||
Machining.Cutting = {}
|
||||
Machining.Pocketing = {}
|
||||
local Result = {}
|
||||
Result.Milling = {}
|
||||
Result.Cutting = {}
|
||||
Result.Pocketing = {}
|
||||
local ToolSearchParameters = {}
|
||||
|
||||
-- in caso sia una mortasa frontale, bisogna lavorare il taglio
|
||||
if Proc.FeatureInfo.bIsFrontMortise then
|
||||
-- scelta automatica lavorazione. Non viene mai scelta la motosega
|
||||
if Strategy.Parameters.sCuttingStrategy == 'AUTO' then
|
||||
-- creo piano di taglio sulla testa del tenone
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idMortiseCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
end
|
||||
-- se non possibile di lama si prova con fresa
|
||||
if not Machining.Cutting or Result.Cutting.sStatus ~= 'Completed' then
|
||||
Machining.bCuttingWithMill = true
|
||||
end
|
||||
-- lavorazione forzata con utensile lama
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'BLADE_FORCED' then
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idMortiseCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
else
|
||||
Machining.Cutting.bIsApplicable = false
|
||||
end
|
||||
-- lavorazione forzata con utensile fresa
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'MILL_FORCED' then
|
||||
Machining.bCuttingWithMill = true
|
||||
-- lavorazione forzata con utensile motosega
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'CHAINSAW_FORCED' then
|
||||
-- DA FARE!!
|
||||
end
|
||||
|
||||
-- === ricerca utensile per svuotare taglio iniziale, se taglio non possibile ===
|
||||
if Machining.bCuttingWithMill and ( not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit) then
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = 0
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Machining.Cutting.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Machining.Cutting.ToolInfo.nToolIndex then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Cutting.ToolInfo.nToolIndex
|
||||
Result.Cutting.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
Result.Cutting.sStatus = 'Completed'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- === ricerca utensile per lavorare mortasa coda di rondine ===
|
||||
Machining.Milling.bIsApplicable = false
|
||||
-- se mortasa in testa oppure se di coda ma è possibile lavorare dopo separazione
|
||||
if not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit then
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dMortiseDepth
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
ToolSearchParameters.sMillShape = 'DOVETAIL'
|
||||
Machining.Milling.ToolInfo = {}
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
Machining.Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Machining.Milling.ToolInfo.nToolIndex then
|
||||
local dToolDiam = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter
|
||||
|
||||
-- se richiesta passata antischeggia
|
||||
if Strategy.Parameters.bAntiSplint then
|
||||
Machining.AntiSplint = GetMortiseAntiSplint( Proc, Part, Machining.Milling.ToolInfo)
|
||||
end
|
||||
|
||||
Machining.Milling.bIsApplicable = true
|
||||
-- calcolo numero passate necessarie
|
||||
if Proc.FeatureInfo.dMortiseMaxDist > dToolDiam * 1.9 then
|
||||
local sSideStep = TOOLS[Machining.Milling.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.nMillingPathsNeeded = 1 + ceil( ( Proc.FeatureInfo.dMortiseMaxDist - dToolDiam * 1.9) / ( sSideStep * 2))
|
||||
-- suddivido step in base al numero passate da fare
|
||||
Machining.Milling.dRealSideStep = ( ( Proc.FeatureInfo.dMortiseMaxDist / 2) - dToolDiam) / (Machining.nMillingPathsNeeded - 1)
|
||||
else
|
||||
Machining.nMillingPathsNeeded = 1
|
||||
end
|
||||
|
||||
-- aggiungo geometria
|
||||
Machining.Milling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Machining.Milling.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Machining.Milling.nType = MCH_MY.MILLING
|
||||
Machining.Milling.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
Machining.Milling.sDepth = Strategy.Parameters.dOverMatOnLength
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Machining.Milling.LeadIn = {}
|
||||
Machining.Milling.LeadOut = {}
|
||||
Machining.Milling.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Machining.Milling.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
|
||||
local dDeltaAngledEntry = Proc.FeatureInfo.vtMortisePathStart * dToolDiam / 2
|
||||
local dDeltaAngledExit = Proc.FeatureInfo.vtMortisePathEnd * dToolDiam / 2
|
||||
|
||||
Machining.Milling.LeadIn.dTangentDistance = dToolDiam / 2 + dDeltaAngledEntry + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadIn.dPerpDistance = 0
|
||||
Machining.Milling.LeadOut.dTangentDistance = dToolDiam / 2 + dDeltaAngledExit + BeamData.COLL_SIC
|
||||
Machining.Milling.LeadOut.dPerpDistance = 0
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.Milling.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
Machining.Milling.bInvert = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Machining.Milling.nWorkside = EgtIf( TOOLS[Machining.Milling.ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT)
|
||||
|
||||
Machining.Milling.dMaxElev = Proc.FeatureInfo.dMortiseDepth
|
||||
|
||||
Machining.Milling.nSCC = GetSCC( Machining.Milling)
|
||||
|
||||
-- passate con sovramateriale
|
||||
Machining.Milling.AuxiliaryData = { Clones = {}}
|
||||
for i = Machining.nMillingPathsNeeded, 1, -1 do
|
||||
-- il primo è il passaggio più esterno
|
||||
local nIndexClones = Machining.nMillingPathsNeeded - i + 1
|
||||
-- cambia solo sovrmateriale radiale
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones] = {}
|
||||
-- ultima passata con sovramateriale impostato
|
||||
if i == 1 then
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = Strategy.Parameters.dOverMatOnRadius
|
||||
else
|
||||
-- suddivido step in base al numero passate da fare
|
||||
Machining.Milling.AuxiliaryData.Clones[nIndexClones].dRadialOffset = ( i - 1) * Machining.Milling.dRealSideStep
|
||||
end
|
||||
end
|
||||
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Milling.ToolInfo.nToolIndex
|
||||
Result.Milling.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
-- l'utensile a coda di rondine deve per forza riuscire a lavorare tutto, altrimenti errore
|
||||
if Machining.Milling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Result.Milling.sStatus = 'Completed'
|
||||
else
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
local idGeomMaxOffset = EgtCopyGlob( Proc.FeatureInfo.idAddAuxGeom, Part.idTempGroup)
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
EgtAddCurveCompoLineTg( idGeomMaxOffset, Machining.Milling.LeadIn.dTangentDistance, false)
|
||||
EgtAddCurveCompoLineTg( idGeomMaxOffset, Machining.Milling.LeadOut.dTangentDistance, true)
|
||||
EgtOffsetCurve( idGeomMaxOffset, Machining.Milling.AuxiliaryData.Clones[1].dRadialOffset + TOOLS[Machining.Milling.ToolInfo.nToolIndex].dDiameter / 2, Part.idTempGroup)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomMaxOffset, Proc.FeatureInfo.vtMortiseN, Machining.Milling.nSCC, TOOLS[Machining.Milling.ToolInfo.nToolIndex])
|
||||
if bOutOfStroke then
|
||||
Machining.Milling.bIsApplicable = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Machining, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetFeatureRotationIndex( Proc)
|
||||
local nVoteIndex
|
||||
|
||||
-- se fatto con testa sopra
|
||||
if TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bTop then
|
||||
if Proc.FeatureInfo.vtMortiseN:getZ() < 0 then
|
||||
nVoteIndex = 2
|
||||
elseif Proc.FeatureInfo.vtMortiseN:getZ() > abs( Proc.FeatureInfo.vtMortiseN:getY()) then
|
||||
nVoteIndex = 4
|
||||
else
|
||||
nVoteIndex = 3
|
||||
end
|
||||
-- se fatto con testa sotto
|
||||
elseif TOOLS[Strategy.Machining.Milling.ToolInfo.nToolIndex].SetupInfo.HeadType.bBottom then
|
||||
if Proc.FeatureInfo.vtMortiseN:getZ() > 0 then
|
||||
nVoteIndex = 2
|
||||
elseif Proc.FeatureInfo.vtMortiseN:getZ() < - abs( Proc.FeatureInfo.vtMortiseN:getY()) then
|
||||
nVoteIndex = 4
|
||||
else
|
||||
nVoteIndex = 3
|
||||
end
|
||||
end
|
||||
|
||||
return nVoteIndex
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO vedere se leggere direttamente la quality dell'utensile e mediarle nel caso di utensile doppio
|
||||
function GetMortiseMachiningResult( Proc, Result)
|
||||
local TotalResult = {}
|
||||
-- setto il risultato in base agli utensili trovati
|
||||
|
||||
-- lavorazione mortasa frontale completa
|
||||
if Strategy.Machining.Milling.bIsApplicable and Strategy.Machining.Cutting.bIsApplicable and Proc.FeatureInfo.bIsFrontMortise then
|
||||
TotalResult.sStatus = Result.Milling.sStatus
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
TotalResult.dMRR = ( Result.Milling.dMRR + Result.Cutting.dMRR) / 2
|
||||
local sQuality
|
||||
if not Strategy.Machining.bCuttingWithMill and Strategy.Machining.AntiSplint.bIsApplicable then
|
||||
sQuality = 'BEST'
|
||||
elseif Strategy.Machining.AntiSplint.bIsApplicable then
|
||||
sQuality = 'FINE'
|
||||
else
|
||||
sQuality = 'STD'
|
||||
end
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( sQuality)
|
||||
TotalResult.nFeatureRotationIndex = GetFeatureRotationIndex( Proc)
|
||||
TotalResult.sInfo = ''
|
||||
-- lavorazione mortasa completa
|
||||
elseif Strategy.Machining.Milling.bIsApplicable and not( Proc.FeatureInfo.bIsFrontMortise) then
|
||||
TotalResult.sStatus = Result.Milling.sStatus
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
TotalResult.dMRR = Result.Milling.dMRR
|
||||
local sQuality = EgtIf( Strategy.Machining.AntiSplint.bIsApplicable, 'BEST', 'STD')
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( sQuality)
|
||||
TotalResult.nFeatureRotationIndex = GetFeatureRotationIndex( Proc)
|
||||
TotalResult.sInfo = ''
|
||||
-- lavorazione incompleta
|
||||
elseif Strategy.Machining.Cutting.bIsApplicable then
|
||||
TotalResult.sStatus = 'Not-Completed'
|
||||
TotalResult.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 50)
|
||||
TotalResult.dMRR = Result.Cutting.dMRR
|
||||
TotalResult.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Strategy.Machining.bCuttingWithMill, 'MILL', 'SAWBLADE'))
|
||||
TotalResult.sInfo = 'Mortise not completed'
|
||||
-- strategia non applicabile, manca il taglio di lama sulla lunghezza del Mortise
|
||||
else
|
||||
TotalResult = FeatureLib.GetStrategyResultNotApplicable( 'Error on Mortise cutting')
|
||||
end
|
||||
return TotalResult
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function CalcTopPath( nProcId, AuxId, nAddGrpId, dAltMort, dSideAng, b3Solid)
|
||||
-- copio la curva di base
|
||||
local NewAuxId = EgtCopyGlob( AuxId, nAddGrpId)
|
||||
if not NewAuxId then return end
|
||||
-- ne allungo gli estremi
|
||||
EgtAddCurveCompoLineTg( NewAuxId, 100, false)
|
||||
EgtAddCurveCompoLineTg( NewAuxId, 100, true)
|
||||
EgtMergeCurvesInCurveCompo( NewAuxId)
|
||||
|
||||
local dOffset = dAltMort * tan( dSideAng)
|
||||
if not EgtOffsetCurveAdv( NewAuxId, dOffset) then return end
|
||||
|
||||
-- la limito entro la trave
|
||||
local refBox = Frame3d( b3Solid:getMin())
|
||||
local vtBoxDiag = b3Solid:getMax() - b3Solid:getMin()
|
||||
local nCount
|
||||
NewAuxId, nCount = EgtTrimFlatCurveWithBox( NewAuxId, refBox, vtBoxDiag, true, true, GDB_RT.GLOB)
|
||||
|
||||
-- eseguo traslazione e offset per portarla sul top
|
||||
local vtMove = EgtCurveExtrusion( AuxId, GDB_RT.GLOB) * ( dAltMort - 10 * GEO.EPS_SMALL)
|
||||
EgtMove( NewAuxId, vtMove, GDB_RT.GLOB)
|
||||
|
||||
-- se divisa in più parti, le unisco congiungendole con segmenti
|
||||
if nCount > 1 then
|
||||
if EgtGetType( NewAuxId) ~= GDB_TY.CRV_COMPO then
|
||||
NewAuxId = EgtCurveCompo( nAddGrpId, NewAuxId)
|
||||
end
|
||||
for i = 2, nCount do
|
||||
local CrvId = NewAuxId + i - 1
|
||||
local ptStart = EgtSP( CrvId)
|
||||
EgtAddCurveCompoLine( NewAuxId, ptStart)
|
||||
EgtAddCurveCompoCurve( NewAuxId, CrvId)
|
||||
end
|
||||
end
|
||||
return NewAuxId
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function GetMortiseAntiSplint( Proc, Part, ToolInfo)
|
||||
local AntiSplint = { bIsApplicable = false}
|
||||
-- se il percorso non è chiuso, aggiungo percorso e lavorazione antischeggia
|
||||
if not EgtCurveIsClosed( Proc.FeatureInfo.idAddAuxGeom) then
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
-- calcolo il percorso top mortise
|
||||
local dSideAng = TOOLS[ToolInfo.nToolIndex].dSideAngle
|
||||
local dToolDiam = TOOLS[ToolInfo.nToolIndex].dDiameter
|
||||
local vtExtr = Proc.FeatureInfo.vtMortiseN
|
||||
local nAuxId1 = CalcTopPath( Proc.id, Proc.FeatureInfo.idAddAuxGeom, nAddGrpId, Proc.FeatureInfo.dMortiseDepth, dSideAng, Part.b3Part)
|
||||
-- se esiste il percorso
|
||||
if nAuxId1 then
|
||||
-- creo percorso sulla parte alta della mortasa
|
||||
local dToolRadDelta = Proc.FeatureInfo.dMortiseDepth * tan( dSideAng)
|
||||
local dTopDiam = dToolDiam + 2 * dToolRadDelta
|
||||
-- recupero punto iniziale e finale del percorso
|
||||
local ptStart = EgtSP( nAuxId1, GDB_RT.GLOB)
|
||||
local ptEnd = EgtEP( nAuxId1, GDB_RT.GLOB)
|
||||
if ptStart and ptEnd then
|
||||
local nId1
|
||||
|
||||
-- direzione del segmento
|
||||
local vtDir = ptEnd - ptStart ;
|
||||
local dLen = vtDir:len()
|
||||
vtDir:normalize()
|
||||
-- direzioni tangenti iniziale e finale
|
||||
local vtStart = EgtSV( nAuxId1, GDB_RT.GLOB)
|
||||
local vtEnd = EgtEV( nAuxId1, GDB_RT.GLOB)
|
||||
-- angoli
|
||||
local dAngStart = acos( vtStart * vtDir)
|
||||
local dAngEnd = acos( vtEnd * vtDir)
|
||||
local dMaxAng = min( 30, dAngStart, dAngEnd)
|
||||
if dLen < dTopDiam then
|
||||
dMaxAng = min( dMaxAng, asin( dLen / dTopDiam))
|
||||
end
|
||||
local vtTg = vtDir ; vtTg:rotate( vtExtr, -dMaxAng)
|
||||
-- creo l'arco
|
||||
nId1 = EgtArc2PV( nAddGrpId, ptStart, ptEnd, vtTg, GDB_RT.GLOB)
|
||||
|
||||
if not nId1 then
|
||||
local sErr = 'Wrong geometry : Error on DtMortise '
|
||||
EgtOutLog( sErr)
|
||||
return AntiSplint
|
||||
end
|
||||
EgtModifyCurveExtrusion( nId1, vtExtr, GDB_RT.GLOB)
|
||||
|
||||
AntiSplint.nToolIndex = ToolInfo.nToolIndex
|
||||
AntiSplint.nType = MCH_MY.MILLING
|
||||
AntiSplint.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
AntiSplint.LeadIn = {}
|
||||
AntiSplint.LeadOut = {}
|
||||
AntiSplint.LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
AntiSplint.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
AntiSplint.LeadIn.dTangentDistance = TOOLS[ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
AntiSplint.LeadIn.dPerpDistance = 0
|
||||
AntiSplint.LeadOut.dTangentDistance = TOOLS[ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
AntiSplint.LeadOut.dPerpDistance = 0
|
||||
|
||||
AntiSplint.dRadialOffset = dToolRadDelta - 1
|
||||
AntiSplint.sDepth = Proc.FeatureInfo.dMortiseDepth - Strategy.Parameters.dOverMatOnLength
|
||||
AntiSplint.Geometry = {{ nId1, -1}}
|
||||
AntiSplint.bInvert = EgtIf( TOOLS[ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
AntiSplint.nWorkside = EgtIf( TOOLS[ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.LEFT, MCH_MILL_WS.RIGHT)
|
||||
AntiSplint.dMaxElev = Proc.FeatureInfo.dMortiseDepth
|
||||
AntiSplint.nSCC = GetSCC( AntiSplint)
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
AntiSplint.sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- test finecorsa sulla passata più esterna: se extracorsa, la lavorazione non è fattibile
|
||||
local idGeomOffset = EgtCopyGlob( nId1, Part.idTempGroup)
|
||||
EgtOffsetCurve( idGeomOffset, EgtIf( AntiSplint.bInvert, -TOOLS[ToolInfo.nToolIndex].dDiameter / 2, TOOLS[ToolInfo.nToolIndex].dDiameter / 2), Part.idTempGroup)
|
||||
-- trasformo arco in una curva compo per poi allungarla in direzione tangente
|
||||
-- TODO funzione per allungare il percorso??????
|
||||
idGeomOffset = EgtCurveCompo( Part.idTempGroup, idGeomOffset)
|
||||
EgtAddCurveCompoLineTg( idGeomOffset, AntiSplint.LeadIn.dTangentDistance, false)
|
||||
EgtAddCurveCompoLineTg( idGeomOffset, AntiSplint.LeadOut.dTangentDistance, true)
|
||||
local bOutOfStroke = PreSimulationLib.CheckOutOfStrokeFromGeometry( idGeomOffset, Proc.FeatureInfo.vtMortiseN, AntiSplint.nSCC, TOOLS[ToolInfo.nToolIndex])
|
||||
-- se soddisfa tutti i requisiti, posso applicare
|
||||
if bOutOfStroke then
|
||||
AntiSplint.bIsApplicable = false
|
||||
else
|
||||
AntiSplint.bIsApplicable = true
|
||||
end
|
||||
|
||||
else
|
||||
local sErr = 'Wrong geometry : Error on DtMortise ' .. tostring( Proc.id)
|
||||
EgtOutLog( sErr)
|
||||
end
|
||||
else
|
||||
local sErr = 'Wrong geometry : Error on DtMortise ' .. tostring( Proc.id)
|
||||
EgtOutLog( sErr)
|
||||
end
|
||||
end
|
||||
return AntiSplint
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0007.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machining = {}
|
||||
Strategy.Result = {}
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
local Results = {}
|
||||
|
||||
-- controllo conformità offset mortasa
|
||||
Strategy.Parameters.dOverMatOnRadius = EgtClamp( Strategy.Parameters.dOverMatOnRadius, -5, 5)
|
||||
Strategy.Parameters.dOverMatOnLength = EgtClamp( Strategy.Parameters.dOverMatOnLength, -2, 2)
|
||||
|
||||
-- calcolo se la lavorazione della mortasa può essere spostata dopo taglio di coda
|
||||
local dLengthOnX = Proc.b3Box:getDimX()
|
||||
Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
||||
|
||||
-- se mortasa frontale, verifico che esista faccia di taglio
|
||||
if Proc.FeatureInfo.bIsFrontMortise then
|
||||
-- verifico esista la faccia di taglio
|
||||
local ptCutC, vtCutN = EgtSurfTmFacetCenter( Proc.id, 1, GDB_ID.ROOT)
|
||||
if ptCutC and vtCutN and AreSameVectorApprox( Proc.FeatureInfo.vtMortiseN, vtCutN) then
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
Strategy.idMortiseCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, ptCutC, vtCutN, Part.b3Part, GDB_RT.GLOB)
|
||||
end
|
||||
end
|
||||
|
||||
Strategy.Machining, Results = GetMortiseStrategy( Proc, Part)
|
||||
|
||||
Strategy.Result = GetMortiseMachiningResult( Proc, Results)
|
||||
|
||||
|
||||
-- applicazione delle lavorazioni
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- taglio in lunghezza sul tenone
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
OptionalParameters = {}
|
||||
|
||||
-- se cutting da fare come svuotatura
|
||||
if Strategy.Machining.bCuttingWithMill then
|
||||
Strategy.Machining.Cutting.Steps = {}
|
||||
Strategy.Machining.Cutting.LeadIn = {}
|
||||
Strategy.Machining.Cutting.nType = MCH_MY.POCKETING
|
||||
Strategy.Machining.Cutting.nSubType = MCH_POCK_SUB.SPIRALIN
|
||||
Strategy.Machining.Cutting.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Strategy.Machining.Cutting.Steps.dStep = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dStep
|
||||
Strategy.Machining.Cutting.Steps.dSideStep = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dSideStep
|
||||
Strategy.Machining.Cutting.nToolIndex = Strategy.Machining.Cutting.ToolInfo.nToolIndex
|
||||
Strategy.Machining.Cutting.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Strategy.Machining.Cutting.LeadIn.dElevation = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Strategy.Machining.Cutting.sDepth = 0
|
||||
Strategy.Machining.Cutting.Geometry = {{ Strategy.idMortiseCutPlane, 0}}
|
||||
Strategy.Machining.Cutting.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machining.Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting)
|
||||
|
||||
-- taglio di lama
|
||||
else
|
||||
for i = 1, #Strategy.Machining.Cutting do
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machining.Cutting[i].sStage = 'AfterTail'
|
||||
end
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se richiesta passata antischeggia
|
||||
if Strategy.Machining.AntiSplint.bIsApplicable then
|
||||
bAreAllMachiningsAdded = bAreAllMachiningsAdded and MachiningLib.AddMachinings( Proc, Strategy.Machining.AntiSplint)
|
||||
end
|
||||
|
||||
-- passaggio sul profilo
|
||||
if Strategy.Machining.Milling.bIsApplicable then
|
||||
-- se molti passaggi richiesti, si fa svuotatura
|
||||
-- TODO in attesa delle svuotature, si fanno passaggi senza limiti sul numero massimo. Poi togliere il FALSE nella condizione.
|
||||
if false and Strategy.Machining.nMillingPathsNeeded > Strategy.Parameters.nMaxMillingPaths then
|
||||
-- TODO. SERVONO NUOVE SVUOTATURE!!!!
|
||||
else
|
||||
-- aggiunge lavorazione
|
||||
bAreAllMachiningsAdded = bAreAllMachiningsAdded and MachiningLib.AddMachinings( Proc, Strategy.Machining.Milling, Strategy.Machining.Milling.AuxiliaryData)
|
||||
end
|
||||
end
|
||||
end
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0007
|
||||
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"sStrategyId": "STR0008",
|
||||
"sStrategyName": "Mortise",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dOverMatOnLength",
|
||||
"sNameNge": "OVM_LENGTH",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on mortise length",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOverMatOnRadius",
|
||||
"sNameNge": "OVM_RADIUS",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial on mortise width",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCuttingStrategy",
|
||||
"sNameNge": "EXEC_TENON_SURF",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Cutting Strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BLADE_FORCED",
|
||||
"sDescriptionShort": "Blade only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "MILL_FORCED",
|
||||
"sDescriptionShort": "Mill only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "CHAINSAW_FORCED",
|
||||
"sDescriptionShort": "ChainSaw only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sPocketingList",
|
||||
"sNameNge": "POCK_MORTISE_SURF_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the mortise cut surface",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "MORTISE_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the mortise",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
-- Strategia: STR0008
|
||||
-- Descrizione
|
||||
-- Svuotatura tasca
|
||||
-- Feature tipo Mortise (con raggio)
|
||||
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0008 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function IsTopologyOk( Proc)
|
||||
if Proc.Topology.sName == 'Pocket-Round' or
|
||||
Proc.Topology.sName == 'Pocket-Round-Through' or
|
||||
Proc.Topology.sName == 'Pocket-Round-Front' then
|
||||
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO vedere se leggere direttamente la quality dell'utensile e mediarle nel caso di utensile doppio
|
||||
local function GetBestPocketingStrategy( Proc, Part)
|
||||
local Machining = { Cutting = {}, Pocketing = {}}
|
||||
local Result = { Cutting = {}, Pocketing = {}}
|
||||
local ToolSearchParameters = {}
|
||||
|
||||
Machining.sTypeMachining = 'None' -- Bottom\ Side1\ Side2\ Side1-Side2\ None
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'MILL')
|
||||
|
||||
-- in caso sia una mortasa frontale, bisogna lavorare il taglio
|
||||
if Proc.FeatureInfo.bIsFrontMortise then
|
||||
-- scelta automatica lavorazione. Non viene mai scelta la motosega
|
||||
if Strategy.Parameters.sCuttingStrategy == 'AUTO' then
|
||||
-- creo piano di taglio sulla testa del tenone
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idMortiseCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
end
|
||||
-- se non possibile di lama si prova con fresa
|
||||
if not Machining.Cutting or #Machining.Cutting == 0 then
|
||||
Machining.bCuttingWithMill = true
|
||||
end
|
||||
-- lavorazione forzata con utensile lama
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'BLADE_FORCED' then
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining.Cutting, Result.Cutting = BladeToWaste.Make( Strategy.idMortiseCutPlane, Part, OptionalParameters)
|
||||
-- se presente almeno una lavorazione e completo, il taglio è applicabile
|
||||
if #Machining.Cutting > 0 and Result.Cutting.sStatus == 'Completed' then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
else
|
||||
Machining.Cutting.bIsApplicable = false
|
||||
end
|
||||
-- lavorazione forzata con utensile fresa
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'MILL_FORCED' then
|
||||
Machining.bCuttingWithMill = true
|
||||
-- lavorazione forzata con utensile motosega
|
||||
elseif Strategy.Parameters.sCuttingStrategy == 'CHAINSAW_FORCED' then
|
||||
-- DA FARE!!
|
||||
end
|
||||
|
||||
-- === ricerca utensile per svuotare taglio iniziale, se taglio non possibile ===
|
||||
if Machining.bCuttingWithMill then
|
||||
-- se può essere fatto di fresa
|
||||
if not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit then
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = 0
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
Machining.Cutting.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if Machining.Cutting.ToolInfo.nToolIndex then
|
||||
Machining.Cutting.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.Cutting.ToolInfo.nToolIndex
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
end
|
||||
-- alterimenti esco subito
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Applicable'
|
||||
Strategy.Result.dCompletionIndex = 0
|
||||
Strategy.Result.dMRR = 0
|
||||
Strategy.Result.dQuality = 0
|
||||
Strategy.Result.sInfo = 'Mill not found'
|
||||
return Machining
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- ===== RICERCA UTENSILE =====
|
||||
-- cerco utensile per lavorare faccia Bottom
|
||||
local Milling = {}
|
||||
Milling.bIsApplicable = false
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.dMaxToolDiameter = Proc.FeatureInfo.dMortiseMinRadius * 2
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dMortiseDepth + EgtIf( Proc.Topology.sName == 'Pocket-Round-Through', BeamData.CUT_EXTRA, 0)
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Pocketing')
|
||||
Milling.ToolInfo = {}
|
||||
-- si cerca prima utensile per lavorare in accordo con normale mortasa
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
Milling.idFaceToMachine = 0 -- ATTENZIONE: Per convenzione, la faccia di fondo della mortasa ha sempre indice 0
|
||||
Milling.idProc = Proc.id
|
||||
Milling.vtFaceNormal = Proc.FeatureInfo.vtMortiseN
|
||||
Milling.dElevation = Proc.FeatureInfo.dMortiseDepth
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
Milling.bIsApplicable = true
|
||||
end
|
||||
table.insert( Machining.Pocketing, Milling)
|
||||
|
||||
-- si cerca utensile che lavora dal lato opposto
|
||||
Milling = {}
|
||||
Milling.bIsApplicable = false
|
||||
if Proc.Topology.sName == 'Pocket-Round-Through' then
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.dMaxToolDiameter = Proc.FeatureInfo.dMortiseMinRadius * 2
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dMortiseDepth + BeamData.CUT_EXTRA
|
||||
ToolSearchParameters.vtToolDirection = -Proc.FeatureInfo.vtMortiseN
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Pocketing')
|
||||
Milling.ToolInfo = {}
|
||||
-- si cerca prima utensile per lavorare in accordo con normale mortasa
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
Milling.idFaceToMachine = 0 -- ATTENZIONE: Per convenzione, la faccia di fondo della mortasa ha sempre indice 0
|
||||
Milling.idProc = Proc.id
|
||||
Milling.vtFaceNormal = -Proc.FeatureInfo.vtMortiseN
|
||||
Milling.bToolInvert = true
|
||||
Milling.dElevation = Proc.FeatureInfo.dMortiseDepth
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
Milling.bIsApplicable = true
|
||||
end
|
||||
end
|
||||
table.insert( Machining.Pocketing, Milling)
|
||||
|
||||
|
||||
-- tipo di lavorazione
|
||||
-- solo svuotatura diretta come normale mortasa, completa
|
||||
if Machining.Pocketing[1].bIsApplicable and Machining.Pocketing[1].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
if Proc.Topology.sName == 'Pocket-Round-Through' then
|
||||
Machining.sTypeMachining = 'Side1'
|
||||
Machining.Pocketing[1].sDepth = BeamData.CUT_EXTRA
|
||||
else
|
||||
Machining.sTypeMachining = 'Bottom'
|
||||
Machining.Pocketing[1].sDepth = -Strategy.Parameters.dOverMatOnLength
|
||||
end
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining.Pocketing[1].ToolInfo)
|
||||
Machining.dResidual = 0
|
||||
Machining.Pocketing[2].bIsApplicable = false
|
||||
-- solo svuotatura diretta opposta alla normale mortasa, completa
|
||||
elseif Machining.Pocketing[2].bIsApplicable and Machining.Pocketing[2].ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL then
|
||||
Machining.sTypeMachining = 'Side2'
|
||||
Machining.dResidual = 0
|
||||
Machining.Pocketing[2].sDepth = Proc.FeatureInfo.dMortiseDepth + BeamData.CUT_EXTRA
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining.Pocketing[2].ToolInfo)
|
||||
Machining.Pocketing[1].bIsApplicable = false
|
||||
-- solo svuotatura diretta come normale mortasa, incompleta
|
||||
elseif Machining.Pocketing[1].bIsApplicable and not Machining.Pocketing[2].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Side1'
|
||||
Machining.dResidual = Machining.Pocketing[1].ToolInfo.dResidualDepth
|
||||
Machining.Pocketing[1].sDepth = -Machining.dResidual
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining.Pocketing[1].ToolInfo)
|
||||
-- solo svuotatura diretta come normale mortasa, incompleta
|
||||
elseif Machining.Pocketing[2].bIsApplicable and not Machining.Pocketing[1].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Side2'
|
||||
Machining.dResidual = Machining.Pocketing[2].ToolInfo.dResidualDepth
|
||||
Machining.Pocketing[2].sDepth = Proc.FeatureInfo.dMortiseDepth - Machining.dResidual
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Machining.Pocketing[2].ToolInfo)
|
||||
-- lavorazione da entrambi i lati
|
||||
elseif Machining.Pocketing[1].bIsApplicable and Machining.Pocketing[2].bIsApplicable then
|
||||
Machining.sTypeMachining = 'Side1-Side2'
|
||||
local dResidualMach = Machining.Pocketing[1].ToolInfo.dResidualDepth + Machining.Pocketing[2].ToolInfo.dResidualDepth - Proc.FeatureInfo.dMortiseDepth
|
||||
Machining.dResidual = max( 0, dResidualMach)
|
||||
-- se lavorazione non copmpleta, si entra il massimio possibile
|
||||
if dResidualMach > 0 then
|
||||
Machining.Pocketing[1].sDepth = -Machining.Pocketing[1].ToolInfo.dResidualDepth
|
||||
Machining.Pocketing[2].sDepth = Proc.FeatureInfo.dMortiseDepth - Machining.Pocketing[2].ToolInfo.dResidualDepth
|
||||
else
|
||||
Machining.Pocketing[1].sDepth = -Machining.Pocketing[1].ToolInfo.dResidualDepth + dResidualMach/2 + BeamData.CUT_EXTRA_MIN
|
||||
Machining.Pocketing[2].sDepth = Proc.FeatureInfo.dMortiseDepth - ( Machining.Pocketing[2].ToolInfo.dResidualDepth - dResidualMach/2 - BeamData.CUT_EXTRA_MIN)
|
||||
end
|
||||
Strategy.Result.dMRR = min( MachiningLib.GetToolMRR( Machining.Pocketing[1].ToolInfo), MachiningLib.GetToolMRR( Machining.Pocketing[2].ToolInfo))
|
||||
-- altrimenti non applicabile
|
||||
else
|
||||
-- TODO per feature frontale, ha senso voler applicare solo il taglio e non la lavorazione della mortasatura? Adesso non fa nulla
|
||||
Strategy.Result.sStatus = 'Not-Applicable'
|
||||
Strategy.Result.dCompletionIndex = 0
|
||||
Strategy.Result.dMRR = 0
|
||||
Strategy.Result.dQuality = 0
|
||||
Strategy.Result.sInfo = 'Mill not found'
|
||||
return Machining
|
||||
end
|
||||
|
||||
-- se completo
|
||||
if Machining.dResidual < 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionPercentage = 100
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
Strategy.Result.sInfo = 'Mortise not complete, left ' .. ceil( Machining.dResidual) .. 'mm'
|
||||
Strategy.Result.dCompletionPercentage = ( 1 - Machining.dResidual / Proc.FeatureInfo.dMortiseDepth) * 100
|
||||
end
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Strategy.Result.dCompletionPercentage)
|
||||
|
||||
return Machining
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0008.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machining = {}
|
||||
Strategy.Result = {}
|
||||
|
||||
if not IsTopologyOk( Proc) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not implemented'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
local Pocketing = {}
|
||||
|
||||
-- controllo conformità offset mortasa
|
||||
Strategy.Parameters.dOverMatOnRadius = EgtClamp( Strategy.Parameters.dOverMatOnRadius, -5, 5)
|
||||
Strategy.Parameters.dOverMatOnLength = EgtClamp( Strategy.Parameters.dOverMatOnLength, -2, 2)
|
||||
|
||||
-- calcolo se la lavorazione della mortasa può essere spostata dopo taglio di coda
|
||||
local dLengthOnX = Proc.b3Box:getDimX()
|
||||
Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
||||
|
||||
-- se mortasa frontale, verifico che esista faccia di taglio
|
||||
if Proc.FeatureInfo.bIsFrontMortise then
|
||||
-- verifico esista la faccia di taglio
|
||||
local ptCutC, vtCutN = EgtSurfTmFacetCenter( Proc.id, 1, GDB_ID.ROOT)
|
||||
if ptCutC and vtCutN and AreSameVectorApprox( Proc.FeatureInfo.vtMortiseN, vtCutN) then
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
Strategy.idMortiseCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, ptCutC, vtCutN, Part.b3Part, GDB_RT.GLOB)
|
||||
end
|
||||
end
|
||||
|
||||
Strategy.Machining = GetBestPocketingStrategy( Proc, Part)
|
||||
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- se mortasa frontale si fa taglio di lama
|
||||
if Proc.FeatureInfo.bIsFrontMortise then
|
||||
-- taglio in lunghezza sulla faccia frontale
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
OptionalParameters = {}
|
||||
|
||||
-- se cutting da fare come svuotatura
|
||||
if Strategy.Machining.bCuttingWithMill then
|
||||
Strategy.Machining.Cutting.Steps = {}
|
||||
Strategy.Machining.Cutting.LeadIn = {}
|
||||
Strategy.Machining.Cutting.nType = MCH_MY.POCKETING
|
||||
Strategy.Machining.Cutting.nSubType = MCH_POCK_SUB.SPIRALIN
|
||||
Strategy.Machining.Cutting.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Strategy.Machining.Cutting.Steps.dStep = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dStep
|
||||
Strategy.Machining.Cutting.Steps.dSideStep = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dSideStep
|
||||
Strategy.Machining.Cutting.nToolIndex = Strategy.Machining.Cutting.ToolInfo.nToolIndex
|
||||
Strategy.Machining.Cutting.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Strategy.Machining.Cutting.LeadIn.dElevation = TOOLS[Strategy.Machining.Cutting.ToolInfo.nToolIndex].dDiameter/2
|
||||
Strategy.Machining.Cutting.sDepth = 0
|
||||
Strategy.Machining.Cutting.Geometry = {{ Strategy.idMortiseCutPlane, 0}}
|
||||
Strategy.Machining.Cutting.vtToolDirection = Proc.FeatureInfo.vtMortiseN
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machining.Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting)
|
||||
|
||||
-- taglio di lama
|
||||
else
|
||||
for i = 1, #Strategy.Machining.Cutting do
|
||||
if Strategy.Machining.Cutting.bIsApplicable then
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Machining.Cutting[i].sStage = 'AfterTail'
|
||||
end
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining.Cutting[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- si applicano le lavorazioni di svuotatura
|
||||
for i = 1, #Strategy.Machining.Pocketing do
|
||||
if Strategy.Machining.Pocketing[i].bIsApplicable then
|
||||
Pocketing = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING)
|
||||
Pocketing.nSubType = MCH_POCK_SUB.SPIRALOUT
|
||||
Pocketing.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Pocketing.Steps.dStep = TOOLS[Strategy.Machining.Pocketing[i].ToolInfo.nToolIndex].dStep
|
||||
Pocketing.Steps.dSideStep = TOOLS[Strategy.Machining.Pocketing[i].ToolInfo.nToolIndex].dSideStep
|
||||
Pocketing.nToolIndex = Strategy.Machining.Pocketing[i].ToolInfo.nToolIndex
|
||||
Pocketing.LeadIn.dTangentDistance = TOOLS[Strategy.Machining.Pocketing[i].ToolInfo.nToolIndex].dDiameter/2
|
||||
Pocketing.LeadIn.dElevation = TOOLS[Strategy.Machining.Pocketing[i].ToolInfo.nToolIndex].dDiameter/2
|
||||
Pocketing.sDepth = Strategy.Machining.Pocketing[i].sDepth
|
||||
Pocketing.dRadialOffset = Strategy.Parameters.dOverMatOnRadius
|
||||
Pocketing.bToolInvert = Strategy.Machining.Pocketing[i].bToolInvert
|
||||
|
||||
if Proc.FeatureInfo.bIsFrontMortise then
|
||||
Pocketing.dMaxElev = Proc.FeatureInfo.dMortiseDepth
|
||||
end
|
||||
-- se feature passante, si applica la lavorazione alla curva
|
||||
if Proc.Topology.sName == 'Pocket-Round-Through' then
|
||||
Pocketing.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
else
|
||||
Pocketing.Geometry = {{ Strategy.Machining.Pocketing[i].idProc, Strategy.Machining.Pocketing[i].idFaceToMachine}}
|
||||
end
|
||||
Pocketing.vtToolDirection = Strategy.Machining.Pocketing[i].vtFaceNormal
|
||||
|
||||
-- se è aperta sulla coda, dico che deve essere fatta dopo la separazione
|
||||
if Proc.AffectedFaces.bLeft then
|
||||
Pocketing.sStage = 'AfterTail'
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Pocketing)
|
||||
end
|
||||
end
|
||||
else
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0008
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"sStrategyId": "STR0009",
|
||||
"sStrategyName": "ScarfJoint",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dDepthChamfer",
|
||||
"sNameNge": "DEPTH_CHAMFER",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Depth Chamfer",
|
||||
"sDescriptionLong": "Depth of the V-Mill to execute chamfers on cut-edges",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bAntiSplint",
|
||||
"sNameNge": "ANTISPLINT",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Use Anti-Splint strategy",
|
||||
"sDescriptionLong": "The strategy will apply blade cuts on corner to avoid wood splint",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "PROFILE_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the profile",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
-- Strategia: STR0009
|
||||
-- Descrizione
|
||||
-- Feature tipo ScarfJoint
|
||||
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require( 'BLADETOWASTE')
|
||||
local FaceByMill = require( 'FACEBYMILL')
|
||||
local FaceByBlade = require( 'FACEBYBLADE')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0009 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetFacesIdOrder( Proc, Part)
|
||||
local Faces = {}
|
||||
if Proc.nFct == 5 then
|
||||
-- carico gli id delle facce
|
||||
for i = 1, Proc.nFct do
|
||||
Faces[#Faces + 1] = BeamLib.TableCopyDeep( Proc.Faces[i])
|
||||
end
|
||||
elseif Proc.nFct == 4 then
|
||||
local vtN1 = Proc.Faces[1].vtN
|
||||
local vtN2 = Proc.Faces[2].vtN
|
||||
local nIndex = EgtIf( abs( vtN1:getX()) > abs( vtN2:getX()), 1, 2)
|
||||
for i = nIndex, Proc.nFct do
|
||||
Faces[#Faces + 1] = BeamLib.TableCopyDeep( Proc.Faces[i])
|
||||
end
|
||||
-- TODO manca il caso in cui mancano facce 4 e 5
|
||||
else -- Proc.nFct == 3
|
||||
for i = 2, Proc.nFct do
|
||||
Faces[#Faces + 1] = BeamLib.TableCopyDeep( Proc.Faces[i])
|
||||
end
|
||||
end
|
||||
|
||||
return Faces
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetEdgeToMachine( ClosingFace, idBottomFace)
|
||||
local EdgeToMachine
|
||||
|
||||
for i = 1, #ClosingFace.Edges do
|
||||
if ClosingFace.Edges[i].idAdjacentFace == idBottomFace then
|
||||
EdgeToMachine = ClosingFace.Edges[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return EdgeToMachine
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetScarfJointStrategy( Proc, Part)
|
||||
-- ordino le facce in base al loro numero e al parallelismo delle due facce principali
|
||||
-- faccia 0: superficie tappo (*potrebbe non esserci)
|
||||
-- faccia 1: superficie principale di fondo
|
||||
-- faccia 2: superficie opposta alla faccia 1
|
||||
-- faccia 3: superficie principale superiore
|
||||
-- faccia 4: superficie di testa (*potrebbe non esserci)
|
||||
-- creo una tabella unica contenente tutte le lavorazioni
|
||||
local Result = {}
|
||||
local Cutting = { Machinings = {}, Result = {}}
|
||||
local AntiSplints = {}
|
||||
local Pocketing = {}
|
||||
|
||||
Result.dTimeToMachine = 0
|
||||
local Faces = GetFacesIdOrder( Proc)
|
||||
-- taglio su faccia 4
|
||||
if Faces[4] and Faces[4].vtN then
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
-- TODO la nuova faccia creata sulla 4 può tagliare faccia 1. In caso tagliasse faccia 1, bisogna calcolare i cubetti con 2 facce
|
||||
Strategy.idFeatureCutPlane = EgtSurfTmPlaneInBBox( nAddGrpId, Faces[4].ptCenter, Faces[4].vtN, Part.b3Part, GDB_RT.GLOB)
|
||||
Cutting.Machinings, Cutting.Result = BladeToWaste.Make( Strategy.idFeatureCutPlane, Part)
|
||||
if Cutting.Result.sStatus == 'Completed' then
|
||||
Cutting.Machinings.bIsApplicable = true
|
||||
end
|
||||
end
|
||||
|
||||
-- antischeggia facce 1 e 3
|
||||
local bAreAllAntisplintsApplicable = true
|
||||
if Strategy.Parameters.bAntiSplint then
|
||||
AntiSplints = AntiSplintOnFace.Make( Proc, Part, Faces[2])
|
||||
for k = 1, #AntiSplints do
|
||||
if not AntiSplints[k].bIsApplicable then
|
||||
bAreAllAntisplintsApplicable = false
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- svuotatura faccia 2
|
||||
if Faces[2] then
|
||||
local frPock, dL, dW = EgtSurfTmFacetMinAreaRectangle( Proc.id, Faces[2].id, GDB_ID.ROOT)
|
||||
local ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.vtToolDirection = Faces[2].vtN
|
||||
ToolSearchParameters.dElevation = abs( ( Faces[2].ptCenter - Faces[4].ptCenter) * Faces[2].vtN)
|
||||
ToolSearchParameters.dMaxToolDiameter = min( dL, dW)
|
||||
ToolSearchParameters.ToolInfo = {}
|
||||
ToolSearchParameters.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if ToolSearchParameters.ToolInfo.nToolIndex then
|
||||
local Machining = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING)
|
||||
Machining.Geometry = {{ Proc.id, Faces[2].id}}
|
||||
Machining.dElevation = ToolSearchParameters.dElevation
|
||||
Machining.dMaxElev = Machining.dElevation
|
||||
Machining.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
Machining.nSubType = MCH_POCK_SUB.SPIRALIN
|
||||
Machining.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Machining.Steps.dStep = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dStep
|
||||
Machining.Steps.dSideStep = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.nToolIndex = ToolSearchParameters.ToolInfo.nToolIndex
|
||||
Machining.LeadIn.dTangentDistance = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dDiameter / 2
|
||||
Machining.LeadIn.dElevation = TOOLS[ToolSearchParameters.ToolInfo.nToolIndex].dDiameter / 2
|
||||
Machining.sDepth = 0
|
||||
Machining.dResidualDepth = ToolSearchParameters.ToolInfo.dResidualDepth
|
||||
-- TODO vedere se questo parametro con svuotature nuove si può rimuovere
|
||||
Machining.dOpenMinSafe = Strategy.Parameters.dOpenMinSafe
|
||||
Machining.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
Result.dTimeToMachine = Result.dTimeToMachine + Machining.dTimeToMachine
|
||||
table.insert( Pocketing, Machining)
|
||||
Pocketing.bIsApplicable = true
|
||||
-- se non sono stati fatti i passaggi antischeggia si verifica che le facce siano a 90°, altrimenti serve passaggio con fresa
|
||||
if not Strategy.Parameters.bAntiSplint or not bAreAllAntisplintsApplicable then
|
||||
local dAngleBetweenFaces = Proc.AdjacencyMatrix[1][2] or 0
|
||||
-- si fa passaggio con fresa
|
||||
if dAngleBetweenFaces > -90 then
|
||||
local EdgeToMachine = GetEdgeToMachine( Faces[1], Faces[2].id)
|
||||
local CuttingClosingFace = FaceByBlade.Make( Proc, Part, Faces[1], EdgeToMachine)
|
||||
if CuttingClosingFace.bIsApplicable then
|
||||
table.insert( AntiSplints, CuttingClosingFace)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se manca taglio principale, feature non eseguibile
|
||||
if not Cutting.Machinings.bIsApplicable then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. Strategy.sName .. ' not applicable'
|
||||
EgtOutLog( sErr)
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
else
|
||||
local dCompletionPercentage = 100
|
||||
-- completa se svuotatura eseguita e antisplit eseguiti (o non richiesti)
|
||||
if Pocketing.bIsApplicable and ( bAreAllAntisplintsApplicable or not Strategy.Parameters.bAntiSplint) then
|
||||
Result.sStatus = 'Completed'
|
||||
if bAreAllAntisplintsApplicable then
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
else
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
||||
end
|
||||
-- altrimenti non completa
|
||||
else
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'STD')
|
||||
Result.sStatus = 'Not-Completed'
|
||||
-- se fa solo svuotatura
|
||||
if Pocketing.bIsApplicable then
|
||||
dCompletionPercentage = 90
|
||||
Result.sInfo = 'Anti-Split not executed'
|
||||
elseif Strategy.Parameters.bAntiSplint and bAreAllAntisplintsApplicable then
|
||||
dCompletionPercentage = 75
|
||||
Result.sInfo = 'Pocketing not executed'
|
||||
else
|
||||
dCompletionPercentage = 50
|
||||
Result.sInfo = 'Only the cut has been executed'
|
||||
end
|
||||
end
|
||||
|
||||
Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
||||
end
|
||||
|
||||
-- creo una tabella unica contenente tutte le lavorazioni
|
||||
local Machinings = {}
|
||||
EgtJoinTables( Machinings, Cutting.Machinings)
|
||||
EgtJoinTables( Machinings, AntiSplints)
|
||||
EgtJoinTables( Machinings, Pocketing)
|
||||
|
||||
return Machinings, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0009.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machinings = {}
|
||||
Strategy.Result = {}
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
-- controlli preliminari
|
||||
if Proc.nFct < 3 or Proc.nFct > 5 then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not applicable'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
Strategy.Machinings, Strategy.Result = GetScarfJointStrategy( Proc, Part)
|
||||
|
||||
-- aggiunta lavorazioni
|
||||
if #Strategy.Machinings > 0 then
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #Strategy.Machinings do
|
||||
if Proc.AffectedFaces.bLeft then
|
||||
Strategy.Machinings[j].sStage = 'AfterTail'
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machinings[j])
|
||||
end
|
||||
end
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
end
|
||||
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0009
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"sStrategyId": "STR0010",
|
||||
"sStrategyName": "Milling",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "bAntiSplintWithBlade",
|
||||
"sNameNge": "ANTISPLINT_BLADE",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Antisplint with blade",
|
||||
"sDescriptionLong": "Use the blade as antisplint in case the geometry is not through",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dExtendAfterTail",
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bFinishWithMill",
|
||||
"sNameNge": "ALLOW_FINISH_MILL",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Clean radius with mill",
|
||||
"sDescriptionLong": "Clean radius with mill",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMillingOffsetFromSide",
|
||||
"sNameNge": "MILLING_OFFSET_SIDE",
|
||||
"sValue": "1",
|
||||
"sDescriptionShort": "Milling offset from side",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCanDamageNextPiece",
|
||||
"sNameNge": "DAMAGE_NEXT_PIECE",
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Damage next piece",
|
||||
"sDescriptionLong": "This option allows you to decide how to consider the next piece in the bar. The software calculates specifics LeadIn/out to respect the parameter. This parameter may change the machining time",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Never damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ONLY_IF_RAWPART",
|
||||
"sDescriptionShort": "Damage only if raw",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ALWAYS",
|
||||
"sDescriptionShort": "Can damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
-- Strategia: STR0010
|
||||
-- Descrizione
|
||||
-- fresatura perpendicolare
|
||||
-- Feature: cut, longcut, ...
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local FaceByMill = require( 'FACEBYMILL')
|
||||
local FaceByBlade = require( 'FACEBYBLADE')
|
||||
local AntiSplintOnFace = require( 'ANTISPLINTONFACE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0010 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetStrategyCompletionPercentage( Machinings)
|
||||
local dCompletionPercentage = 0
|
||||
|
||||
local dCompletionPercentageNumerator = 0
|
||||
local dCompletionPercentageDenominator = 0
|
||||
local nWeightsCount = 0
|
||||
for i = 1, #Machinings do
|
||||
local Machining = Machinings[i]
|
||||
local dWeight = Machining.dResultWeight
|
||||
if not dWeight or ( dWeight < 10 * GEO.EPS_SMALL) then
|
||||
dWeight = 1
|
||||
else
|
||||
nWeightsCount = nWeightsCount + 1
|
||||
end
|
||||
-- il peso deve essere settato in tutte le lavorazioni o in nessuna
|
||||
if nWeightsCount ~= 0 and nWeightsCount ~= i then
|
||||
error( 'GetWeightedCompletionPercentage : inconsistent weights')
|
||||
end
|
||||
local dWeightedCompletionPercentage = ( Machining.dCompletionPercentage or 0) / 100 * dWeight
|
||||
if Machining.bIsApplicable then
|
||||
dCompletionPercentageNumerator = dCompletionPercentageNumerator + dWeightedCompletionPercentage
|
||||
end
|
||||
dCompletionPercentageDenominator = dCompletionPercentageDenominator + dWeight
|
||||
end
|
||||
|
||||
dCompletionPercentage = min( 100 * dCompletionPercentageNumerator / dCompletionPercentageDenominator, 100)
|
||||
|
||||
return dCompletionPercentage
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareEdgesLongestTop( EdgeA, EdgeB)
|
||||
-- si preferiscono i lati più lunghi
|
||||
if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa lunghezza si preferiscono i lati più in basso
|
||||
else
|
||||
if EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa Z si preferiscono i lati verso il fronte della trave
|
||||
else
|
||||
if EdgeA.vtN:getY() > EdgeB.vtN:getY() + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.vtN:getY() < EdgeB.vtN:getY() - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function CompareEdgesLongestBottom( EdgeA, EdgeB)
|
||||
-- si preferiscono i lati più lunghi
|
||||
if EdgeA.dLength > EdgeB.dLength + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.dLength < EdgeB.dLength - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa lunghezza si preferiscono i lati più in alto
|
||||
else
|
||||
if EdgeA.vtN:getZ() < EdgeB.vtN:getZ() - 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.vtN:getZ() > EdgeB.vtN:getZ() + 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
-- se stessa Z si preferiscono i lati verso il fronte della trave
|
||||
else
|
||||
if EdgeA.vtN:getY() > EdgeB.vtN:getY() + 10 * GEO.EPS_SMALL then
|
||||
return true
|
||||
elseif EdgeA.vtN:getY() < EdgeB.vtN:getY() - 10 * GEO.EPS_SMALL then
|
||||
return false
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function IsTopologyOk( Proc)
|
||||
if Proc.Topology.sFamily == 'Bevel' or Proc.Topology.sFamily == 'DoubleBevel' or
|
||||
Proc.Topology.sName == 'VGroove-2-Through' or Proc.Topology.sName == 'Rabbet-2-Through' or
|
||||
Proc.Topology.sName == 'Cut-1-Through' then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO modificare funzione e verificare pinzaggio con regioni e area outline
|
||||
local function IsPositionOk( Proc, Part)
|
||||
local bIsFeatureLong = FeatureLib.IsMachiningLong( Proc.b3Box:getDimX(), Part, { dMaxSegmentLength = BeamData.LONGCUT_ENDLEN})
|
||||
-- se impatta su faccia retro o sotto, controllo fattibilità
|
||||
if Proc.AffectedFaces.bBack then
|
||||
if ( bIsFeatureLong and Proc.b3Box:getDimZ() > Part.dHeight / 2) or ( not bIsFeatureLong and Proc.b3Box:getDimZ() > Part.dHeight / 2) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if Proc.AffectedFaces.bBottom then
|
||||
if ( bIsFeatureLong and Proc.b3Box:getDimY() > Part.dHeight / 2) or ( not bIsFeatureLong and Proc.b3Box:getDimY() > Part.dHeight / 2) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- altrimenti fattibile
|
||||
return true
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetLongEdgeToMachine( Face, bHeadType)
|
||||
local Edge = {}
|
||||
|
||||
local EdgesSorted = {}
|
||||
for i = 1, #Face.Edges do
|
||||
table.insert( EdgesSorted, Face.Edges[i])
|
||||
end
|
||||
if bHeadType.bBottom then
|
||||
table.sort( EdgesSorted, CompareEdgesLongestBottom)
|
||||
else
|
||||
table.sort( EdgesSorted, CompareEdgesLongestTop)
|
||||
end
|
||||
|
||||
-- se il lato migliore è accessibile si sceglie questo, altrimenti il lato opposto; se entrambi non accessibili (faccia chiusa da due lati) si mantiene il lato scelto
|
||||
Edge = EdgesSorted[1]
|
||||
local EdgeOpposite = BeamLib.FindEdgeBestOrientedAsDirection( Face.Edges, -Edge.vtN)
|
||||
if ( not EdgeOpposite.bIsOpen) and Edge.bIsOpen then
|
||||
Edge = EdgeOpposite
|
||||
end
|
||||
|
||||
return Edge
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function SortMachiningsBySegment( MachiningA, MachiningB)
|
||||
if MachiningA.nFeatureSegment > MachiningB.nFeatureSegment then
|
||||
return false
|
||||
elseif MachiningB.nFeatureSegment > MachiningA.nFeatureSegment then
|
||||
return true
|
||||
-- se segmento uguale, si guarda la priorità
|
||||
else
|
||||
if MachiningA.nInternalSortingPriority > MachiningB.nInternalSortingPriority then
|
||||
return false
|
||||
elseif MachiningB.nInternalSortingPriority > MachiningA.nInternalSortingPriority then
|
||||
return true
|
||||
-- se priorità uguale, si minimizzano i cambi di lato
|
||||
else
|
||||
local bIsOddSegment = ( MachiningA.nFeatureSegment % 2 ~= 0)
|
||||
if MachiningA.vtToolDirection:getY() < MachiningB.vtToolDirection:getY() - 10 * GEO.EPS_SMALL then
|
||||
if bIsOddSegment then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
elseif MachiningA.vtToolDirection:getY() > MachiningB.vtToolDirection:getY() + 10 * GEO.EPS_SMALL then
|
||||
if bIsOddSegment then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0010.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri da default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machinings = {}
|
||||
Strategy.Result = {}
|
||||
local CalculatedMachinings = {}
|
||||
|
||||
-- controllo su topologia
|
||||
if not IsTopologyOk( Proc) then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Strategy ' .. StrategyLib.Config.sStrategyId .. ' not implemented')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- controllo dimensioni solo se non è forzata
|
||||
if not CustomParameters.bForcedStrategy then
|
||||
if not IsPositionOk( Proc, Part) then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Feature not machinable in this position')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
-- se la lavorazione ostacola il pinzaggio, non posso farla, serve una lavorazioen che lasci il testimone
|
||||
if MachiningLib.IsFeatureHinderingClamping( Proc, Part) then
|
||||
local sErr = 'Feature '.. Proc.idFeature .. ' : strategy ' .. StrategyLib.Config.sStrategyId .. ' not applicable ( Feature hinders clamping)'
|
||||
EgtOutLog( sErr)
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sErr)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- volume della feature
|
||||
local dFeatureVolume = Proc.dVolume
|
||||
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
local bIsSplitFeature = false
|
||||
if #FeatureSplittingPoints > 0 then
|
||||
bIsSplitFeature = true
|
||||
end
|
||||
|
||||
local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece - BeamData.CUT_EXTRA, 0)
|
||||
if MachiningLib.CanExtendAfterTail( Strategy.Parameters.sCanDamageNextPiece, Part) then
|
||||
dExtendAfterTail = 10000
|
||||
end
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
-- ricerca delle Bottom (la principale deve avere 4 lati esatti)
|
||||
local BottomFace1 = Proc.MainFaces.BottomFaces[1]
|
||||
local BottomFace2 = Proc.MainFaces.BottomFaces[2]
|
||||
if #BottomFace1.Edges ~= 4 then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- ricerca utensile
|
||||
local ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = BottomFace1.dElevation
|
||||
ToolSearchParameters.vtToolDirection = BottomFace1.vtN
|
||||
ToolSearchParameters.bAllowTopHead = true
|
||||
ToolSearchParameters.bAllowBottomHead = true
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
local ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
local nToolIndex = ToolInfo.nToolIndex
|
||||
|
||||
-- se utensile non trovato si esce subito
|
||||
if not TOOLS[nToolIndex] or not TOOLS[nToolIndex].sName then
|
||||
local sMessage = 'Mill not found'
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sMessage)
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- per prima si lavora sempre la Bottom principale
|
||||
local Milling1 = {}
|
||||
local OptionalParametersMilling1 = { nStepType = MCH_MILL_ST.ONEWAY, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail}
|
||||
local BottomEdgeToMachine1 = GetLongEdgeToMachine( BottomFace1, TOOLS[nToolIndex].SetupInfo.HeadType)
|
||||
if BottomEdgeToMachine1.bIsOpen then
|
||||
OptionalParametersMilling1.dDepthToMachine = BottomEdgeToMachine1.dElevation + BeamData.CUT_EXTRA
|
||||
end
|
||||
Milling1 = FaceByMill.Make( Proc, Part, BottomFace1, BottomEdgeToMachine1, OptionalParametersMilling1)
|
||||
Milling1.nInternalSortingPriority = 2
|
||||
Milling1.dResultWeight = 0.3
|
||||
table.insert( CalculatedMachinings, Milling1)
|
||||
|
||||
-- se necessario si lavora la seconda Bottom (solo se ha 4 lati esatti)
|
||||
local Milling2
|
||||
local BottomEdgeToMachine2
|
||||
if BottomFace2 then
|
||||
local dAngleBetweenFaces = Proc.AdjacencyMatrix[BottomFace1.id + 1][BottomFace2.id + 1]
|
||||
if dAngleBetweenFaces >= -89.5 then
|
||||
Milling2 = {}
|
||||
if #BottomFace2.Edges == 4 then
|
||||
local OptionalParametersMilling2 = { nStepType = MCH_MILL_ST.ONEWAY, bIsSplitFeature = bIsSplitFeature, dExtendAfterTail = dExtendAfterTail}
|
||||
BottomEdgeToMachine2 = GetLongEdgeToMachine( BottomFace2, TOOLS[nToolIndex].SetupInfo.HeadType)
|
||||
if BottomEdgeToMachine2.bIsOpen then
|
||||
OptionalParametersMilling2.dDepthToMachine = BottomEdgeToMachine2.dElevation + BeamData.CUT_EXTRA
|
||||
end
|
||||
Milling2 = FaceByMill.Make( Proc, Part, BottomFace2, BottomEdgeToMachine2, OptionalParametersMilling2)
|
||||
Milling2.nInternalSortingPriority = 2
|
||||
Milling2.dResultWeight = 0.3
|
||||
else
|
||||
Milling2.bIsApplicable = false
|
||||
end
|
||||
table.insert( CalculatedMachinings, Milling2)
|
||||
end
|
||||
end
|
||||
|
||||
-- fresatura eventuali facce di chiusura (se non già lavorate)
|
||||
-- TODO funzione
|
||||
if Strategy.Parameters.bFinishWithMill then
|
||||
|
||||
if Milling1 then
|
||||
-- si recuperano i lati chiusi non lavorati
|
||||
local EdgesClosedNotMachined = {}
|
||||
for i = 1, #BottomFace1.Edges do
|
||||
if not( ( BottomFace1.Edges[i].id == BottomEdgeToMachine1.id) or BottomFace1.Edges[i].bIsOpen) then
|
||||
table.insert( EdgesClosedNotMachined, BottomFace1.Edges[i])
|
||||
end
|
||||
end
|
||||
-- su ognuno si fa la fresatura di pulizia
|
||||
for i = 1, #EdgesClosedNotMachined do
|
||||
local dMillingOffsetFromSide = Strategy.Parameters.bAntiSplintWithBlade and Strategy.Parameters.dMillingOffsetFromSide or 0
|
||||
local dDepthToMachine = EdgesClosedNotMachined[i].dElevation - dMillingOffsetFromSide
|
||||
local dToolMarkLength = Milling1.dToolMarkLength or 0
|
||||
local OptionalParameters = {
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dRadialStepSpan = dToolMarkLength,
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
local Milling = FaceByMill.Make( Proc, Part, BottomFace1, EdgesClosedNotMachined[i], OptionalParameters)
|
||||
Milling.nInternalSortingPriority = 3
|
||||
Milling.dResultWeight = 0.05
|
||||
table.insert( CalculatedMachinings, Milling)
|
||||
end
|
||||
end
|
||||
|
||||
if Milling2 then
|
||||
-- si recuperano i lati chiusi non lavorati
|
||||
local EdgesClosedNotMachined = {}
|
||||
for i = 1, #BottomFace2.Edges do
|
||||
if not( ( BottomFace2.Edges[i].id == BottomEdgeToMachine2.id) or BottomFace2.Edges[i].bIsOpen) then
|
||||
table.insert( EdgesClosedNotMachined, BottomFace2.Edges[i])
|
||||
end
|
||||
end
|
||||
-- su ognuno si fa la fresatura di pulizia
|
||||
for i = 1, #EdgesClosedNotMachined do
|
||||
local dMillingOffsetFromSide = Strategy.Parameters.bAntiSplintWithBlade and Strategy.Parameters.dMillingOffsetFromSide or 0
|
||||
local dDepthToMachine = EdgesClosedNotMachined[i].dElevation - dMillingOffsetFromSide
|
||||
local dToolMarkLength = Milling2.dToolMarkLength or 0
|
||||
local OptionalParameters = {
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
dRadialStepSpan = dToolMarkLength,
|
||||
dDepthToMachine = dDepthToMachine
|
||||
}
|
||||
local Milling = FaceByMill.Make( Proc, Part, BottomFace2, EdgesClosedNotMachined[i], OptionalParameters)
|
||||
Milling.nInternalSortingPriority = 3
|
||||
Milling.dResultWeight = 0.05
|
||||
table.insert( CalculatedMachinings, Milling)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- antischeggia sulle facce di chiusura delle facce lavorate
|
||||
local CalculatedMachiningsNoAntisplint = BeamLib.TableCopyDeep( CalculatedMachinings)
|
||||
if Strategy.Parameters.bAntiSplintWithBlade then
|
||||
|
||||
local OptionalParametersAntiSplint = {
|
||||
bIsSplitFeature = bIsSplitFeature,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
nInternalSortingPriority = 1,
|
||||
dResultWeight = 0.15
|
||||
}
|
||||
local AntiSplints1 = AntiSplintOnFace.Make( Proc, Part, BottomFace1, OptionalParametersAntiSplint)
|
||||
for i = 1, #AntiSplints1 do
|
||||
table.insert( CalculatedMachinings, AntiSplints1[i])
|
||||
end
|
||||
if Milling2 then
|
||||
local AntiSplints2 = AntiSplintOnFace.Make( Proc, Part, BottomFace2, OptionalParametersAntiSplint)
|
||||
for i = 1, #AntiSplints2 do
|
||||
table.insert( CalculatedMachinings, AntiSplints2[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- calcolo completamento, serve la lista di lavorazioni che comprende le non applicabili, ma non gli antischeggia (quelle alzano la qualità e sono già contemplate)
|
||||
Strategy.Result.dCompletionPercentage = GetStrategyCompletionPercentage( CalculatedMachiningsNoAntisplint)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Strategy.Result.dCompletionPercentage)
|
||||
|
||||
-- lavorazioni da applicare spostate in lista finale
|
||||
for i = 1, #CalculatedMachinings do
|
||||
if CalculatedMachinings[i].bIsApplicable then
|
||||
table.insert( Strategy.Machinings, CalculatedMachinings[i])
|
||||
end
|
||||
end
|
||||
|
||||
Strategy.Machinings = MachiningLib.GetSplitMachinings( Strategy.Machinings, FeatureSplittingPoints, Part)
|
||||
table.sort( Strategy.Machinings, SortMachiningsBySegment)
|
||||
|
||||
-- se non ci sono lati chiusi, la qualità è migliore
|
||||
if Proc.Topology.sName == 'Bevel-1-Through' or Proc.Topology.sName == 'DoubleBevel-2-Through' or Proc.Topology.sName == 'Cut-1-Through' then
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
else
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( Strategy.Machinings)
|
||||
end
|
||||
Strategy.Result.dTimeToMachine = FeatureLib.GetStrategyTimeToMachine( Strategy.Machinings)
|
||||
Strategy.Result.dMRR = ( dFeatureVolume / Strategy.Result.dTimeToMachine) / pow( 10, 6)
|
||||
if Strategy.Result.dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
end
|
||||
|
||||
-- aggiunta lavorazioni
|
||||
if #Strategy.Machinings > 0 then
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #Strategy.Machinings do
|
||||
local AuxiliaryData = {}
|
||||
-- se strategia forzata non considero area non pinzabile
|
||||
if CustomParameters.bForcedStrategy then
|
||||
AuxiliaryData.bIgnoreNotClampableLength = true
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machinings[j], AuxiliaryData)
|
||||
end
|
||||
end
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0010
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"sStrategyId": "STR0011",
|
||||
"sStrategyName": "Hole with Drillbit",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dDiameterTolerance",
|
||||
"sNameNge": "TOLERANCE",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Tolerance on Diameter",
|
||||
"sDescriptionLong": "Tolerance on Diameter",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dDepthPreHole",
|
||||
"sNameNge": "DEPTHPREHOLE",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Depth PreHole",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sDrillingMode",
|
||||
"sNameNge": "DRILLING_MODE",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Drilling Mode",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "PREFER_ONE",
|
||||
"sDescriptionShort": "Preferred machining from one side only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "FORCE_TWO",
|
||||
"sDescriptionShort": "Force machining from two sides",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sDrillBitList",
|
||||
"sNameNge": "DRILL_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available Drillbit list",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.DRILLBIT",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
-- Strategia: STR0011
|
||||
-- Descrizione
|
||||
-- foratura
|
||||
-- Feature: foro
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0011 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-- TODO Da fare completamente gestione foratura doppia con 2 teste
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetDrillingStrategy( Proc, Part)
|
||||
local ToolSearchParameters = {}
|
||||
local Machining = {}
|
||||
|
||||
-- si cerca utensile 1
|
||||
local Drilling = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dToolDiameter = Proc.FeatureInfo.dDrillDiam
|
||||
ToolSearchParameters.dDiameterTolerance = Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sDrillBitList, 'Drilling')
|
||||
ToolSearchParameters.ptCheckOutStroke = { Proc.FeatureInfo.ptDrillCenter + ( EgtMdbGetGeneralParam( MCH_GP.SAFEZ) * ToolSearchParameters.vtToolDirection)}
|
||||
|
||||
Drilling.ToolInfo = {}
|
||||
Drilling.ToolInfo = MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
-- se trovato utensile si settano i parametri comuni
|
||||
if Drilling.ToolInfo.nToolIndex then
|
||||
Drilling.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling.nToolIndex = Drilling.ToolInfo.nToolIndex
|
||||
Drilling.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling.dStep = TOOLS[Drilling.nToolIndex].dStep
|
||||
end
|
||||
|
||||
-- TODO se utensile 2 che si torverà è il gemello da usare nelle lavorazioni in doppio, allora gestire di conseguenza l'applicazione delle lavorazioni in doppio
|
||||
-- si cerca utensile 2
|
||||
local Drilling2 = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
Drilling2.ToolInfo = {}
|
||||
if Proc.FeatureInfo.bIsDrillOpen then
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dDiameterTolerance = Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sDrillBitList, 'Drilling')
|
||||
ToolSearchParameters.ptCheckOutStroke = { Proc.FeatureInfo.ptDrillCenter + ( ( Proc.FeatureInfo.dDrillLen + EgtMdbGetGeneralParam( MCH_GP.SAFEZ)) * ToolSearchParameters.vtToolDirection)}
|
||||
|
||||
Drilling2.ToolInfo = MachiningLib.FindDrill( Proc, ToolSearchParameters)
|
||||
-- se trovato utensile si settano i parametri comuni
|
||||
if Drilling2.ToolInfo.nToolIndex then
|
||||
Drilling2.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
Drilling2.nToolIndex = Drilling2.ToolInfo.nToolIndex
|
||||
Drilling2.bInvert = true
|
||||
Drilling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
Drilling2.dStep = TOOLS[Drilling2.nToolIndex].dStep
|
||||
end
|
||||
end
|
||||
|
||||
-- se possono lavorare entrambi e si deve fare lavorazione doppia e si riesce a completare
|
||||
if Drilling.ToolInfo.nToolIndex and Drilling2.ToolInfo.nToolIndex and
|
||||
( Strategy.Parameters.sDrillingMode == 'FORCE_TWO' or Strategy.Parameters.sDrillingMode == 'AUTO') and
|
||||
Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth < Proc.FeatureInfo.dDrillLen then
|
||||
|
||||
local dExtraDrill = ( Proc.FeatureInfo.dDrillLen - BeamData.MILL_OVERLAP - ( Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth)) / 2
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Drilling)
|
||||
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Drilling2)
|
||||
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.sInfo = ''
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
|
||||
-- se utensile 1 esegue completamente
|
||||
elseif Drilling.ToolInfo.nToolIndex and Drilling.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL and
|
||||
( Strategy.Parameters.sDrillingMode == 'PREFER_ONE' or ( not Drilling2.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode == 'AUTO') or not Proc.FeatureInfo.bIsDrillOpen) then
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen
|
||||
table.insert( Machining, Drilling)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Proc.FeatureInfo.bIsDrillOpen, 'ROUGH', 'FINE'))
|
||||
Strategy.Result.sInfo = ''
|
||||
-- annullo altra lavorazione
|
||||
Drilling2.ToolInfo.nToolIndex = nil
|
||||
-- se utensile 2 esegue completamente
|
||||
elseif Drilling2.ToolInfo.nToolIndex and Drilling2.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL and
|
||||
( Strategy.Parameters.sDrillingMode == 'PREFER_ONE' or ( not Drilling.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode == 'AUTO')) then
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen
|
||||
table.insert( Machining, Drilling2)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( EgtIf( Proc.FeatureInfo.bIsDrillOpen, 'ROUGH', 'FINE'))
|
||||
Strategy.Result.sInfo = ''
|
||||
-- annullo altra lavorazione
|
||||
Drilling.ToolInfo.nToolIndex = nil
|
||||
-- se possono lavorare entrambi
|
||||
elseif Drilling.ToolInfo.nToolIndex and Drilling2.ToolInfo.nToolIndex then
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling)
|
||||
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling2)
|
||||
if Drilling.ToolInfo.dResidualDepth + Drilling2.ToolInfo.dResidualDepth < Proc.FeatureInfo.dDrillLen then
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth + Machining[2].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.sInfo = ''
|
||||
end
|
||||
-- voto
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- se utensile 1 non completo
|
||||
elseif Drilling.ToolInfo.nToolIndex and ( Strategy.Parameters.sDrillingMode ~= 'FORCE_TWO' or Proc.FeatureInfo.bIsDrillOpen) then
|
||||
Drilling.sDepth = Proc.FeatureInfo.dDrillLen - Drilling.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- annullo altra lavorazione
|
||||
Drilling2.ToolInfo.nToolIndex = nil
|
||||
-- se utensile 2 non completo
|
||||
elseif Drilling2.ToolInfo.nToolIndex and Strategy.Parameters.sDrillingMode ~= 'FORCE_TWO' then
|
||||
Drilling2.sDepth = Proc.FeatureInfo.dDrillLen - Drilling2.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Drilling2)
|
||||
-- voto
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dMachinedLen = Machining[1].sDepth
|
||||
local dMachinedPrercentage = 100 * ( dMachinedLen / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dMachinedPrercentage)
|
||||
Strategy.Result.sInfo = 'Drill not complete, left ' .. tostring( 100 - ceil( dMachinedPrercentage)) .. '%'
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'FINE')
|
||||
-- annullo altra lavorazione
|
||||
Drilling.ToolInfo.nToolIndex = nil
|
||||
else
|
||||
local sMessage
|
||||
-- se non sono state trovate punte
|
||||
if not Drilling.ToolInfo.nToolIndex and not Drilling2.ToolInfo.nToolIndex then
|
||||
sMessage = 'Drillbit not found'
|
||||
-- se son state trovate delle punte, ma non è stato possibile forare da entrambe le parti
|
||||
elseif Strategy.Parameters.sDrillingMode == 'FORCE_TWO' then
|
||||
sMessage = "Not possible to force machining from both sides. Please change drilling mode to AUTO"
|
||||
end
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sMessage)
|
||||
end
|
||||
|
||||
-- calcolo tempo di lavorazione
|
||||
Strategy.Result.dTimeToMachine = 0
|
||||
if Drilling.ToolInfo.nToolIndex then
|
||||
Strategy.Result.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Drilling, Part)
|
||||
end
|
||||
if Drilling2.ToolInfo.nToolIndex then
|
||||
Strategy.Result.dTimeToMachine = Strategy.Result.dTimeToMachine + MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Drilling2, Part)
|
||||
end
|
||||
|
||||
return Machining, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0011.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri da default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machinings = {}
|
||||
Strategy.Result = {}
|
||||
|
||||
local bAreAllMachiningsAdded
|
||||
|
||||
Strategy.Machinings, Strategy.Result = GetDrillingStrategy( Proc, Part)
|
||||
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #Strategy.Machinings do
|
||||
Strategy.Machinings[j].nType = MCH_MY.DRILLING
|
||||
Strategy.Machinings[j].Steps.dStep = TOOLS[Strategy.Machinings[j].ToolInfo.nToolIndex].dStep
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machinings[j])
|
||||
end
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0011
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"sStrategyId": "STR0012",
|
||||
"sStrategyName": "RidgeLap with Blade",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dExtendAfterTail",
|
||||
"sNameNge": "EXTEND_AFTER_TAIL",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Extend after tail",
|
||||
"sDescriptionLong": "The automatism considers this length as machinable. This means you accept to damage the next piece in the bar",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sCanDamageNextPiece",
|
||||
"sNameNge": "DAMAGE_NEXT_PIECE",
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Damage next piece",
|
||||
"sDescriptionLong": "This option allows you to decide how to consider the next piece in the bar. The software calculates specifics LeadIn/out to respect the parameter. This parameter may change the machining time",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "NEVER",
|
||||
"sDescriptionShort": "Never damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ONLY_IF_RAWPART",
|
||||
"sDescriptionShort": "Damage only if raw",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "ALWAYS",
|
||||
"sDescriptionShort": "Can damage",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sRidgelapStrategy",
|
||||
"sNameNge": "RIDGELAP_STRATEGY",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Ridge Lap strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BLADE",
|
||||
"sDescriptionShort": "Use blade",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "MILL",
|
||||
"sDescriptionShort": "Use mill",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
-- Strategia: STR0012
|
||||
-- Descrizione
|
||||
-- RidgeLap
|
||||
-- Feature: RidgeLap
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require( 'BLADETOWASTE')
|
||||
local BladeKeepWaste =require ( 'BLADEKEEPWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0012 = {}
|
||||
local Strategy = {}
|
||||
local RidgeLap = {}
|
||||
RidgeLap.Result = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO risolvere problemi calcolo volume nullo se facce rimosse
|
||||
-- TODO gestire lavorazione con svuotatura
|
||||
-- TODO risolvere problema ultimo cubetto troppo profondo!!
|
||||
-- TODO gestire strategia con fresa
|
||||
function STR0012.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri da default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.sInfo = ''
|
||||
RidgeLap.Result = {}
|
||||
local TwoFaces = {}
|
||||
local AddedFace = {}
|
||||
TwoFaces.Result = {}
|
||||
AddedFace.Result = {}
|
||||
local dTimeToMachine = 0
|
||||
local dMRRBlade = 0
|
||||
local dCompletionPercentage = 0
|
||||
local dQuality = 0
|
||||
local dMRRBladeAddedFace = 0
|
||||
local dCompletionPercentageAddedFace = 0
|
||||
local dQualityAddedFace = 0
|
||||
local AuxiliaryData = { bIgnoreNotClampableLength = false}
|
||||
|
||||
-- gestito solo RidgeLap 3 facce
|
||||
if Proc.nFct ~= 3 then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Only RidgeLap 3 faces is applicable')
|
||||
end
|
||||
|
||||
-- estensione oltre la coda
|
||||
local dExtendAfterTail = Strategy.Parameters.dExtendAfterTail or max( Part.dDistanceToNextPiece - BeamData.CUT_EXTRA, 0)
|
||||
if MachiningLib.CanExtendAfterTail( Strategy.Parameters.sCanDamageNextPiece, Part) then
|
||||
dExtendAfterTail = 10000
|
||||
end
|
||||
|
||||
-- separazione della terza faccia
|
||||
local idAddedTmFace
|
||||
local nAddedFace
|
||||
if Proc.AdjacencyMatrix[2][3] < 0 then
|
||||
nAddedFace = 1 - 1
|
||||
elseif Proc.AdjacencyMatrix[1][3] < 0 then
|
||||
nAddedFace = 2 - 1
|
||||
else
|
||||
nAddedFace = 3 - 1
|
||||
end
|
||||
local OriginalProc = Proc
|
||||
-- recupero gruppo per geometria addizionale
|
||||
local nAddGrpId = BeamLib.GetAddGroup( Part.id)
|
||||
-- se la faccia aggiuntiva non corrisponde al taglio di testa o di coda, si deve lavorare come faccia singola
|
||||
if not( AreSameVectorApprox( Proc.Faces[nAddedFace + 1].vtN, X_AX()) and abs( Proc.Faces[nAddedFace + 1].ptCenter:getX() - Part.b3Part:getMax():getX()) < 10 * GEO.EPS_SMALL)
|
||||
and not( AreSameVectorApprox( Proc.Faces[nAddedFace + 1].vtN, -X_AX()) and abs( Proc.Faces[nAddedFace + 1].ptCenter:getX() - Part.b3Part:getMin():getX()) < 10 * GEO.EPS_SMALL) then
|
||||
|
||||
-- faccia aggiuntiva da lavorare: si estende fino al box della parte
|
||||
local idAddGroup
|
||||
if bAddMachining then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
idAddedTmFace = EgtSurfTmPlaneInBBox( idAddGroup, Proc.Faces[nAddedFace + 1].ptCenter, Proc.Faces[nAddedFace + 1].vtN, Part.b3Part, GDB_ID.ROOT)
|
||||
end
|
||||
|
||||
-- rimozione della terza faccia dalla Proc
|
||||
local idNewProc = EgtCopyGlob( Proc.id, nAddGrpId)
|
||||
EgtSurfTmRemoveFacet( idNewProc, nAddedFace)
|
||||
local NewProc = FeatureLib.GetProcFromTrimesh( idNewProc, Part, Proc)
|
||||
NewProc.Topology = FeatureLib.ClassifyTopology( NewProc, Part)
|
||||
NewProc.NotClampableLength = FeatureLib.CalculateFeatureNotClampableLengths( NewProc, Part)
|
||||
NewProc.bHindersLaserMeasure = FeatureLib.CalculateFeatureHindersLaserMeasure( NewProc, Part)
|
||||
|
||||
-- considerazioni necessarie a determinare se lavorare con codolo oppure no
|
||||
local bKeepWasteAttached = ( Strategy.Parameters.sCuttingStrategy == 'KEEP_WASTE_ATTACHED')
|
||||
local bDropWaste = ( Strategy.Parameters.sCuttingStrategy == 'DROP_WASTE')
|
||||
local bFeatureHindersClamping = MachiningLib.IsFeatureHinderingClamping( Proc, Part)
|
||||
|
||||
-- lavorazione con codolo
|
||||
if ( bFeatureHindersClamping and not bDropWaste)
|
||||
or bKeepWasteAttached then
|
||||
|
||||
local BladeKeepWasteResult
|
||||
local OptionalParameters = { dExtendAfterTail = dExtendAfterTail, dStripWidth = 5, bFinishWithMill = false}
|
||||
AuxiliaryData.bIgnoreNotClampableLength = true
|
||||
TwoFaces.Result, BladeKeepWasteResult = BladeKeepWaste.Make( NewProc, Part, OptionalParameters)
|
||||
dTimeToMachine = BladeKeepWasteResult.dTimeToMachine
|
||||
dMRRBlade = BladeKeepWasteResult.dMRR
|
||||
dCompletionPercentage = BladeKeepWasteResult.dCompletionPercentage
|
||||
dQuality = BladeKeepWasteResult.dQuality
|
||||
|
||||
-- lavorazione a cubetti facce concave
|
||||
else
|
||||
local BladeToWasteResult
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
AuxiliaryData.bIgnoreNotClampableLength = false
|
||||
TwoFaces.Result, BladeToWasteResult = BladeToWaste.Make( NewProc, Part, OptionalParameters)
|
||||
dTimeToMachine = BladeToWasteResult.dTimeToMachine
|
||||
dMRRBlade = BladeToWasteResult.dMRR
|
||||
dCompletionPercentage = BladeToWasteResult.dCompletionPercentage
|
||||
dQuality = BladeToWasteResult.dQuality
|
||||
end
|
||||
|
||||
-- lavorazione terza faccia
|
||||
-- TODO da completare
|
||||
-- TODO va messa per prima????????
|
||||
if idAddedTmFace then
|
||||
local BladeToWasteResult
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bSaveAddedGeometries = bAddMachining,
|
||||
dExtendAfterTail = dExtendAfterTail,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
AddedFace.Result, BladeToWasteResult = BladeToWaste.Make( idAddedTmFace, Part, OptionalParameters)
|
||||
|
||||
-- TODO calcolo risultati da aggiornare con funzioni nuove
|
||||
dMRRBladeAddedFace = BladeToWasteResult.dMRR
|
||||
dCompletionPercentageAddedFace = BladeToWasteResult.dCompletionPercentage
|
||||
dQualityAddedFace = BladeToWasteResult.dQuality
|
||||
|
||||
dTimeToMachine = dTimeToMachine + BladeToWasteResult.dTimeToMachine
|
||||
-- la faccia aggiuntiva conta per 1/3
|
||||
dMRRBlade = 2/3 * dMRRBlade + 1/3 * dMRRBladeAddedFace
|
||||
dCompletionPercentage = 2/3 * dCompletionPercentage + 1/3 * dCompletionPercentageAddedFace
|
||||
dQuality = 2/3 * dQuality + 1/3 * dQualityAddedFace
|
||||
end
|
||||
|
||||
-- lavorazioni in lista unica
|
||||
for i = 1, #AddedFace.Result do
|
||||
table.insert( RidgeLap.Result, AddedFace.Result[i])
|
||||
end
|
||||
for i = 1, #TwoFaces.Result do
|
||||
table.insert( RidgeLap.Result, TwoFaces.Result[i])
|
||||
end
|
||||
|
||||
-- aggiunta lavorazioni
|
||||
local nIsApplicableCount = 0
|
||||
local bAreAllMachiningsAdded = true
|
||||
for i = 1, #RidgeLap.Result do
|
||||
if RidgeLap.Result[i].bIsApplicable then
|
||||
nIsApplicableCount = nIsApplicableCount + 1
|
||||
if bAddMachining then
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( OriginalProc, RidgeLap.Result[i], AuxiliaryData)
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
Strategy.Result.sInfo = Strategy.Result.sInfo .. '\n' .. RidgeLap.Result[i].sMessage
|
||||
end
|
||||
end
|
||||
-- TODO migliorare calcolo area lavorata; se ho il codolo ha senso l'incompleta? se incompleta con codolo faccio i cubetti??
|
||||
-- TODO settare che il codolo restituisce incompleta tranne quando è forzato
|
||||
if nIsApplicableCount > 0 then
|
||||
if dCompletionPercentage > 100 - 10 * GEO.EPS_SMALL then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
end
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( dCompletionPercentage)
|
||||
Strategy.Result.dQuality = dQuality
|
||||
Strategy.Result.dTimeToMachine = dTimeToMachine
|
||||
Strategy.Result.dMRR = dMRRBlade
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Applicable'
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
end
|
||||
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0012
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"sStrategyId": "STR0013",
|
||||
"sStrategyName": "Hole with Mill",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dDiameterTolerance",
|
||||
"sNameNge": "TOLERANCE",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Tolerance on Diameter",
|
||||
"sDescriptionLong": "Tolerance on Diameter",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bUseMillAsDrill",
|
||||
"sNameNge": "DRILLMILL",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Use mill as a drillbit",
|
||||
"sDescriptionLong": "Admit to use the mill as a drillbit",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bOnlyContouring",
|
||||
"sNameNge": "ONLYCONT",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Execute contour only",
|
||||
"sDescriptionLong": "Execute the contour anyway, even the hole is bigger than the tool diameter",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sDrillingMode",
|
||||
"sNameNge": "DRILLING_MODE",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Drilling mode",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "PREFER_ONE",
|
||||
"sDescriptionShort": "Preferred machining from one side only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "FORCE_TWO",
|
||||
"sDescriptionShort": "Force machining from two sides",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sMillList",
|
||||
"sNameNge": "DRILLPOCK_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine drills",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
-- Strategia: STR0013
|
||||
-- Descrizione
|
||||
-- foratura
|
||||
-- Feature: foro con fresa
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
-- strategie di base
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0013 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetDrillingWithMillStrategy( Proc, Part)
|
||||
local ToolSearchParameters = {}
|
||||
local Machining = {}
|
||||
local Milling = { ToolInfo = {}}
|
||||
local Milling2 = { ToolInfo = {}}
|
||||
|
||||
-- si cerca fresa con direzione standard
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dMaxToolDiameter = Proc.FeatureInfo.dDrillDiam + Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.sType = 'MILL_STD'
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillList, 'Milling')
|
||||
Milling.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
|
||||
-- se foro aperto, si cerca anche fresa con direzione invertita
|
||||
if Proc.FeatureInfo.bIsDrillOpen then
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dMaxToolDiameter = Proc.FeatureInfo.dDrillDiam + Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.sType = 'MILL_STD'
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillList, 'Milling')
|
||||
Milling2.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
Milling2.bInvert = true
|
||||
Milling2.bToolInvert = true
|
||||
Milling2.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
end
|
||||
|
||||
local bDouble = false
|
||||
-- se ho trovato entrambi gli utensili e non è forzato da eseguire solo da un lato e una punta lo fa completo, si fa foratura in doppio
|
||||
if Milling.ToolInfo.nToolIndex and Milling2.ToolInfo.nToolIndex and
|
||||
not ( Strategy.Parameters.sDrillingMode == 'PREFER_ONE' and ( Milling.ToolInfo.dResidualDepth < 0 or Milling2.ToolInfo.dResidualDepth < 0)) then
|
||||
|
||||
bDouble = true
|
||||
-- se entrambe le punte lavorano più della metà del foro, si cerca un altro utensile che possa lavorare fino alla metà del foro
|
||||
-- è possibile che si possa trovare fresa più corta che lavora a sufficienza
|
||||
if Milling.ToolInfo.dResidualDepth < ( Proc.FeatureInfo.dDrillLen - BeamData.MILL_OVERLAP) / 2 and
|
||||
Milling2.ToolInfo.dResidualDepth < ( Proc.FeatureInfo.dDrillLen - BeamData.MILL_OVERLAP) / 2 then
|
||||
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = ( Proc.FeatureInfo.dDrillLen + BeamData.MILL_OVERLAP) / 2
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.dMaxToolDiameter = Proc.FeatureInfo.dDrillDiam + Strategy.Parameters.dDiameterTolerance
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillList, 'Milling')
|
||||
local HalfMilling = {}
|
||||
HalfMilling.ToolInfo = {}
|
||||
HalfMilling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
|
||||
ToolSearchParameters.vtToolDirection = -Proc.FeatureInfo.vtDrillExtrusion
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillList, 'Milling')
|
||||
local HalfMilling2 = {}
|
||||
HalfMilling2.ToolInfo = {}
|
||||
HalfMilling2.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
|
||||
-- se entrambi gli utensili lavorano in modo completo fino alla metà del foro, li sostituisco a qeulli trovati in precedenza
|
||||
if HalfMilling.ToolInfo.dResidualDepth and HalfMilling2.ToolInfo.dResidualDepth and HalfMilling.ToolInfo.dResidualDepth < 0 and HalfMilling2.ToolInfo.dResidualDepth < 0 then
|
||||
if Milling.ToolInfo.nToolIndex ~= HalfMilling.ToolInfo.nToolIndex then
|
||||
Milling.ToolInfo.nToolIndex, Milling.ToolInfo.dResidualDepth = HalfMilling.ToolInfo.nToolIndex, HalfMilling.ToolInfo.dResidualDepth
|
||||
end
|
||||
if Milling2.ToolInfo.nToolIndex ~= HalfMilling2.ToolInfo.nToolIndex then
|
||||
Milling2.ToolInfo.nToolIndex, Milling2.ToolInfo.dResidualDepth = HalfMilling2.ToolInfo.nToolIndex, HalfMilling2.ToolInfo.dResidualDepth
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local dResidual = Proc.FeatureInfo.dDrillLen
|
||||
-- aggiunta lavorazioni a lista
|
||||
-- se foro doppio
|
||||
if bDouble then
|
||||
dResidual = Milling.ToolInfo.dResidualDepth + Milling2.ToolInfo.dResidualDepth - Proc.FeatureInfo.dDrillLen
|
||||
Strategy.Result.dMRR = ( MachiningLib.GetToolMRR( Milling.ToolInfo) + MachiningLib.GetToolMRR( Milling2.ToolInfo)) / 2
|
||||
local dExtraDrill = ( Proc.FeatureInfo.dDrillLen - BeamData.MILL_OVERLAP - ( Milling.ToolInfo.dResidualDepth + Milling2.ToolInfo.dResidualDepth)) / 2
|
||||
Milling.sDepth = Proc.FeatureInfo.dDrillLen - Milling.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Milling)
|
||||
Milling2.sDepth = Proc.FeatureInfo.dDrillLen - Milling2.ToolInfo.dResidualDepth - dExtraDrill
|
||||
table.insert( Machining, Milling2)
|
||||
-- altrimenti singolo
|
||||
else
|
||||
local BestMilling
|
||||
if not Milling.ToolInfo.nToolIndex then
|
||||
BestMilling = Milling2
|
||||
elseif not Milling2.ToolInfo.nToolIndex then
|
||||
BestMilling = Milling
|
||||
else
|
||||
if Milling.ToolInfo.dResidualDepth < 0 then
|
||||
BestMilling = Milling
|
||||
elseif Milling2.ToolInfo.dResidualDepth < 0 then
|
||||
BestMilling = Milling2
|
||||
else
|
||||
BestMilling = EgtIf( Milling.ToolInfo.dResidualDepth < Milling2.ToolInfo.dResidualDepth, Milling, Milling2)
|
||||
end
|
||||
end
|
||||
if BestMilling.ToolInfo.nToolIndex then
|
||||
dResidual = BestMilling.ToolInfo.dResidualDepth
|
||||
if dResidual < 0 then
|
||||
BestMilling.sDepth = Proc.FeatureInfo.dDrillLen + EgtIf( Proc.FeatureInfo.bIsDrillOpen, BeamData.MILL_OVERLAP, 0)
|
||||
else
|
||||
BestMilling.sDepth = Proc.FeatureInfo.dDrillLen - BestMilling.ToolInfo.dResidualDepth
|
||||
end
|
||||
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( BestMilling.ToolInfo)
|
||||
table.insert( Machining, BestMilling)
|
||||
end
|
||||
end
|
||||
|
||||
-- se c'è almeno una lavorazione, si calcola voto
|
||||
if #Machining > 0 then
|
||||
if dResidual < 0 then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.sInfo = ''
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'MILL')
|
||||
else
|
||||
Strategy.Result.sStatus = 'Not-Completed'
|
||||
local dResidualPrercentage = 100 * ( dResidual / Proc.FeatureInfo.dDrillLen)
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100 - dResidualPrercentage)
|
||||
Strategy.Result.sInfo = 'Machining not complete, left ' .. tostring( ceil( dResidualPrercentage)) .. '%'
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'MILL')
|
||||
end
|
||||
-- se son state trovate frese compatibili
|
||||
else
|
||||
local sMessage = 'Mill not found'
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( sMessage)
|
||||
end
|
||||
|
||||
return Machining, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0013.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri da default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machinings = {}
|
||||
Strategy.Result = {}
|
||||
|
||||
local bAreAllMachiningsAdded
|
||||
|
||||
Strategy.Machinings, Strategy.Result = GetDrillingWithMillStrategy( Proc, Part)
|
||||
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #Strategy.Machinings do
|
||||
local MachiningToAdd
|
||||
local nIndexTool = Strategy.Machinings[j].ToolInfo.nToolIndex
|
||||
-- se diametro fresa differisce al massimo della tolleranza si fa foratura con fresa (se ammesso)
|
||||
if abs( TOOLS[nIndexTool].dDiameter - Proc.FeatureInfo.dDrillDiam) < Strategy.Parameters.dDiameterTolerance and Strategy.Parameters.bUseMillAsDrill then
|
||||
MachiningToAdd = MachiningLib.InitMachiningParameters( MCH_MY.DRILLING)
|
||||
MachiningToAdd = BeamLib.MergeTables( MachiningToAdd, Strategy.Machinings[j])
|
||||
MachiningToAdd.Steps.dStep = TOOLS[nIndexTool].dStep / 3
|
||||
-- se diametro foro più grande della fresa, ma non oltre il doppio del diametro, si fa contornatura a spirale
|
||||
elseif Proc.FeatureInfo.dDrillDiam < ( TOOLS[nIndexTool].dDiameter * 0.75) * 2 or Strategy.Parameters.bOnlyContouring then
|
||||
MachiningToAdd = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
MachiningToAdd = BeamLib.MergeTables( MachiningToAdd, Strategy.Machinings[j])
|
||||
-- il diametro deve essere almeno 1mm più grande del foro, altrimenti la macchina non riesce ad interpolare
|
||||
MachiningToAdd.dRadialOffset = min( 0, Proc.FeatureInfo.dDrillDiam - ( TOOLS[nIndexTool].dDiameter + 1))
|
||||
MachiningToAdd.Steps.nStepType = MCH_MILL_ST.SPIRAL
|
||||
MachiningToAdd.Steps.dStep = TOOLS[nIndexTool].dStep / 3
|
||||
MachiningToAdd.LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
MachiningToAdd.LeadOut.dTangentDistance = 0.5
|
||||
MachiningToAdd.LeadOut.dPerpDistance = 0.5
|
||||
MachiningToAdd.LeadOut.dElevation = Proc.FeatureInfo.dDrillLen
|
||||
-- se diametro foro più grande del doppio del diametro fresa, si fa svuotatura
|
||||
else
|
||||
MachiningToAdd = MachiningLib.InitMachiningParameters( MCH_MY.POCKETING)
|
||||
MachiningToAdd = BeamLib.MergeTables( MachiningToAdd, Strategy.Machinings[j])
|
||||
MachiningToAdd.Steps.dStep = TOOLS[nIndexTool].dStep
|
||||
MachiningToAdd.Steps.dSideStep = TOOLS[nIndexTool].dSideStep
|
||||
MachiningToAdd.nSubType = MCH_POCK_SUB.SPIRALOUT
|
||||
MachiningToAdd.LeadIn.nType = MCH_POCK_LI.HELIX
|
||||
MachiningToAdd.LeadIn.dTangentDistance = TOOLS[nIndexTool].dDiameter / 2
|
||||
MachiningToAdd.LeadIn.dElevation = MachiningToAdd.Steps.dStep / 2
|
||||
end
|
||||
|
||||
MachiningToAdd.nToolIndex = nIndexTool
|
||||
MachiningToAdd.Geometry = {{ Proc.FeatureInfo.idAddAuxGeom, -1}}
|
||||
|
||||
if Proc.AffectedFaces.bLeft and not Proc.FeatureInfo.bIsDrillOpen then
|
||||
MachiningToAdd.sStage = 'AfterTail'
|
||||
end
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, MachiningToAdd)
|
||||
end
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0013
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"sStrategyId": "STR0014",
|
||||
"sStrategyName": "Marking",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dMachiningDepth",
|
||||
"sNameNge": "DEPTH",
|
||||
"sValue": "1",
|
||||
"sDescriptionShort": "Machining Depth",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "MARK_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine mark and text",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "tool",
|
||||
"sSubType": "MCH_TF.MILL",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sMarkStrategy",
|
||||
"sNameNge": "EXEC_MARK",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Marking Strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "PEN_FORCED",
|
||||
"sDescriptionShort": "Pen only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "VMILL_FORCED",
|
||||
"sDescriptionShort": "V-Mill only",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
-- Strategia: STR0014
|
||||
-- Descrizione
|
||||
-- Incisione con fresa
|
||||
-- Feature tipo Mark
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local ID = require( 'Identity')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0014 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetSCC( Machining)
|
||||
local nSCC
|
||||
|
||||
if TOOLS[Machining.nToolIndex].SetupInfo.bToolOnAggregate then
|
||||
nSCC = MCH_SCC.ADIR_NEAR
|
||||
elseif Machining.vtToolDirection:getY() <= 0 then
|
||||
nSCC = MCH_SCC.ADIR_YM
|
||||
else
|
||||
nSCC = MCH_SCC.ADIR_YP
|
||||
end
|
||||
|
||||
return nSCC
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
-- TODO rimuovere il calcolo MRR dove non serve, è fatto tutto alla fine.
|
||||
function STR0014.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Machining = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
Strategy.Result = {}
|
||||
Strategy.Result.dTimeToMachine = 0
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
local ToolSearchParameters = {}
|
||||
ToolSearchParameters.dElevation = 0
|
||||
ToolSearchParameters.vtToolDirection = Proc.FeatureInfo.vtExtr
|
||||
|
||||
if Strategy.Parameters.sMarkStrategy == 'AUTO' then
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'Milling')
|
||||
ToolSearchParameters.sMillShape = EgtIf( ID.IsMarking( Proc), 'VMILL', 'PEN')
|
||||
Strategy.Machining.ToolInfo = {}
|
||||
Strategy.Machining.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
-- se utensile non trovato, si cerca altro tipo di utensile compatibile per questi tipi di lavorazione
|
||||
if not Strategy.Machining.ToolInfo.nToolIndex then
|
||||
ToolSearchParameters.sMillShape = EgtIf( ID.IsMarking( Proc), 'PEN', 'VMILL')
|
||||
Strategy.Machining.ToolInfo = {}
|
||||
Strategy.Machining.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
end
|
||||
else
|
||||
if Strategy.Parameters.sMarkStrategy == 'PEN_FORCED' then
|
||||
ToolSearchParameters.sMillShape = 'PEN'
|
||||
elseif Strategy.Parameters.sMarkStrategy == 'VMILL_FORCED' then
|
||||
ToolSearchParameters.sMillShape = 'VMILL'
|
||||
end
|
||||
Strategy.Machining.ToolInfo = {}
|
||||
Strategy.Machining.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
end
|
||||
|
||||
if Strategy.Machining.ToolInfo.nToolIndex then
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( 100)
|
||||
local Parameters = { nToolIndex = Strategy.Machining.ToolInfo.nToolIndex}
|
||||
Strategy.Result.dMRR = MachiningLib.GetToolMRR( Parameters)
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'MILL')
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable()
|
||||
end
|
||||
|
||||
if Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
if bAddMachining then
|
||||
-- potrebbero esserci altre geometrie, si prepara già struttura con cloni
|
||||
Strategy.AuxiliaryData = {}
|
||||
Strategy.AuxiliaryData.Clones = {}
|
||||
Strategy.AuxiliaryData.Clones[1] = {}
|
||||
Strategy.AuxiliaryData.Clones[1].Geometry = {{ Proc.id, -1}}
|
||||
Strategy.Machining.Geometry = {{ Proc.id, -1}}
|
||||
Strategy.Machining.nToolIndex = Strategy.Machining.ToolInfo.nToolIndex
|
||||
Strategy.Machining.vtToolDirection = Proc.FeatureInfo.vtExtr
|
||||
|
||||
Strategy.Machining.nSCC = GetSCC( Strategy.Machining)
|
||||
|
||||
Strategy.Machining.nType = MCH_MY.MILLING
|
||||
Strategy.Machining.sDepth = EgtClamp( Strategy.Parameters.dMachiningDepth, -1, 5)
|
||||
Strategy.Machining.nWorkside = MCH_MILL_WS.CENTER
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Strategy.Machining.LeadIn = {}
|
||||
Strategy.Machining.LeadOut = {}
|
||||
Strategy.Machining.LeadIn.nType = MCH_MILL_LI.NONE
|
||||
Strategy.Machining.LeadOut.nType = MCH_MILL_LI.NONE
|
||||
|
||||
-- stessi parametri cambia solo al geometria
|
||||
for i = 1, #Proc.FeatureInfo.AdditionalGeometries do
|
||||
local AuxId = Proc.id + Proc.FeatureInfo.AdditionalGeometries[i]
|
||||
Strategy.AuxiliaryData.Clones[i+1] = {}
|
||||
Strategy.AuxiliaryData.Clones[i+1].Geometry = {{ AuxId, -1}}
|
||||
end
|
||||
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.Machining, Strategy.AuxiliaryData)
|
||||
end
|
||||
else
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0014
|
||||
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"sStrategyId": "STR0015",
|
||||
"sStrategyName": "Mill Heading",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dDepthChamfer",
|
||||
"sNameNge": "DEPTH_CHAMFER",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Depth Chamfer",
|
||||
"sDescriptionLong": "Depth of the V-Mill to execute chamfers on cut-edges",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bOnlyChamfer",
|
||||
"sNameNge": "ONLY_CHAMFER",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Only Chamfer",
|
||||
"sDescriptionLong": "Execute the chamfer only, no other machining",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dOverMaterial",
|
||||
"sNameNge": "OVERMAT",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Overmaterial",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxCornerRadius",
|
||||
"sNameNge": "MAX_CORNER_RADIUS",
|
||||
"sValue": "15",
|
||||
"sDescriptionShort": "Max radius left on corners",
|
||||
"sDescriptionLong": "Radius-limit left by the tool at each corner of the feature",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bExecRough",
|
||||
"sNameNge": "EXEC_ROUGH",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Execute cut to remove material",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bForceStrip",
|
||||
"sNameNge": "FORCE_STRIP",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Force strip",
|
||||
"sDescriptionLong": "Enable the parameter to force the software to leave a strip to sustain the piece",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dStripWidth",
|
||||
"sNameNge": "STRIP_WIDTH",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Strip width",
|
||||
"sDescriptionLong": "Width of the strip in case if foreseen from the machining",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "sConcaveFaceStrategy",
|
||||
"sNameNge": "CONCAVE_FACE",
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Cutting Strategy",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "combo",
|
||||
"sMinUserLevel": "1",
|
||||
"Choices": [
|
||||
{
|
||||
"sValue": "AUTO",
|
||||
"sDescriptionShort": "Automatic",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "NONE",
|
||||
"sDescriptionShort": "No machining",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "BLADE_FORCED",
|
||||
"sDescriptionShort": "Blade forced",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
},
|
||||
{
|
||||
"sValue": "MILL_FORCED",
|
||||
"sDescriptionShort": "Mill forced",
|
||||
"sDescriptionLong": "",
|
||||
"sMessageId": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sName": "sMillingList",
|
||||
"sNameNge": "PROFILE_TOOL_LIST",
|
||||
"sValue": "",
|
||||
"sDescriptionShort": "Available mill to machine the profile",
|
||||
"sDescriptionLong": "",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,881 @@
|
||||
-- Strategia: STR0015
|
||||
-- Descrizione
|
||||
-- Fresatura di contorno
|
||||
-- Feature tipo Profilo arcuato, Convesso, Concavo, Arco
|
||||
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local FaceData = require( 'FaceData')
|
||||
local ID = require( 'Identity')
|
||||
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
local FaceByBlade = require('FACEBYBLADE')
|
||||
local FaceByMill = require('FACEBYMILL')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local STR0015 = {}
|
||||
local Strategy = {}
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetEdgeToMachine( Proc, idFace, vtEdge)
|
||||
local Edge
|
||||
local dBestEdgeAngle = 999
|
||||
for i = 1, #Proc.Faces[idFace].Edges do
|
||||
local dAngle = abs( GetAngle( Proc.Faces[idFace].Edges[i].vtN, vtEdge) or 999)
|
||||
if dAngle < dBestEdgeAngle then
|
||||
dBestEdgeAngle = dAngle
|
||||
Edge = Proc.Faces[idFace].Edges[i]
|
||||
end
|
||||
end
|
||||
return Edge
|
||||
end
|
||||
|
||||
|
||||
-- TODO funzione recuperata da beam vecchio, verificare se possibile migliorare
|
||||
---------------------------------------------------------------------
|
||||
local function GetSawCutData( Proc, AuxId, vtNF, vtN)
|
||||
local ptStart, vtNP
|
||||
|
||||
if ID.IsHeadConcaveProfile( Proc) or ID.IsHeadConvexProfile( Proc) or ID.IsHeadProfile( Proc) or ID.IsFrontProfile( Proc) then
|
||||
vtNP = Vector3d( vtN)
|
||||
-- comincio con la normale a 45deg
|
||||
for i = 1, 3 do
|
||||
if vtNP[i] > GEO.EPS_SMALL then
|
||||
vtNP[i] = 1
|
||||
elseif vtNP[i] < -GEO.EPS_SMALL then
|
||||
vtNP[i] = -1
|
||||
end
|
||||
end
|
||||
vtNP:normalize()
|
||||
-- assegno un punto di passaggio
|
||||
ptStart = EgtMP( AuxId, GDB_ID.ROOT)
|
||||
local frOCS = Frame3d( ptStart, vtNP) ;
|
||||
local b3Box = EgtGetBBoxRef( AuxId, GDB_BB.STANDARD, frOCS)
|
||||
ptStart = ptStart + vtNP * ( b3Box:getMax():getZ() + 10.0)
|
||||
elseif ID.IsHeadCamberedProfile( Proc) then
|
||||
vtNP = Vector3d( vtNF)
|
||||
-- comincio con la normale a 45deg
|
||||
for i = 1, 3 do
|
||||
if vtNP[i] > GEO.EPS_SMALL then
|
||||
vtNP[i] = 1
|
||||
elseif vtNP[i] < -GEO.EPS_SMALL then
|
||||
vtNP[i] = -1
|
||||
end
|
||||
end
|
||||
vtNP:normalize()
|
||||
-- assegno un punto di passaggio
|
||||
ptStart = EgtSP( AuxId, GDB_ID.ROOT) + vtNP * 5.0
|
||||
-- determino asse di rotazione
|
||||
local vtRot = - Y_AX()
|
||||
if vtNF:getX() < 0 then vtRot = - vtRot end
|
||||
if vtNF:getZ() < -0.1 then
|
||||
vtRot = - vtRot
|
||||
elseif vtNF:getY() < -0.1 then
|
||||
vtRot:rotate( X_AX(), 90)
|
||||
elseif vtNF:getY() > 0.1 then
|
||||
vtRot:rotate( X_AX(), -90)
|
||||
end
|
||||
-- miglioro l'inclinazione (ripartendo da faccia perpendicolare asse trave)
|
||||
vtNP[2] = 0 vtNP[3] = 0
|
||||
local dRot = 45
|
||||
for i = 1, 4 do
|
||||
local vtNP2 = Vector3d( vtNP)
|
||||
vtNP2:rotate( vtRot, dRot)
|
||||
local frRef = Frame3d( ptStart, vtNP2)
|
||||
local b3Box = EgtGetBBoxRef( AuxId, GDB_BB.STANDARD, frRef)
|
||||
if b3Box:getMax():getZ() < -3 then
|
||||
vtNP = Vector3d( vtNP2)
|
||||
end
|
||||
dRot = dRot / 2
|
||||
end
|
||||
end
|
||||
-- restituisco i dati del piano
|
||||
return ptStart, vtNP
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetRoughStrategy( Proc, Part, bSaveAddedGeometries)
|
||||
local Machining = {}
|
||||
local Result = {}
|
||||
|
||||
-- ====== Taglio di sgrossatura generale su tutto il profilo ======
|
||||
local vtNF = EgtSurfTmFacetNormVersor( Proc.id, Proc.nFct-1, GDB_ID.ROOT)
|
||||
local nMidFacet = Proc.nFct // 2 -- faccia a metà circa
|
||||
local vtN = EgtSurfTmFacetNormVersor( Proc.id, nMidFacet, GDB_ID.ROOT)
|
||||
|
||||
local idAddGroup
|
||||
if bSaveAddedGeometries then
|
||||
idAddGroup = BeamLib.GetAddGroup( Part.id)
|
||||
else
|
||||
idAddGroup = Part.idTempGroup
|
||||
end
|
||||
-- aggiungo piano di sgrossatura e lo lavoro
|
||||
local ptStart, vtNP = GetSawCutData( Proc, Proc.idAddAuxGeom, vtNF, vtN)
|
||||
local AddId = EgtSurfTmPlaneInBBox( idAddGroup, ptStart, vtNP, Part.b3Part, GDB_RT.GLOB)
|
||||
-- se la faccia è stata creata
|
||||
if AddId then
|
||||
|
||||
-- creo piano di taglio sulla testa del tenone
|
||||
local OptionalParameters = { dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength,
|
||||
bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
}
|
||||
Machining, Result = BladeToWaste.Make( AddId, Part, OptionalParameters)
|
||||
|
||||
-- se non ci sono lavorazioni, provo con fresa
|
||||
if not Machining or #Machining == 0 then
|
||||
Machining.bCuttingWithMill = true
|
||||
-- === ricerca utensile per svuotare taglio iniziale, se taglio non possibile ===
|
||||
if not( Proc.AffectedFaces.bLeft) or Strategy.bCanMoveAfterSplit then
|
||||
ToolSearchParameters = {}
|
||||
|
||||
-- TODO SISTEMARE!!! qui la svuotatura non deve limitare l'elevazione se aperta da tutti i lati. In futuro si deve passare 0 come elevazione
|
||||
ToolSearchParameters.dElevation = EgtSurfTmFacetElevationInBBox( AddId, 0, Part.b3Part, true, GDB_ID.ROOT)
|
||||
|
||||
ToolSearchParameters.vtToolDirection = vtNP
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sPocketingList, 'Pocketing')
|
||||
Machining.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
|
||||
-- TODO anche il test sul ResidualDepth va tolto
|
||||
if Machining.ToolInfo.nToolIndex and ( Machining.ToolInfo.dResidualDepth < 10 * GEO.EPS_SMALL) then
|
||||
Machining.bIsApplicable = true
|
||||
local ParametersMRR = {}
|
||||
ParametersMRR.nToolIndex = Machining.ToolInfo.nToolIndex
|
||||
Result.dMRR = MachiningLib.GetToolMRR( ParametersMRR)
|
||||
Result.sStatus = 'Completed'
|
||||
Machining.Steps = {}
|
||||
Machining.LeadIn = {}
|
||||
Machining.nType = MCH_MY.POCKETING
|
||||
Machining.nSubType = MCH_POCK_SUB.SPIRALIN
|
||||
Machining.LeadIn.nType = MCH_POCK_LI.ZIGZAG
|
||||
Machining.Steps.dStep = TOOLS[Machining.ToolInfo.nToolIndex].dStep
|
||||
Machining.Steps.dSideStep = TOOLS[Machining.ToolInfo.nToolIndex].dSideStep
|
||||
Machining.nToolIndex = Machining.ToolInfo.nToolIndex
|
||||
Machining.LeadIn.dTangentDistance = TOOLS[Machining.ToolInfo.nToolIndex].dDiameter/2
|
||||
Machining.LeadIn.dElevation = TOOLS[Machining.ToolInfo.nToolIndex].dDiameter/2
|
||||
Machining.sDepth = 0
|
||||
Machining.Geometry = {{ AddId, 0}}
|
||||
Machining.vtToolDirection = vtNF
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Machining.sStage = 'AfterTail'
|
||||
end
|
||||
-- tempo di svuotatura
|
||||
Result.dTimeToMachine = MachiningLib.GetTimeToMachineAllStepsWithLeadInOut( Machining, Part)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Machining, Result
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetEdgeWithCornerStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
local Result = { dCompletionPercentage = 100}
|
||||
|
||||
local nFirstFacet = 0 -- faccia iniziale
|
||||
local nLastFacet = Proc.nFct - 1 -- faccia finale
|
||||
-- verifico se necessari ripassi agli estremi negli angoli
|
||||
local _, _, _, dFirstAng = EgtSurfTmFacetsContact( Proc.id, nFirstFacet, nFirstFacet + 1, GDB_ID.ROOT)
|
||||
local bFirstTrim = ( dFirstAng and dFirstAng < -30)
|
||||
local _, _, _, dLastAng = EgtSurfTmFacetsContact( Proc.id, nLastFacet, nLastFacet - 1, GDB_ID.ROOT)
|
||||
local bLastTrim = ( dLastAng and dLastAng < -30)
|
||||
local nMidFacet = ( nLastFacet + 1) // 2 -- faccia a metà circa
|
||||
local vtN = EgtSurfTmFacetNormVersor( Proc.id, nMidFacet, GDB_ID.ROOT)
|
||||
|
||||
|
||||
-- se non ci sono angoli da pulire si esce subito
|
||||
if Strategy.Parameters.sConcaveFaceStrategy == 'NONE' or ( not bFirstTrim and not bLastTrim) then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
local FacesToGet = {}
|
||||
if bFirstTrim then
|
||||
table.insert( FacesToGet, nFirstFacet)
|
||||
table.insert( FacesToGet, nFirstFacet+1)
|
||||
end
|
||||
if bLastTrim then
|
||||
table.insert( FacesToGet, nLastFacet - 1)
|
||||
table.insert( FacesToGet, nLastFacet)
|
||||
end
|
||||
-- ricavo info facce da lavorare
|
||||
Proc.Faces = FaceData.GetFacesInfo( Proc, Part, FacesToGet)
|
||||
|
||||
-- direzioni di lavorazione
|
||||
local vtCutDir1
|
||||
-- se è diretta verso alto o basso
|
||||
if abs( vtN:getZ()) > abs( vtN:getY()) then
|
||||
if vtN:getZ() > 0 then
|
||||
vtCutDir1 = Z_AX()
|
||||
else
|
||||
vtCutDir1 = -Z_AX()
|
||||
end
|
||||
-- altrimenti è di fianco
|
||||
else
|
||||
if vtN:getY() > 0 then
|
||||
vtCutDir1 = Y_AX()
|
||||
else
|
||||
vtCutDir1 = -Y_AX()
|
||||
end
|
||||
end
|
||||
|
||||
local vtCutDir2
|
||||
if vtN:getX() > 0 then
|
||||
vtCutDir2 = X_AX()
|
||||
else
|
||||
vtCutDir2 = -X_AX()
|
||||
end
|
||||
|
||||
local nMachiningsToAdd
|
||||
|
||||
-- AUTO = preferisce lama. Se non è possibile prende fresa
|
||||
-- BLADE_FORCED = solo lama, altriemnti non applica nulla (potrebbe essere necessario un ribaltamento)
|
||||
-- MILL_FORCED = solo fresa, altriemnti non applica nulla (potrebbe essere necessario un ribaltamento)
|
||||
if Strategy.Parameters.sConcaveFaceStrategy == 'AUTO' or Strategy.Parameters.sConcaveFaceStrategy == 'BLADE_FORCED' then
|
||||
|
||||
nMachiningsToAdd = 0
|
||||
|
||||
-- TODO c'è una funzione che ritorni l'edge di connessione tra una faccia e un'altra?
|
||||
-- lavorazione faccia 1 spigolo finale
|
||||
if bLastTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nLastFacet+1, vtCutDir1)
|
||||
local Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nLastFacet+1], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 1 spigolo iniziale
|
||||
if bFirstTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nFirstFacet+2, vtCutDir1)
|
||||
local Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nFirstFacet+2], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Cutting.sStage = 'AfterTail'
|
||||
end
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 2 spigolo finale
|
||||
if bLastTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
EdgeToMachine = GetEdgeToMachine( Proc, nLastFacet, vtCutDir2)
|
||||
Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nLastFacet], EdgeToMachine)
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 2 spigolo iniziale
|
||||
if bFirstTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nFirstFacet+1, vtCutDir2)
|
||||
local Cutting = FaceByBlade.Make( Proc, Part, Proc.Faces[nFirstFacet+1], EdgeToMachine)
|
||||
if Cutting.bIsApplicable then
|
||||
table.insert( Machining, Cutting)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- se non ci sono lavorazioni provo a pulire spigoli con fresa, a patto che non sia stato forzato con lama
|
||||
if ( not nMachiningsToAdd or ( #Machining < nMachiningsToAdd)) and Strategy.Parameters.sConcaveFaceStrategy ~= 'BLADE_FORCED' then
|
||||
|
||||
Machining = {}
|
||||
nMachiningsToAdd = 0
|
||||
|
||||
-- TODO c'è una funzione che ritorni l'edge di connessione tra una faccia e un'altra?
|
||||
-- lavorazione faccia 1 spigolo iniziale
|
||||
if bFirstTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
local EdgeToMachine = GetEdgeToMachine( Proc, nFirstFacet+2, vtCutDir1)
|
||||
local Milling = FaceByMill.Make( Proc, Part, Proc.Faces[nFirstFacet+2], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Milling.sStage = 'AfterTail'
|
||||
end
|
||||
if Milling.bIsApplicable then
|
||||
table.insert( Machining, Milling)
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione faccia 2 spigolo finale
|
||||
if bLastTrim then
|
||||
nMachiningsToAdd = nMachiningsToAdd + 1
|
||||
EdgeToMachine = GetEdgeToMachine( Proc, nLastFacet, vtCutDir2)
|
||||
local Milling = FaceByMill.Make( Proc, Part, Proc.Faces[nLastFacet], EdgeToMachine)
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Milling.sStage = 'AfterTail'
|
||||
end
|
||||
if Milling.bIsApplicable then
|
||||
table.insert( Machining, Milling)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if nMachiningsToAdd and ( #Machining < nMachiningsToAdd) then
|
||||
Result = { dCompletionPercentage = ( #Machining / nMachiningsToAdd)}
|
||||
end
|
||||
|
||||
return Machining, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetChamferStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
local Result = {}
|
||||
local ToolSearchParameters = {}
|
||||
local dExtraDepth = 2
|
||||
local vtExtr = EgtCurveExtrusion( Proc.idAddAuxGeom, GDB_RT.GLOB)
|
||||
local bIsHorizontal = abs( vtExtr:getZ()) < 10 * GEO.EPS_SMALL
|
||||
local bToolInvert = ( vtExtr:getZ() < -0.1)
|
||||
|
||||
if Strategy.Parameters.dDepthChamfer > 100 * GEO.EPS_SMALL then
|
||||
-- controllo conformità affondamento smussi
|
||||
Strategy.Parameters.dDepthChamfer = EgtClamp( Strategy.Parameters.dDepthChamfer, 0.1, 5)
|
||||
|
||||
-- si prapara tabella con parametri di base comuni a tutte le lavorazioni
|
||||
local BasicMach = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
BasicMach.Geometry = {{ Proc.idAddAuxGeom, -1}}
|
||||
BasicMach.nType = MCH_MY.MILLING
|
||||
BasicMach.sDepth = Strategy.Parameters.dDepthChamfer + dExtraDepth
|
||||
-- LeadIn / LeadOut
|
||||
BasicMach.LeadIn.nType = MCH_MILL_LI.NONE
|
||||
BasicMach.LeadOut.nType = MCH_MILL_LI.NONE
|
||||
BasicMach.LeadIn.dStartAddLength = 5
|
||||
BasicMach.LeadOut.dEndAddLength = 5
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
BasicMach.sStage = 'AfterTail'
|
||||
end
|
||||
BasicMach.ptEdge1 = EgtSP( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
BasicMach.ptEdge2 = EgtEP( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
BasicMach.dEdgeLength = EgtCurveLength( Proc.idAddAuxGeom)
|
||||
BasicMach.vtEdgeDirection = EgtSV( Proc.idAddAuxGeom, GDB_ID.ROOT) + EgtMV( Proc.idAddAuxGeom, GDB_ID.ROOT) + EgtEV( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
BasicMach.dLengthOnX = Proc.b3Box:getDimX()
|
||||
-- parametri di ricerca utensile comuni a tutte le lavorazioni
|
||||
ToolSearchParameters.sMillShape = 'VMILL'
|
||||
ToolSearchParameters.dElevation = Strategy.Parameters.dDepthChamfer
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, 'MillingSmooth')
|
||||
|
||||
-- se lavorazione orizzontale
|
||||
if bIsHorizontal then
|
||||
local Milling = {}
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, -vtExtr, vtExtr)
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
-- se trovato utensile adatto
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
Milling.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
|
||||
Milling.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dRadialOffset = dExtraDepth * cos( TOOLS[Milling.nToolIndex].dSideAngle)
|
||||
|
||||
Milling.bInvert = EgtIf( TOOLS[Milling.nToolIndex].bIsCCW, false, true)
|
||||
Milling.nWorkside = EgtIf( TOOLS[Milling.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
Milling = BeamLib.MergeTables( BasicMach, Milling)
|
||||
table.insert( Machining, Milling)
|
||||
|
||||
local Milling2 = BeamLib.TableCopyDeep( Milling)
|
||||
Milling2.bToolInvert = true
|
||||
Milling2.bInvert = EgtIf( TOOLS[Milling2.nToolIndex].bIsCCW, true, false)
|
||||
Milling2.nWorkside = EgtIf( TOOLS[Milling2.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
|
||||
table.insert( Machining, Milling2)
|
||||
end
|
||||
-- se lavorazione verticale
|
||||
else
|
||||
-- si cerca utensile 1
|
||||
local Milling = {}
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, -vtExtr, vtExtr)
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
Milling.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
|
||||
-- si cerca utensile 2
|
||||
local Milling2 = {}
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, vtExtr, -vtExtr)
|
||||
Milling2.ToolInfo = {}
|
||||
Milling2.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
Milling2.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
Milling2.bToolInvert = true
|
||||
|
||||
-- se trovato utensile 1 adatto
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
|
||||
Milling.nToolIndex = Milling.ToolInfo.nToolIndex
|
||||
Milling.dRadialOffset = dExtraDepth * cos( TOOLS[Milling.nToolIndex].dSideAngle)
|
||||
|
||||
Milling.bInvert = EgtIf( TOOLS[Milling.nToolIndex].bIsCCW, false, true)
|
||||
Milling.nWorkside = EgtIf( TOOLS[Milling.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
Milling = BeamLib.MergeTables( BasicMach, Milling)
|
||||
table.insert( Machining, Milling)
|
||||
end
|
||||
|
||||
-- se trovato utensile 2 adatto
|
||||
if Milling2.ToolInfo.nToolIndex then
|
||||
|
||||
Milling2.nToolIndex = Milling2.ToolInfo.nToolIndex
|
||||
Milling2.dRadialOffset = dExtraDepth * cos( TOOLS[Milling2.nToolIndex].dSideAngle)
|
||||
|
||||
Milling2.bToolInvert = true
|
||||
Milling2.bInvert = EgtIf( TOOLS[Milling2.nToolIndex].bIsCCW, true, false)
|
||||
Milling2.nWorkside = EgtIf( TOOLS[Milling2.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
Milling2 = BeamLib.MergeTables( BasicMach, Milling2)
|
||||
table.insert( Machining, Milling2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Machining, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetArcStrategy( Proc, Part)
|
||||
local Machining = {}
|
||||
local Result = { dCompletionPercentage = 100}
|
||||
local ToolSearchParameters = {}
|
||||
|
||||
-- recupero i dati della curva e del profilo
|
||||
local dDepth = abs( EgtCurveThickness( Proc.idAddAuxGeom))
|
||||
local vtExtr = EgtCurveExtrusion( Proc.idAddAuxGeom, GDB_RT.GLOB)
|
||||
local bToolInvert = ( vtExtr:getZ() < -0.1)
|
||||
local bIsHorizontal = abs( vtExtr:getZ()) < 10 * GEO.EPS_SMALL
|
||||
local bIsFeatureDown = Proc.AffectedFaces.bBottom and not Proc.AffectedFaces.bTop
|
||||
local bIsFeatureBack = Proc.AffectedFaces.bBack and not Proc.AffectedFaces.bFront
|
||||
local bForceStrip = Strategy.Parameters.bForceStrip
|
||||
local dDimStrip = EgtIf( Strategy.Parameters.dStripWidth < 100 * GEO.EPS_SMALL, nil, Strategy.Parameters.dStripWidth)
|
||||
local sMaxDepth = dDepth * 2
|
||||
|
||||
local bExecStrip = false
|
||||
-- se la lavorazione si trova nella parte inferiore o in battuta dietro, il codolo va sempre lasciato
|
||||
if ID.IsRoundArch( Proc) and ( bIsFeatureDown or bIsFeatureBack or bForceStrip) then
|
||||
if bIsFeatureDown or bIsFeatureBack then
|
||||
dDimStrip = dDimStrip or max( BeamData.DIM_STRIP or 5, 5)
|
||||
else
|
||||
dDimStrip = dDimStrip or max( BeamData.DIM_STRIP_SMALL or 5, 1)
|
||||
end
|
||||
bExecStrip = true
|
||||
end
|
||||
if not bExecStrip then
|
||||
dDimStrip = 0
|
||||
end
|
||||
|
||||
-- la passata di finitura c'è sempre
|
||||
local nPassages = 1
|
||||
-- si verifica se fare passaggio di sgrossatura con fresa
|
||||
if not bExecStrip and Strategy.Parameters.dOverMaterial > 100 * GEO.EPS_SMALL then
|
||||
nPassages = 2
|
||||
end
|
||||
|
||||
-- ciclo su numero passate (2 in caso di sgrossatura + finitura)
|
||||
for nCycle = nPassages, 1, -1 do
|
||||
local nMaxDiamMill = EgtIf( nCycle == 1, Strategy.Parameters.dMaxCornerRadius * 2, nil)
|
||||
local sTypeTool = EgtIf( nCycle == 1 and nPassages == 2, 'MillingFinish', 'Milling')
|
||||
-- se lavorazione orizzontale
|
||||
if bIsHorizontal then
|
||||
local bDouble
|
||||
local Milling = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.dElevation = EgtIf( bExecStrip, ( dDepth - dDimStrip) / 2, dDepth + BeamData.MILL_OVERLAP)
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, -vtExtr, vtExtr)
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, sTypeTool)
|
||||
ToolSearchParameters.dMaxToolDiameter = nMaxDiamMill
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
-- se posso lavorare in una passata, ma utensile trovato non completa la lavorazione,
|
||||
-- allora provo a cercare utensile con massimo materiale sufficiente per fare le due passate, magari trova un utensile più prestante
|
||||
if Milling.ToolInfo.nToolIndex then
|
||||
if Milling.ToolInfo.dResidualDepth > 10 * GEO.EPS_SMALL and not bExecStrip then
|
||||
bDouble = true
|
||||
ToolSearchParameters.dElevation = ( dDepth + BeamData.MILL_OVERLAP) / 2
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
end
|
||||
Milling.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
|
||||
if nCycle == 2 then
|
||||
Milling.dRadialOffset = Strategy.Parameters.dOverMaterial
|
||||
end
|
||||
|
||||
-- se non completo
|
||||
if Milling.ToolInfo.dResidualDepth > 10 * GEO.EPS_SMALL then
|
||||
sMaxDepth = ToolSearchParameters.dElevation - Milling.ToolInfo.dResidualDepth
|
||||
-- si salva percentuala lavorata
|
||||
Result.dCompletionPercentage = 100 - ceil( ( Milling.ToolInfo.dResidualDepth / ToolSearchParameters.dElevation) * 100)
|
||||
end
|
||||
if bDouble or bExecStrip then
|
||||
if bDouble then
|
||||
Milling.sDepth = min( sMaxDepth, ( dDepth + BeamData.MILL_OVERLAP) / 2)
|
||||
else
|
||||
Milling.sDepth = min( sMaxDepth, ( dDepth - dDimStrip) / 2)
|
||||
end
|
||||
table.insert( Machining, Milling)
|
||||
local Milling2 = BeamLib.TableCopyDeep( Milling)
|
||||
Milling2.bOtherDirection = true
|
||||
table.insert( Machining, Milling2)
|
||||
else
|
||||
Milling.sDepth = min( sMaxDepth, dDepth + BeamData.MILL_OVERLAP)
|
||||
table.insert( Machining, Milling)
|
||||
end
|
||||
end
|
||||
-- se lavorazione verticale
|
||||
else
|
||||
ToolSearchParameters = {}
|
||||
ToolSearchParameters.sMillShape = 'STANDARD'
|
||||
ToolSearchParameters.dElevation = dDepth + BeamData.MILL_OVERLAP
|
||||
ToolSearchParameters.AvailableToolList = MachiningLib.GetAvailableToolList( Proc, Strategy.Parameters.sMillingList, sTypeTool)
|
||||
ToolSearchParameters.dMaxToolDiameter = nMaxDiamMill
|
||||
|
||||
-- si cerca utensile 1
|
||||
local Milling = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, -vtExtr, vtExtr)
|
||||
Milling.ToolInfo = {}
|
||||
Milling.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if nCycle == 2 then
|
||||
Milling.dRadialOffset = Strategy.Parameters.dOverMaterial
|
||||
end
|
||||
Milling.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
Milling.bOtherDirection = bToolInvert
|
||||
|
||||
|
||||
-- si cerca utensile 2
|
||||
local Milling2 = MachiningLib.InitMachiningParameters( MCH_MY.MILLING)
|
||||
ToolSearchParameters.vtToolDirection = EgtIf( bToolInvert, vtExtr, -vtExtr)
|
||||
Milling2.ToolInfo = {}
|
||||
Milling2.ToolInfo = MachiningLib.FindMill( Proc, ToolSearchParameters)
|
||||
if nCycle == 2 then
|
||||
Milling2.dRadialOffset = Strategy.Parameters.dOverMaterial
|
||||
end
|
||||
Milling2.vtToolDirection = ToolSearchParameters.vtToolDirection
|
||||
Milling2.bOtherDirection = bToolInvert
|
||||
|
||||
-- se serve codolo
|
||||
if bExecStrip then
|
||||
local sDepthMachined = 0
|
||||
-- se a disposizione entrambi gli utensili
|
||||
if Milling.ToolInfo.nToolIndex and Milling2.ToolInfo.nToolIndex then
|
||||
local dExtraDepth = ( dDepth - dDimStrip - ( Milling.ToolInfo.dResidualDepth + Milling2.ToolInfo.dResidualDepth)) / 2
|
||||
Milling.sDepth = dDepth - Milling.ToolInfo.dResidualDepth - dExtraDepth
|
||||
Milling2.sDepth = dDepth - Milling2.ToolInfo.dResidualDepth - dExtraDepth
|
||||
sDepthMachined = Milling.sDepth + Milling2.sDepth
|
||||
table.insert( Machining, Milling)
|
||||
table.insert( Machining, Milling2)
|
||||
-- se disponibile solo primo utensile
|
||||
elseif Milling.ToolInfo.nToolIndex then
|
||||
sMaxDepth = ToolSearchParameters.dElevation - Milling.ToolInfo.dResidualDepth
|
||||
Milling.sDepth = min( sMaxDepth, dDepth - dDimStrip)
|
||||
table.insert( Machining, Milling)
|
||||
sDepthMachined = Milling.sDepth
|
||||
-- se disponibile solo secondo utensile
|
||||
elseif Milling2.ToolInfo.nToolIndex then
|
||||
sMaxDepth = ToolSearchParameters.dElevation - Milling2.ToolInfo.dResidualDepth
|
||||
Milling2.sDepth = min( sMaxDepth, dDepth - dDimStrip)
|
||||
table.insert( Machining, Milling2)
|
||||
sDepthMachined = Milling2.sDepth
|
||||
-- nessun utensile disponibile
|
||||
else
|
||||
-- non si fa nulla
|
||||
end
|
||||
Result.dCompletionPercentage = min( ( sDepthMachined * 100) / ( dDepth - dDimStrip), 100)
|
||||
-- altrimenti senza codolo
|
||||
else
|
||||
local sDepthMachined = 0
|
||||
local dExtraDepth = ( dDepth - BeamData.MILL_OVERLAP - ( Milling.ToolInfo.dResidualDepth + Milling2.ToolInfo.dResidualDepth)) / 2
|
||||
-- se utensile 1 esegue completamente (con almeno 1mm extra)
|
||||
if Milling.ToolInfo.nToolIndex and Milling.ToolInfo.dResidualDepth < 1000 * GEO.EPS_SMALL then
|
||||
sMaxDepth = ToolSearchParameters.dElevation - Milling.ToolInfo.dResidualDepth
|
||||
Milling.sDepth = min( sMaxDepth, dDepth + BeamData.MILL_OVERLAP)
|
||||
table.insert( Machining, Milling)
|
||||
sDepthMachined = Milling.sDepth
|
||||
-- se utensile 2 esegue completamente (con almeno 1mm extra)
|
||||
elseif Milling2.ToolInfo.nToolIndex and Milling2.ToolInfo.dResidualDepth < 1000 * GEO.EPS_SMALL then
|
||||
sMaxDepth = ToolSearchParameters.dElevation - Milling2.ToolInfo.dResidualDepth
|
||||
Milling2.sDepth = min( sMaxDepth, dDepth + BeamData.MILL_OVERLAP)
|
||||
table.insert( Machining, Milling2)
|
||||
sDepthMachined = Milling2.sDepth
|
||||
-- se possono lavorare entrambi
|
||||
elseif Milling.ToolInfo.nToolIndex and Milling2.ToolInfo.nToolIndex then
|
||||
Milling.sDepth = dDepth - Milling.ToolInfo.dResidualDepth - dExtraDepth
|
||||
Milling2.sDepth = dDepth - Milling2.ToolInfo.dResidualDepth - dExtraDepth
|
||||
table.insert( Machining, Milling)
|
||||
table.insert( Machining, Milling2)
|
||||
sDepthMachined = Milling.sDepth + Milling2.sDepth
|
||||
-- se utensile 1 non completo
|
||||
elseif Milling.ToolInfo.nToolIndex then
|
||||
Milling.sDepth = ToolSearchParameters.dElevation - Milling.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Milling)
|
||||
sDepthMachined = Milling.sDepth
|
||||
-- se utensile 2 non completo
|
||||
elseif Milling2.ToolInfo.nToolIndex then
|
||||
Milling2.sDepth = ToolSearchParameters.dElevation - Milling2.ToolInfo.dResidualDepth
|
||||
table.insert( Machining, Milling2)
|
||||
sDepthMachined = Milling2.sDepth
|
||||
end
|
||||
Result.dCompletionPercentage = min( ( sDepthMachined * 100) / ( dDepth - dDimStrip), 100)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Machining.bIsApplicable = #Machining > 0
|
||||
|
||||
return Machining, Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function GetFeatureResult( Proc)
|
||||
local Result = { sStatus = 'Completed', dCompletionPercentage = 100, sInfo = ''}
|
||||
local dPercentageChamfer = 10
|
||||
local dPercentageEdgeCorner = 10
|
||||
local dPercentageProfile = 80
|
||||
|
||||
-- se non ci sono lavorazioni di smusso
|
||||
if not Strategy.Chamfer.Machinings or #Strategy.Chamfer.Machinings < 2 then
|
||||
-- se esclusivo, non applicabile
|
||||
if Strategy.Parameters.bOnlyChamfer then
|
||||
Result = FeatureLib.GetStrategyResultNotApplicable( 'Not possible to machine chamfer only, tool not found!')
|
||||
Result.dCompletionPercentage = 0
|
||||
-- se non esclusivo, non completo
|
||||
elseif Strategy.Parameters.dDepthChamfer > 100 * GEO.EPS_SMALL then
|
||||
Result.dCompletionPercentage = Result.dCompletionPercentage - dPercentageChamfer -- gli smussi incidono per il 10%
|
||||
dPercentageChamfer = 0
|
||||
Result.sInfo = '- Chamfer not executed, tool not found!\n'
|
||||
end
|
||||
end
|
||||
|
||||
-- se richieste anche le altre lavorazioni
|
||||
if not Strategy.Parameters.bOnlyChamfer then
|
||||
-- per tutti tranne che per feature RoundArc
|
||||
if not ID.IsRoundArch( Proc) and not ID.IsFreeContour( Proc) then
|
||||
-- se sgrossatura da eseguire
|
||||
if Strategy.Parameters.bExecRough then
|
||||
if not Strategy.RoughCut.Machinings or #Strategy.RoughCut.Machinings == 0 then
|
||||
Result.dCompletionPercentage = Result.dCompletionPercentage -- non incide sulla percentuale lavorata, solo messaggio che manca
|
||||
Result.sInfo = Result.sInfo .. '- Roughing not executed\n'
|
||||
end
|
||||
end
|
||||
-- se lavorazioni corner
|
||||
if Strategy.EdgeWithCorner.Machinings and #Strategy.EdgeWithCorner.Machinings == 0 then
|
||||
Result.dCompletionPercentage = Result.dCompletionPercentage - dPercentageEdgeCorner -- la pulizia dei corner incide per il 10%
|
||||
dPercentageEdgeCorner = 0
|
||||
Result.sInfo = Result.sInfo .. '- Corner not executed, material left\n'
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione del profilo
|
||||
if not Strategy.Profile.Machinings or #Strategy.Profile.Machinings == 0 then
|
||||
Result.sInfo = Result.sInfo .. '- Profile not executed, tool not found!\n'
|
||||
else
|
||||
local dTotalPercentage = dPercentageProfile + dPercentageEdgeCorner + dPercentageChamfer
|
||||
Result.dCompletionPercentage = Result.dCompletionPercentage - ( ( ( 100 - Strategy.Profile.Result.dCompletionPercentage) * dTotalPercentage) / 100)
|
||||
end
|
||||
end
|
||||
|
||||
-- si setta lo stato in base alla percentuale di completamento
|
||||
if Result.dCompletionPercentage == 100 then
|
||||
Result.sStatus = "Completed"
|
||||
elseif Result.dCompletionPercentage == 0 then
|
||||
Result.sStatus = "Not-Applicable"
|
||||
else
|
||||
Result.sStatus = "Not-Completed"
|
||||
local dPercentageLeft = ceil( 100 - Result.dCompletionPercentage)
|
||||
Result.sInfo = Result.sInfo .. '- Not Complete : left ' .. tostring( dPercentageLeft) .. '%\n'
|
||||
end
|
||||
Result.dCompletionIndex = FeatureLib.GetFeatureCompletionIndex( Result.dCompletionPercentage)
|
||||
Result.dMRR = 1
|
||||
-- se tutte le lavorazioni sono state eseguite, è la massima qualità che si possa ottenere, altrimenti qualità più bassa
|
||||
if Result.sInfo == '' then
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'BEST')
|
||||
else
|
||||
Result.dQuality = FeatureLib.GetStrategyQuality( 'MILL')
|
||||
end
|
||||
|
||||
return Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function STR0015.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
-- carico parametri de default e li aggiorno con quelli passati dal chiamante (potrebbero non essere congruenti)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.Chamfer = {}
|
||||
Strategy.Chamfer.Machinings = {}
|
||||
Strategy.Chamfer.Result = {}
|
||||
Strategy.Result = {}
|
||||
|
||||
local bAreAllMachiningsAdded = true
|
||||
|
||||
-- verifico se la lavorazione può essere spostata dopo taglio di coda
|
||||
local dLengthOnX = Proc.b3Box:getDimX()
|
||||
Strategy.bCanMoveAfterSplit = MachiningLib.CanMoveAfterSplitcut( dLengthOnX, Part)
|
||||
|
||||
-- recupero e verifico l'entità curva
|
||||
local idAux = EgtGetInfo( Proc.id, 'AUXID', 'i')
|
||||
if idAux then idAux = idAux + Proc.id end
|
||||
if not idAux or ( EgtGetType( idAux) & GDB_FY.GEO_CURVE) == 0 then
|
||||
local sErr = 'Error on process ' .. tostring( Proc.id) .. ' missing profile geometry'
|
||||
EgtOutLog( sErr)
|
||||
return false, sErr
|
||||
end
|
||||
Proc.idAddAuxGeom = idAux
|
||||
|
||||
-- lavorazione smussi
|
||||
Strategy.Chamfer.Machinings, Strategy.Chamfer.Result = GetChamferStrategy( Proc, Part)
|
||||
|
||||
-- se non bisogna fare solo gli smussi, si calcolano le altre lavorazioni
|
||||
if not Strategy.Parameters.bOnlyChamfer then
|
||||
-- per tutti tranne che per feature RoundArc
|
||||
if not ID.IsRoundArch( Proc) and not ID.IsFreeContour( Proc) then
|
||||
-- lavorazione taglio per sgrossare
|
||||
if Strategy.Parameters.bExecRough then
|
||||
Strategy.RoughCut = {}
|
||||
Strategy.RoughCut.Machinings = {}
|
||||
Strategy.RoughCut.Result = {}
|
||||
Strategy.RoughCut.Machinings, Strategy.RoughCut.Result = GetRoughStrategy( Proc, Part, bAddMachining)
|
||||
end
|
||||
-- lavorazione degli estremi con angoli interni
|
||||
Strategy.EdgeWithCorner = {}
|
||||
Strategy.EdgeWithCorner.Machinings = {}
|
||||
Strategy.EdgeWithCorner.Result = {}
|
||||
Strategy.EdgeWithCorner.Machinings, Strategy.EdgeWithCorner.Result = GetEdgeWithCornerStrategy( Proc, Part)
|
||||
end
|
||||
|
||||
-- lavorazione profilo (a meno che non si facciano solo smussi)
|
||||
Strategy.Profile = {}
|
||||
Strategy.Profile.Machinings = {}
|
||||
Strategy.Profile.Result = {}
|
||||
Strategy.Profile.Machinings, Strategy.Profile.Result = GetArcStrategy( Proc, Part)
|
||||
end
|
||||
|
||||
Strategy.Result = GetFeatureResult( Proc)
|
||||
|
||||
if bAddMachining and Strategy.Result.sStatus ~= 'Not-Applicable' then
|
||||
-- eventuali punti di spezzatura
|
||||
local FeatureSplittingPoints = FeatureLib.GetFeatureSplittingPoints( Proc, Part)
|
||||
|
||||
-- lavorazione degli smussi
|
||||
if Strategy.Chamfer.Machinings then
|
||||
for i = 1, #Strategy.Chamfer.Machinings do
|
||||
local MachiningToSplit = {}
|
||||
table.insert( MachiningToSplit, Strategy.Chamfer.Machinings[i])
|
||||
local MachiningResult = MachiningLib.GetSplitMachinings( MachiningToSplit, FeatureSplittingPoints, Part)
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #MachiningResult do
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, MachiningResult[j])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- per tutti tranne che per feature RoundArc
|
||||
if not ID.IsRoundArch( Proc) and not ID.IsFreeContour( Proc) then
|
||||
-- lavorazione di sgrezzatura di lama
|
||||
if Strategy.Parameters.bExecRough and Strategy.RoughCut.Machinings then
|
||||
-- se cutting da fare come svuotatura
|
||||
if Strategy.RoughCut.Machinings.bCuttingWithMill then
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, Strategy.RoughCut.Machinings)
|
||||
-- taglio di lama
|
||||
else
|
||||
for i = 1, #Strategy.RoughCut.Machinings do
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.RoughCut.Machinings[i].sStage = 'AfterTail'
|
||||
end
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Strategy.RoughCut.Machinings[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- lavorazione degli angoli interni
|
||||
if Strategy.EdgeWithCorner.Machinings then
|
||||
for i = 1, #Strategy.EdgeWithCorner.Machinings do
|
||||
local bIsMachiningAdded = MachiningLib.AddMachinings( Proc, Strategy.EdgeWithCorner.Machinings[i])
|
||||
if not bIsMachiningAdded then
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- lavorazione del profilo
|
||||
if Strategy.Profile.Machinings then
|
||||
for i = 1, #Strategy.Profile.Machinings do
|
||||
|
||||
Strategy.Profile.Machinings[i].Geometry = {{ Proc.idAddAuxGeom, -1}}
|
||||
Strategy.Profile.Machinings[i].nToolIndex = Strategy.Profile.Machinings[i].ToolInfo.nToolIndex
|
||||
Strategy.Profile.Machinings[i].nType = MCH_MY.MILLING
|
||||
Strategy.Profile.Machinings[i].Steps = MachiningLib.GetMachiningSteps( false, tonumber( Strategy.Profile.Machinings[i].sDepth), TOOLS[Strategy.Profile.Machinings[i].nToolIndex].dStep)
|
||||
Strategy.Profile.Machinings[i].Steps.nStepType = MCH_MILL_ST.ONEWAY
|
||||
|
||||
-- LeadIn / LeadOut
|
||||
Strategy.Profile.Machinings[i].LeadIn.nType = MCH_MILL_LI.TANGENT
|
||||
Strategy.Profile.Machinings[i].LeadOut.nType = MCH_MILL_LI.TANGENT
|
||||
Strategy.Profile.Machinings[i].LeadIn.dTangentDistance = TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Profile.Machinings[i].LeadIn.dPerpDistance = 0
|
||||
Strategy.Profile.Machinings[i].LeadIn.dStartAddLength = 0
|
||||
Strategy.Profile.Machinings[i].LeadOut.dTangentDistance = TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Profile.Machinings[i].LeadOut.dPerpDistance = 0
|
||||
Strategy.Profile.Machinings[i].LeadOut.dEndAddLength = 0
|
||||
|
||||
if Proc.AffectedFaces.bLeft and Strategy.bCanMoveAfterSplit then
|
||||
Strategy.Profile.Machinings[i].sStage = 'AfterTail'
|
||||
end
|
||||
|
||||
-- preparo attacco/uscita in caso di spezzatura arco
|
||||
Strategy.Profile.Machinings[i].LeadInForSplit = BeamLib.TableCopyDeep( Strategy.Profile.Machinings[i].LeadIn)
|
||||
Strategy.Profile.Machinings[i].LeadOutForSplit = BeamLib.TableCopyDeep( Strategy.Profile.Machinings[i].LeadOut)
|
||||
Strategy.Profile.Machinings[i].LeadInForSplit.nType = MCH_MILL_LI.LINEAR
|
||||
Strategy.Profile.Machinings[i].LeadOutForSplit.nType = MCH_MILL_LI.LINEAR
|
||||
Strategy.Profile.Machinings[i].LeadInForSplit.dTangentDistance = 0
|
||||
Strategy.Profile.Machinings[i].LeadInForSplit.dPerpDistance = TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
Strategy.Profile.Machinings[i].LeadOutForSplit.dTangentDistance = 0
|
||||
Strategy.Profile.Machinings[i].LeadOutForSplit.dPerpDistance = TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].dDiameter / 2 + BeamData.COLL_SIC
|
||||
|
||||
-- sistemo il lato e la direzione di lavoro
|
||||
if Strategy.Profile.Machinings[i].bOtherDirection then
|
||||
Strategy.Profile.Machinings[i].bToolInvert = true
|
||||
Strategy.Profile.Machinings[i].bInvert = EgtIf( TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].bIsCCW, true, false)
|
||||
Strategy.Profile.Machinings[i].nWorkside = EgtIf( TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
else
|
||||
Strategy.Profile.Machinings[i].bInvert = EgtIf( TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].bIsCCW, false, true)
|
||||
Strategy.Profile.Machinings[i].nWorkside = EgtIf( TOOLS[Strategy.Profile.Machinings[i].ToolInfo.nToolIndex].bIsCCW, MCH_MILL_WS.RIGHT, MCH_MILL_WS.LEFT)
|
||||
end
|
||||
Strategy.Profile.Machinings[i].ptEdge1 = EgtSP( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
Strategy.Profile.Machinings[i].ptEdge2 = EgtEP( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
Strategy.Profile.Machinings[i].dEdgeLength = EgtCurveLength( Proc.idAddAuxGeom)
|
||||
Strategy.Profile.Machinings[i].vtEdgeDirection = EgtSV( Proc.idAddAuxGeom, GDB_ID.ROOT) + EgtMV( Proc.idAddAuxGeom, GDB_ID.ROOT) + EgtEV( Proc.idAddAuxGeom, GDB_ID.ROOT)
|
||||
Strategy.Profile.Machinings[i].dLengthOnX = Proc.b3Box:getDimX()
|
||||
|
||||
local MachiningToSplit = {}
|
||||
table.insert( MachiningToSplit, Strategy.Profile.Machinings[i])
|
||||
local MachiningResult = MachiningLib.GetSplitMachinings( MachiningToSplit, FeatureSplittingPoints, Part)
|
||||
-- aggiunge lavorazione
|
||||
for j = 1, #MachiningResult do
|
||||
bAreAllMachiningsAdded = MachiningLib.AddMachinings( Proc, MachiningResult[j])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
bAreAllMachiningsAdded = false
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return STR0015
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"sStrategyId": "TAILCUT",
|
||||
"sStrategyName": "TAILCUT",
|
||||
"ParameterList" : [
|
||||
{
|
||||
"sName": "dDepthChamfer",
|
||||
"sNameNge": "DEPTH_CHAMFER",
|
||||
"sValue": "0",
|
||||
"sDescriptionShort": "Depth Chamfer",
|
||||
"sDescriptionLong": "Depth of the V-Mill to execute chamfers on cut-edges",
|
||||
"sType": "d",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bForceChainSaw",
|
||||
"sNameNge": "FORCE_CHAIN",
|
||||
"sValue": "false",
|
||||
"sDescriptionShort": "Force to use chain saw",
|
||||
"sDescriptionLong": "Force to use chain saw",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bExecutePreCut",
|
||||
"sNameNge": "EXEC_PRECUT",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Force to add PreCuts",
|
||||
"sDescriptionLong": "Autocam will apply a machining on the theoretical zero, to avoid collision if the theoretical piece length doesn't correspond to the real length",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "bFinishWithMill",
|
||||
"sNameNge": "MILL_FINISH",
|
||||
"sValue": "true",
|
||||
"sDescriptionShort": "Finish with mill",
|
||||
"sDescriptionLong": "Use a mill to finish the surface if split with chain saw",
|
||||
"sType": "b",
|
||||
"sMessageId": " ",
|
||||
"sMinUserLevel": "1"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteLength",
|
||||
"sSource": "GEN_dMaxWasteLength",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "dMaxWasteVolume",
|
||||
"sSource": "GEN_dMaxWasteVolume",
|
||||
"sMinUserLevel": "5"
|
||||
},
|
||||
{
|
||||
"sName": "bReduceBladePath",
|
||||
"sSource": "GEN_bReduceBladePath",
|
||||
"sMinUserLevel": "5"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
-- Strategia: TAILCUT
|
||||
-- Descrizione
|
||||
-- Taglio di separazione
|
||||
-- Feature: TailCut
|
||||
|
||||
-- carico librerie
|
||||
local BeamLib = require( 'BeamLib')
|
||||
local BeamData = require( 'BeamDataNew')
|
||||
local FeatureLib = require( 'FeatureLib')
|
||||
local MachiningLib = require( 'MachiningLib')
|
||||
local SPLITCUT = require( 'SPLITCUT')
|
||||
-- strategie di base
|
||||
local BladeToWaste = require('BLADETOWASTE')
|
||||
|
||||
-- Tabella per definizione modulo
|
||||
local TAILCUT = {}
|
||||
local Strategy = {}
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
local function MakeChamfer()
|
||||
-- TODO funzionalità da aggiungere
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
function TAILCUT.Make( bAddMachining, Proc, Part, CustomParameters)
|
||||
local StrategyLib = {}
|
||||
StrategyLib.Config = STRATEGIES_CONFIG[CustomParameters.sStrategyId]
|
||||
Strategy.sName = StrategyLib.Config.sStrategyId
|
||||
Strategy.Parameters = BeamLib.LoadCustomParametersInStrategy( Proc, Part, CustomParameters, StrategyLib.Config)
|
||||
Strategy.SplitStrategy = {}
|
||||
Strategy.Result = {}
|
||||
Strategy.Machining = {}
|
||||
Strategy.Result.sInfo = ''
|
||||
local OptionalParameters = { bForceChainSaw = Strategy.Parameters.bForceChainSaw, bReduceBladePath = Strategy.Parameters.bReduceBladePath,
|
||||
dMaxWasteLength = Strategy.Parameters.dMaxWasteLength, dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume }
|
||||
OptionalParameters.sRestLengthSideForPreSimulation = 'Tail'
|
||||
OptionalParameters.bCannotSplitRestLength = true
|
||||
local bAreAllMachiningsAdded = true
|
||||
local bExecutePrecutOnly = false
|
||||
|
||||
-- si setta che è taglio di coda
|
||||
Strategy.bIsTailCut = true
|
||||
-- quando si aggiunge la lavorazione, si cambia il nome della feature
|
||||
if bAddMachining then
|
||||
-- si forza il nome della feature
|
||||
EgtSetName( Proc.id, 'EndCut')
|
||||
end
|
||||
|
||||
-- separazione solo se esiste grezzo successivo con pezzi o scaricabile
|
||||
Strategy.bSplit = not( Part.bIsLastPart) or Part.dRestLength >= BeamData.dMinRaw
|
||||
|
||||
-- se devo fare split perchè c'è un grezzo da scaricare o un altro pezzo
|
||||
if Strategy.bSplit then
|
||||
OptionalParameters.dOffset = 0
|
||||
OptionalParameters.bDisableDicing = true
|
||||
Strategy.SplitStrategy, Strategy.Result = SPLITCUT.GetMachining( Proc, Part, OptionalParameters)
|
||||
|
||||
if Strategy.Result.sStatus ~= 'Completed' then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Split not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- se devo rimuovere tutto il restante
|
||||
else
|
||||
-- se abilitato, faccio tagli di PRECUT a zero (come SPLIT)
|
||||
if Strategy.Parameters.bExecutePreCut then
|
||||
if Part.dRestLength < 20 then
|
||||
bExecutePrecutOnly = true
|
||||
OptionalParameters.dOffset = 0
|
||||
else
|
||||
Strategy.bIsPreCut = true
|
||||
-- TODO questo dOffset è errato, va creata una nuova faccia oppure usare dLongitudinalOffset e farlo transitare per tutti, anche Engagement
|
||||
-- TODO a dRestLength va anche aggiunto lo spessore lama se c'è a fine grezzo?
|
||||
OptionalParameters.dOffset = Part.dRestLength
|
||||
end
|
||||
OptionalParameters.bDisableDicing = true
|
||||
Strategy.SplitStrategy, Strategy.Result = SPLITCUT.GetMachining( Proc, Part, OptionalParameters)
|
||||
|
||||
if Strategy.Result.sStatus ~= 'Completed' then
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Precut Tail not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
|
||||
-- se non faccio tagli PRECUT, imposto tabella Result direttamente. Non serve verificare che riesca a rimuovere il materiale extra
|
||||
else
|
||||
Strategy.Result.sStatus = 'Completed'
|
||||
Strategy.Result.dCompletionIndex = 5
|
||||
Strategy.Result.dMRR = 1
|
||||
-- si imposta qualità lama perchè verrà fatta BladeToWaste, probabilmente a cubetti
|
||||
Strategy.Result.dQuality = FeatureLib.GetStrategyQuality( 'SAWBLADE')
|
||||
end
|
||||
end
|
||||
|
||||
-- se devo applicare le lavorazioni
|
||||
if bAddMachining then
|
||||
-- inserimento smussi su spigoli del taglio
|
||||
if Strategy.Parameters.bMakeChamfer then
|
||||
MakeChamfer()
|
||||
end
|
||||
|
||||
local MachiningsToAdd = {}
|
||||
-- se devo fare split perchè c'è un grezzo da scaricare o un altro pezzo
|
||||
if Strategy.bSplit then
|
||||
if Strategy.SplitStrategy and #Strategy.SplitStrategy > 0 then
|
||||
for i = 1, #Strategy.SplitStrategy do
|
||||
local TempList = {}
|
||||
TempList.Splitting = Strategy.SplitStrategy[i]
|
||||
if i == #Strategy.SplitStrategy then
|
||||
TempList.Splitting.sUserNotes = 'Split;'
|
||||
TempList.AuxiliaryData = { bIsSplitOrCut = true}
|
||||
else
|
||||
TempList.Splitting.sUserNotes = 'Presplit;'
|
||||
end
|
||||
table.insert( MachiningsToAdd, TempList)
|
||||
end
|
||||
end
|
||||
|
||||
-- se devo rimuovere tutto il restante
|
||||
else
|
||||
-- se abilitato, faccio tagli di PRECUT a zero (come SPLIT)
|
||||
if Strategy.Parameters.bExecutePreCut then
|
||||
if Strategy.SplitStrategy and #Strategy.SplitStrategy > 0 then
|
||||
for i = 1, #Strategy.SplitStrategy do
|
||||
local TempList = {}
|
||||
TempList.Splitting = Strategy.SplitStrategy[i]
|
||||
TempList.Splitting.dLongitudinalOffset = OptionalParameters.dOffset
|
||||
if bExecutePrecutOnly then
|
||||
if i == #Strategy.SplitStrategy then
|
||||
TempList.Splitting.sUserNotes = 'Cut;'
|
||||
TempList.AuxiliaryData = { bIsSplitOrCut = true}
|
||||
else
|
||||
TempList.Splitting.sUserNotes = 'Precut;'
|
||||
end
|
||||
end
|
||||
table.insert( MachiningsToAdd, TempList)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not bExecutePrecutOnly then
|
||||
|
||||
-- si recuperano gli estremi del box del materiale di coda da rimuovere
|
||||
local b3PartWithTail = BeamLib.GetPartBoxWithHeadTail( Part, 'Tail')
|
||||
local ptStartRestLength = Point3d( Part.b3Part:getMin():getX() + 1, Part.b3Part:getMax():getY(), Part.b3Part:getMax():getZ())
|
||||
local ptEndRestLength = Point3d( b3PartWithTail:getMin():getX(), Part.b3Part:getMin():getY(), Part.b3Part:getMin():getZ())
|
||||
|
||||
local OptionalParametersBladeToWaste = {}
|
||||
OptionalParametersBladeToWaste.b3BoxDicing = BBox3d( ptStartRestLength, ptEndRestLength)
|
||||
OptionalParametersBladeToWaste.dMaxWasteVolume = Strategy.Parameters.dMaxWasteVolume
|
||||
OptionalParametersBladeToWaste.dMaxWasteLength = Strategy.Parameters.dMaxWasteLength
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = Strategy.Parameters.bReduceBladePath
|
||||
OptionalParametersBladeToWaste.sRestLengthSideForPreSimulation = 'Tail'
|
||||
OptionalParametersBladeToWaste.bCannotSplitRestLength = true
|
||||
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
-- se taglio non riuscito, si riprova con il riduci percorso forzato (collisione possibile in separazione pezzi alti)
|
||||
if ( not Strategy.Machining) or ( #Strategy.Machining == 0) then
|
||||
OptionalParametersBladeToWaste.bReduceBladePath = true
|
||||
Strategy.Machining, _ = BladeToWaste.Make( Proc, Part, OptionalParametersBladeToWaste)
|
||||
end
|
||||
if Strategy.Machining and #Strategy.Machining > 0 then
|
||||
for i = 1, #Strategy.Machining do
|
||||
local TempList = {}
|
||||
TempList.Splitting = Strategy.Machining[i]
|
||||
if i == #Strategy.Machining then
|
||||
TempList.Splitting.sUserNotes = 'Cut;'
|
||||
TempList.AuxiliaryData = { bIsSplitOrCut = true}
|
||||
else
|
||||
TempList.Splitting.sUserNotes = 'Precut;'
|
||||
end
|
||||
table.insert( MachiningsToAdd, TempList)
|
||||
end
|
||||
else
|
||||
Strategy.Result = FeatureLib.GetStrategyResultNotApplicable( 'Tail machining not possible')
|
||||
return false, Strategy.Result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- aggiungo lavorazioni trovate alla lista generale
|
||||
for i = 1, #MachiningsToAdd do
|
||||
MachiningsToAdd[i].Splitting.sStage = 'Tail'
|
||||
MachiningLib.AddMachinings( Proc, MachiningsToAdd[i].Splitting, MachiningsToAdd[i].AuxiliaryData)
|
||||
end
|
||||
|
||||
return bAreAllMachiningsAdded, Strategy.Result
|
||||
else
|
||||
return nil, Strategy.Result
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
return TAILCUT
|
||||
@@ -0,0 +1,155 @@
|
||||
; Commento per evitare BOM con UTF-8
|
||||
[Comments]
|
||||
STR0001 = Tenone a coda di rondine. Lama + fresa a coda di rondine
|
||||
STR0002 = Topologia tipo LapJoint. Svuotatura con fresa
|
||||
STR0003 = Topologia tipo LapJoint. Lama + motosega
|
||||
STR0004 = Topologia tipo LapJoint. Motosega
|
||||
STR0005 = 1, 2 o 3 facce. Lama con taglio singolo o cubetti. Se richiesto o necessario codolo.
|
||||
STR0006 = Tenone. Lama + fresa
|
||||
STR0007 = Mortasa a coda di rondine e mortasa frontale a coda di rondine
|
||||
STR0008 = Svuotatura mortasa (raggiata)
|
||||
STR0009 = ScarfJoint
|
||||
STR0010 = Fresatura perpendicolare (tipo cut, longcut)
|
||||
STR0011 = Foratura
|
||||
STR0012 = RidgeLap
|
||||
STR0013 = Foratura con fresa (svuotatura)
|
||||
STR0014 = Incisione con fresa/penna (Mark/text)
|
||||
STR0015 = Profilo arcuato (Head Cambered Profile)
|
||||
|
||||
[Strategies]
|
||||
; Processing , Gruppo , Topologia , Strategie
|
||||
;Feature : Cut
|
||||
10,1,Feature,STR0005
|
||||
;Feature : Longitudinal Cut
|
||||
10,0,Feature,STR0005
|
||||
;Feature : Double Cut
|
||||
11,1,Feature,
|
||||
; Feature : Ridge or Valley Cut
|
||||
12,0,Feature,
|
||||
; Feature : Saw Cut
|
||||
13,0,Feature,
|
||||
; Feature : Slot
|
||||
16,0,Pocket-5-Blind,STR0002,STR0003,STR0004
|
||||
16,0,Groove-4-Blind,STR0002,STR0003,STR0004
|
||||
16,0,Groove-3-Through,STR0002,STR0003,STR0004
|
||||
16,0,Groove-3-Blind,STR0002
|
||||
16,0,Rabbet-2-Through,STR0002
|
||||
16,0,Tunnel-4-Through,STR0003,STR0004
|
||||
; Feature : Front Slot
|
||||
17,0,Pocket-5-Blind,STR0002,STR0003,STR0004
|
||||
17,0,Groove-4-Blind,STR0002,STR0003,STR0004
|
||||
17,0,Groove-3-Blind,STR0002
|
||||
17,0,Groove-3-Through,STR0002,STR0003,STR0004
|
||||
17,0,Rabbet-2-Through,STR0002
|
||||
17,0,Tunnel-4-Through,STR0003,STR0004
|
||||
; Feature : Birds Mouth
|
||||
20,0,Feature,
|
||||
; Feature : Hip or Valley Rafter Notch
|
||||
25,0,Feature,
|
||||
; Feature : Ridge Lap
|
||||
30,1,Pocket-5-Blind,STR0002,STR0003,STR0004
|
||||
30,1,Groove-4-Blind,STR0002,STR0003,STR0004
|
||||
30,1,Groove-3-Blind,STR0002
|
||||
30,1,Groove-3-Through,STR0002,STR0003,STR0004
|
||||
30,1,Rabbet-2-Through,STR0002
|
||||
30,1,Tunnel-4-Through,STR0003,STR0004
|
||||
; Feature : Lap Joint
|
||||
30,0,Pocket-5-Blind,STR0002,STR0003,STR0004
|
||||
30,0,Groove-4-Blind,STR0002,STR0003,STR0004
|
||||
30,0,Groove-3-Blind,STR0002
|
||||
30,0,Groove-3-Through,STR0002,STR0003,STR0004
|
||||
30,0,Rabbet-2-Through,STR0002
|
||||
30,0,Tunnel-4-Through,STR0003,STR0004
|
||||
; Feature : Notch/Rabbet
|
||||
32,0,Pocket-5-Blind,STR0002,STR0003,STR0004
|
||||
32,0,Groove-4-Blind,STR0002,STR0003,STR0004
|
||||
32,0,Groove-3-Blind,STR0002
|
||||
32,0,Groove-3-Through,STR0002,STR0003,STR0004
|
||||
32,0,Rabbet-2-Through,STR0002
|
||||
32,0,Tunnel-4-Through,STR0003,STR0004
|
||||
; Feature : Block Haus
|
||||
33,0,Feature,
|
||||
; Feature : Notch
|
||||
34,0,Pocket-5-Blind,STR0002,STR0003,STR0004
|
||||
34,0,Groove-4-Blind,STR0002,STR0003,STR0004
|
||||
34,0,Groove-3-Blind,STR0002
|
||||
34,0,Groove-3-Through,STR0002,STR0003,STR0004
|
||||
34,0,Rabbet-2-Through,STR0002
|
||||
34,0,Tunnel-4-Through,STR0003,STR0004
|
||||
; Feature : French Ridge Lap
|
||||
35,1,Feature,
|
||||
; Feature : Chamfer
|
||||
36,0,Feature,
|
||||
; Feature : Block Haus Half Lap
|
||||
37,0,Feature,
|
||||
; Feature : Block Haus Front
|
||||
38,0,Feature,
|
||||
; Feature : Pocket
|
||||
39,0,Pocket-5-Blind,STR0002,STR0003,STR0004
|
||||
39,0,Groove-4-Blind,STR0002,STR0003,STR0004
|
||||
39,0,Groove-3-Blind,STR0002
|
||||
39,0,Groove-3-Through,STR0002,STR0003,STR0004
|
||||
39,0,Rabbet-2-Through,STR0002
|
||||
39,0,Tunnel-4-Through,STR0003,STR0004
|
||||
; Feature : Drilling
|
||||
40,0,Feature,
|
||||
; Feature : Tenon
|
||||
50,1,Feature,
|
||||
; Feature : Mortise
|
||||
50,0,Feature,
|
||||
; Feature : Front Mortise
|
||||
51,0,Feature,
|
||||
; Feature : House
|
||||
52,1,Feature,
|
||||
; Feature : House Mortise
|
||||
53,0,Feature,
|
||||
; Feature : Dovetail Tenon
|
||||
55,1,Feature,STR0001
|
||||
; Feature : Dovetail Mortise
|
||||
55,0,Feature,
|
||||
; Feature : Dovetail Mortise Front
|
||||
56,0,Feature,
|
||||
; Feature : Marking
|
||||
60,0,Feature,
|
||||
; Feature : Text
|
||||
61,0,Feature,
|
||||
; Feature : Scarf Simple
|
||||
70,1,Feature,
|
||||
; Feature : Scarf Joint
|
||||
71,1,Feature,
|
||||
; Feature : Step Joint
|
||||
80,1,Feature,
|
||||
; Feature : Step Joint Notch
|
||||
80,0,Feature,
|
||||
; Feature : Planing
|
||||
90,0,Feature,
|
||||
; Feature : Front Profile
|
||||
100,0,Feature,
|
||||
; Feature : Head Concave Profile
|
||||
101,0,Feature,
|
||||
; Feature : Head Convex Profile
|
||||
102,0,Feature,
|
||||
; Feature : Head Cambered Profile
|
||||
103,0,Feature,
|
||||
; Feature : Round Arch
|
||||
104,0,Feature,
|
||||
; Feature : Head Profile
|
||||
106,0,Feature,
|
||||
; Feature : Sphere
|
||||
107,0,Feature,
|
||||
; Feature : Triangle Cut
|
||||
120,0,Feature,
|
||||
; Feature : TyroleanDovetail
|
||||
136,0,Feature,
|
||||
; Feature : Dovetail
|
||||
138,0,Feature,
|
||||
; Feature : Free Contour
|
||||
250,0,Feature,
|
||||
; Feature : Outline
|
||||
251,0,Feature,
|
||||
; Feature : Aperture
|
||||
252,0,Feature,
|
||||
; Feature : Variant
|
||||
900,0,Feature,
|
||||
; Feature Decor
|
||||
959,0,Feature,
|
||||