Merge branch 'main-dev' into dev-physics

This commit is contained in:
2025-07-17 17:23:37 +05:30
93 changed files with 3618 additions and 1506 deletions

View File

@@ -0,0 +1,6 @@
<svg width="11" height="14" viewBox="0 0 11 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.7069 1.10756L1.75387 1.07218C2.70246 0.400484 3.83125 0.029837 4.94625 0.0104403C6.35793 -0.0822458 7.7395 0.447354 8.6564 1.3938C9.60485 2.19356 10.1085 3.40227 10.0118 4.55497C10.0147 5.42501 9.73379 6.27227 9.18619 7.00095C8.7929 7.48237 8.33582 7.90794 7.8818 8.22485L7.33801 8.66584C7.21154 8.76481 7.11492 8.89685 7.07561 8.99858C7.01588 9.14321 7.0229 9.37843 7.03176 9.57272V10.6183L3.03176 10.6183L3.01404 9.68567C2.96765 8.99886 3.00577 8.30894 3.14296 7.56046C3.24087 7.17773 3.44043 6.85713 3.73311 6.55348C3.93171 6.34743 4.07945 6.22479 4.55212 5.85341L5.14921 5.38276C5.30838 5.26567 5.45215 5.12897 5.52912 5.03974C5.63134 4.89184 5.69179 4.71911 5.70207 4.58361C5.70517 4.45782 5.66343 4.33503 5.54207 4.18109C5.42185 4.00905 5.21682 3.917 4.94703 3.94676C4.69233 3.96086 4.45265 4.07176 4.3048 4.22627C4.12283 4.43453 4.01908 4.69968 4.01138 4.97613L3.9843 5.94829H0.0899556L0.0150696 5.02953C-0.107782 3.52229 0.526244 2.0525 1.7069 1.10756Z" fill="white"/>
<path d="M2.33157 1.88826C3.11632 1.33258 4.05015 1.02594 5.01157 1.00826C6.13158 0.934725 7.22769 1.3549 8.01156 2.15826C8.71302 2.74975 9.0855 3.64369 9.01156 4.55826C9.01373 5.21079 8.80309 5.84624 8.41157 6.36826C8.07577 6.7793 7.68551 7.14265 7.25157 7.44826L6.72157 7.87826C6.44972 8.09098 6.24205 8.37479 6.12157 8.69826C6.05795 8.88813 6.01736 9.30693 6.03157 9.61826H4.03156C3.9907 9.01311 4.00428 8.40523 4.11156 7.80826C4.22156 7.37826 4.61157 7.07826 5.17157 6.63826L5.74157 6.18826C5.96848 6.02134 6.17343 5.82647 6.35157 5.60826C6.55601 5.31245 6.67692 4.967 6.70157 4.60826C6.71053 4.24514 6.59001 3.89067 6.36157 3.60826C6.03044 3.13441 5.46571 2.88085 4.89157 2.94826C4.38217 2.97645 3.90281 3.19825 3.55156 3.56826C3.21667 3.95153 3.02574 4.43949 3.01156 4.94826H1.01157C0.919144 3.80505 1.38474 2.68762 2.26157 1.94826" fill="black"/>
<path d="M7.03125 10.0078V14.0078H3.03125V10.0078H7.03125Z" fill="white"/>
<path d="M6.03125 11.0078H4.03125V13.0078H6.03125V11.0078Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,4 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 5H14V9H9V14H5V9H0V5H5V0H9V5Z" fill="black"/>
<path d="M8 6H13V8H8V13H6V8H1V6H6V1H8V6Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 217 B

View File

@@ -0,0 +1,7 @@
<svg width="15" height="13" viewBox="0 0 15 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.57009 1.77983C4.05009 1.59983 5.00009 1.70983 5.25009 2.24983C5.50009 2.78983 5.65009 3.48983 5.66009 3.31983C5.64096 2.80313 5.68461 2.28602 5.79009 1.77983C5.90124 1.45565 6.15591 1.20098 6.48009 1.08983C6.77741 0.995805 7.09308 0.975217 7.40009 1.02983C7.71051 1.09373 7.98544 1.27226 8.17009 1.52983C8.40404 2.11296 8.53596 2.73199 8.56009 3.35983C8.58497 2.82409 8.67565 2.29344 8.83009 1.77983C8.9972 1.54438 9.24123 1.37462 9.52009 1.29983C9.85069 1.23939 10.1895 1.23939 10.5201 1.29983C10.7915 1.38989 11.0288 1.56089 11.2001 1.78983C11.4125 2.31998 11.5407 2.88008 11.5801 3.44983C11.5801 3.58983 11.6501 3.05983 11.8701 2.70983C12.0468 2.18516 12.6154 1.9031 13.1401 2.07983C13.6648 2.25656 13.9468 2.82516 13.7701 3.34983C13.7701 3.99983 13.7701 3.96983 13.7701 4.40983C13.7701 4.84983 13.7701 5.23983 13.7701 5.60983C13.7341 6.19505 13.6538 6.77671 13.5301 7.34983C13.3565 7.85715 13.1143 8.33829 12.8101 8.77983C12.3247 9.31989 11.9235 9.93009 11.6201 10.5898C11.5461 10.9178 11.5125 11.2537 11.5201 11.5898C11.5191 11.9005 11.5594 12.2099 11.6401 12.5098C11.2313 12.5535 10.8189 12.5535 10.4101 12.5098C10.0201 12.4498 9.54009 11.6698 9.41009 11.4298C9.34577 11.301 9.21412 11.2195 9.07009 11.2195C8.92607 11.2195 8.79442 11.301 8.73009 11.4298C8.51009 11.8098 8.02009 12.4998 7.73009 12.5398C7.06009 12.6198 5.67009 12.5398 4.59009 12.5398C4.59009 12.5398 4.78009 11.5398 4.36009 11.1798C3.94009 10.8198 3.53009 10.3998 3.22009 10.1198L2.39009 9.19983C1.80478 8.65651 1.37647 7.96569 1.15009 7.19983C0.940094 6.25983 0.960094 5.80983 1.15009 5.42983C1.34388 5.11604 1.64649 4.88464 2.00009 4.77983C2.29386 4.72654 2.59628 4.74716 2.88009 4.83983C3.07636 4.922 3.24598 5.05701 3.37009 5.22983C3.60009 5.53983 3.68009 5.68983 3.58009 5.34983C3.48009 5.00983 3.26009 4.75983 3.15009 4.34983C2.93595 3.86563 2.80737 3.34796 2.77009 2.81983C2.81108 2.346 3.14192 1.9474 3.60009 1.81983" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.57009 1.77983C4.05009 1.59983 5.00009 1.70983 5.25009 2.24983C5.50009 2.78983 5.65009 3.48983 5.66009 3.31983C5.64096 2.80313 5.68461 2.28602 5.79009 1.77983C5.90124 1.45565 6.15591 1.20098 6.48009 1.08983C6.77741 0.995805 7.09308 0.975217 7.40009 1.02983C7.71051 1.09373 7.98544 1.27226 8.17009 1.52983C8.40404 2.11296 8.53596 2.73199 8.56009 3.35983C8.58497 2.82409 8.67565 2.29344 8.83009 1.77983C8.9972 1.54438 9.24123 1.37462 9.52009 1.29983C9.85069 1.23939 10.1895 1.23939 10.5201 1.29983C10.7915 1.38989 11.0288 1.56089 11.2001 1.78983C11.4125 2.31998 11.5407 2.88008 11.5801 3.44983C11.5801 3.58983 11.6501 3.05983 11.8701 2.70983C12.0468 2.18516 12.6154 1.9031 13.1401 2.07983C13.6648 2.25656 13.9468 2.82516 13.7701 3.34983C13.7701 3.99983 13.7701 3.96983 13.7701 4.40983C13.7701 4.84983 13.7701 5.23983 13.7701 5.60983C13.7341 6.19505 13.6538 6.77671 13.5301 7.34983C13.3565 7.85715 13.1143 8.33829 12.8101 8.77983C12.3247 9.31989 11.9235 9.93009 11.6201 10.5898C11.5461 10.9178 11.5125 11.2537 11.5201 11.5898C11.5191 11.9005 11.5594 12.2099 11.6401 12.5098C11.2313 12.5535 10.8189 12.5535 10.4101 12.5098C10.0201 12.4498 9.54009 11.6698 9.41009 11.4298C9.34577 11.301 9.21412 11.2195 9.07009 11.2195C8.92607 11.2195 8.79442 11.301 8.73009 11.4298C8.51009 11.8098 8.02009 12.4998 7.73009 12.5398C7.06009 12.6198 5.67009 12.5398 4.59009 12.5398C4.59009 12.5398 4.78009 11.5398 4.36009 11.1798C3.94009 10.8198 3.53009 10.3998 3.22009 10.1198L2.39009 9.19983C1.80478 8.65651 1.37647 7.96569 1.15009 7.19983C0.940094 6.25983 0.960094 5.80983 1.15009 5.42983C1.34388 5.11604 1.64649 4.88464 2.00009 4.77983C2.29386 4.72654 2.59628 4.74716 2.88009 4.83983C3.07636 4.922 3.24598 5.05701 3.37009 5.22983C3.60009 5.53983 3.68009 5.68983 3.58009 5.34983C3.48009 5.00983 3.26009 4.75983 3.15009 4.34983C2.93595 3.86563 2.80737 3.34796 2.77009 2.81983C2.79054 2.33907 3.11066 1.92291 3.57009 1.77983Z" stroke="black" stroke-width="0.75" stroke-linejoin="round"/>
<path d="M11.3203 9.4548V6.00302C11.3203 5.7964 11.1524 5.62891 10.9453 5.62891C10.7382 5.62891 10.5703 5.7964 10.5703 6.00302V9.4548C10.5703 9.66141 10.7382 9.82891 10.9453 9.82891C11.1524 9.82891 11.3203 9.66141 11.3203 9.4548Z" fill="black"/>
<path d="M9.34031 9.45353L9.32031 5.99998C9.31911 5.79386 9.15025 5.62772 8.94315 5.62891C8.73605 5.6301 8.56913 5.79816 8.57032 6.00428L8.59032 9.45783C8.59151 9.66396 8.76037 9.83009 8.96747 9.8289C9.17458 9.82771 9.3415 9.65965 9.34031 9.45353Z" fill="black"/>
<path d="M6.57032 6.00881L6.59032 9.45342C6.59153 9.66201 6.7604 9.83012 6.96751 9.8289C7.17461 9.82768 7.34152 9.65759 7.34031 9.449L7.32031 6.0044C7.3191 5.7958 7.15022 5.62769 6.94312 5.62891C6.73602 5.63013 6.56911 5.80022 6.57032 6.00881Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 1C11.866 1 15 4.13401 15 8C15 11.866 11.866 15 8 15H2C1.44772 15 1 14.5523 1 14V8C1 4.13401 4.13401 1 8 1Z" fill="black" stroke="white" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 270 B

View File

@@ -0,0 +1,4 @@
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.99 6V0H6.01V6H0V9H6.01V15H8.99V9H15V6H8.99Z" fill="white"/>
<path d="M8 7V1H7V7H1V8H7V14H8V8H14V7H8Z" fill="#232020"/>
</svg>

After

Width:  |  Height:  |  Size: 234 B

View File

@@ -0,0 +1,4 @@
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.70849 18.2848L6.01914 13.9573C6.20421 13.7715 6.45487 13.6658 6.71711 13.663L13.3181 13.5936C14.2439 13.5839 14.6604 12.4297 13.9542 11.8309L1.64669 1.39613C0.996961 0.845261 0 1.30706 0 2.15888V17.5791C0 18.4709 1.07909 18.9167 1.70849 18.2848Z" fill="white"/>
<path d="M1.30078 14.5353V5.02997C1.30078 4.17815 2.29774 3.71636 2.94747 4.26722L10.4817 10.655C11.1864 11.2525 10.7733 12.4042 9.84957 12.4177L5.94136 12.4746C5.66374 12.4787 5.40031 12.5979 5.21412 12.8039L3.04259 15.206C2.42871 15.885 1.30078 15.4507 1.30078 14.5353Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 665 B

View File

@@ -0,0 +1,4 @@
<svg width="10" height="15" viewBox="0 0 10 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.79999 0H0L3.28999 3.2L2.71999 3.83C2.35508 4.31517 2.02108 4.82284 1.71999 5.35C1.42677 5.99118 1.20219 6.66158 1.04999 7.35C0.993385 8.05887 0.993385 8.77113 1.04999 9.48C1.08712 10.0363 1.18777 10.5866 1.34999 11.12C1.50076 11.6048 1.71245 12.0685 1.97999 12.5C2.26031 12.9383 2.59647 13.3384 2.97999 13.69C3.66537 14.158 4.38776 14.5694 5.13999 14.92C4.76649 14.371 4.45144 13.7845 4.19999 13.17C4.07439 12.6664 3.98087 12.1554 3.91999 11.64C3.8692 11.1116 3.84917 10.5807 3.85999 10.05C3.87981 9.6673 3.94356 9.28814 4.04999 8.92C4.21288 8.44919 4.44912 8.00708 4.74999 7.61C4.9876 7.28231 5.25544 6.97764 5.54999 6.7C5.81776 6.43911 6.10165 6.1953 6.39999 5.97L9.79999 9.2V0Z" fill="white"/>
<path d="M8.79835 7V1H2.79835L4.64835 2.78C4.50835 2.93 4.31835 3.12 4.20835 3.26C3.92835 3.61 3.76835 3.8 3.59835 3.99C3.42835 4.18 3.33835 4.31 3.21835 4.46C3.08674 4.64242 2.96651 4.83278 2.85835 5.03C2.74835 5.23 2.62835 5.49 2.48835 5.78C2.3417 6.09919 2.23425 6.43497 2.16835 6.78C2.08885 7.10905 2.03204 7.44317 1.99835 7.78C1.98482 8.03315 1.98482 8.28685 1.99835 8.54C1.97451 8.87291 1.97451 9.20709 1.99835 9.54C2.08696 10.1309 2.24818 10.7086 2.47835 11.26L2.93835 12.19C2.84916 11.4334 2.80907 10.6718 2.81835 9.91C2.88962 9.31114 3.05499 8.72729 3.30835 8.18C3.35585 8.03336 3.41958 7.89249 3.49835 7.76L3.85835 7.19C4.06835 6.85 4.50835 6.32 4.61835 6.19C4.90945 5.86142 5.22358 5.55397 5.55835 5.27L6.34835 4.6L8.79835 7Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 0L0 8L5.22 13.22L8 16L16 8L8 0ZM6 11H5V10H6V11ZM6 6H5V5H6V6ZM11 11H10V10H11V11ZM10 5H11V6H10V5Z" fill="white"/>
<path d="M14.5502 7.98187L11.9902 5.17188V7.00187H7.99016H3.98016V5.17188L1.41016 7.98187L3.98016 10.7919V8.98187H7.99016H11.9902V10.7919L14.5502 7.98187Z" fill="black"/>
<path d="M8.97188 7.99187H8.98187V3.99188H10.7919L7.99187 1.42188L5.18187 3.99188H6.99187V7.99187V11.9919H5.17188L7.97187 14.5619L10.7819 11.9919H8.97188V7.99187Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 577 B

View File

@@ -0,0 +1,7 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.98353 8.91984C4.88353 8.54984 4.78353 8.06984 4.57353 7.36984C4.36353 6.66984 4.23353 6.50984 4.10353 6.13984C3.97353 5.76984 3.80353 5.41984 3.60353 4.95984C3.42033 4.4899 3.2667 4.00896 3.14353 3.51984C3.06029 3.10764 3.1627 2.6797 3.42353 2.34984C3.78238 1.99966 4.30021 1.8664 4.78352 1.99984C5.16218 2.16543 5.4826 2.44057 5.70353 2.78984C5.99856 3.26151 6.24006 3.76462 6.42353 4.28984C6.70527 5.00947 6.90975 5.757 7.03352 6.51984L7.12353 6.96984C7.12353 6.96984 7.12353 5.84984 7.12353 5.80984C7.12353 4.80984 7.06353 3.98984 7.12353 2.86984C7.12353 2.73984 7.18353 2.27984 7.20353 2.14984C7.22938 1.7198 7.48564 1.33732 7.87353 1.14984C8.31881 0.950053 8.82824 0.950053 9.27353 1.14984C9.67213 1.32827 9.93818 1.71385 9.96352 2.14984C9.96352 2.25984 10.0535 3.14984 10.0535 3.25984C10.0535 4.25984 10.0535 4.89984 10.0535 5.42984C10.0535 5.65984 10.0535 7.05984 10.0535 6.89984C10.0771 5.5803 10.1907 4.26391 10.3935 2.95984C10.512 2.55128 10.7995 2.21285 11.1835 2.02984C11.6585 1.84278 12.198 1.93527 12.5835 2.26984C12.8717 2.58613 13.0413 2.99253 13.0635 3.41984C13.0635 3.82984 13.0635 4.31984 13.0635 4.66984C13.0635 5.53984 13.0635 5.98984 13.0635 6.78984C13.0635 6.78984 13.0635 7.08984 13.0635 6.96984C13.1535 6.68984 13.2535 6.42984 13.3335 6.22984C13.4135 6.02984 13.5735 5.61984 13.6935 5.36984C13.8156 5.1315 13.9526 4.90105 14.1035 4.67984C14.2604 4.42557 14.4955 4.22906 14.7735 4.11984C15.024 4.02302 15.3029 4.03099 15.5474 4.14197C15.7919 4.25294 15.9815 4.45758 16.0735 4.70984C16.1331 5.07409 16.1331 5.44559 16.0735 5.80984C16.0069 6.36927 15.8897 6.92152 15.7235 7.45984C15.5935 7.90984 15.4535 8.68984 15.3835 9.05984C15.3135 9.42984 15.1535 10.4398 15.0235 10.8798C14.831 11.4047 14.5651 11.8997 14.2335 12.3498C13.7483 12.8901 13.3472 13.5002 13.0435 14.1598C12.9688 14.4877 12.9352 14.8236 12.9435 15.1598C12.9419 15.4705 12.9823 15.78 13.0635 16.0798C12.6547 16.1234 12.2424 16.1234 11.8335 16.0798C11.4435 16.0198 10.9635 15.2398 10.8335 14.9998C10.7692 14.871 10.6376 14.7895 10.4935 14.7895C10.3495 14.7895 10.2178 14.871 10.1535 14.9998C9.92353 15.3798 9.44353 16.0698 9.10353 16.1098C8.43353 16.1898 7.05353 16.1098 5.96353 16.1098C5.96353 16.1098 6.15353 15.1098 5.73353 14.7498C5.31353 14.3898 4.90353 13.9698 4.59353 13.6898L3.76353 12.7698C3.48353 12.4098 3.13353 11.6798 2.52353 10.7698C2.17353 10.2698 1.52353 9.67984 1.24353 9.18984C1.00845 8.79216 0.940151 8.31767 1.05353 7.86984C1.22333 7.2752 1.81419 6.9043 2.42353 7.00984C2.88703 7.04038 3.32544 7.2313 3.66353 7.54984C3.93124 7.78148 4.18189 8.03213 4.41353 8.29984C4.57353 8.48984 4.61353 8.57984 4.79353 8.80984C4.97353 9.03984 5.09353 9.26984 5.00353 8.92984" fill="white"/>
<path d="M4.98353 8.91984C4.88353 8.54984 4.78353 8.06984 4.57353 7.36984C4.36353 6.66984 4.23353 6.50984 4.10353 6.13984C3.97353 5.76984 3.80353 5.41984 3.60353 4.95984C3.42033 4.4899 3.2667 4.00896 3.14353 3.51984C3.06029 3.10764 3.1627 2.6797 3.42353 2.34984C3.78238 1.99966 4.30021 1.8664 4.78352 1.99984C5.16218 2.16543 5.4826 2.44057 5.70353 2.78984C5.99856 3.26151 6.24006 3.76462 6.42353 4.28984C6.70527 5.00947 6.90975 5.757 7.03352 6.51984L7.12353 6.96984C7.12353 6.96984 7.12353 5.84984 7.12353 5.80984C7.12353 4.80984 7.06353 3.98984 7.12353 2.86984C7.12353 2.73984 7.18353 2.27984 7.20353 2.14984C7.22938 1.7198 7.48564 1.33732 7.87353 1.14984C8.31881 0.950053 8.82824 0.950053 9.27353 1.14984C9.67213 1.32827 9.93818 1.71385 9.96352 2.14984C9.96352 2.25984 10.0535 3.14984 10.0535 3.25984C10.0535 4.25984 10.0535 4.89984 10.0535 5.42984C10.0535 5.65984 10.0535 7.05984 10.0535 6.89984C10.0771 5.5803 10.1907 4.26391 10.3935 2.95984C10.512 2.55128 10.7995 2.21285 11.1835 2.02984C11.6585 1.84278 12.198 1.93527 12.5835 2.26984C12.8717 2.58613 13.0413 2.99253 13.0635 3.41984C13.0635 3.82984 13.0635 4.31984 13.0635 4.66984C13.0635 5.53984 13.0635 5.98984 13.0635 6.78984C13.0635 6.78984 13.0635 7.08984 13.0635 6.96984C13.1535 6.68984 13.2535 6.42984 13.3335 6.22984C13.4135 6.02984 13.5735 5.61984 13.6935 5.36984C13.8156 5.1315 13.9526 4.90105 14.1035 4.67984C14.2604 4.42557 14.4955 4.22906 14.7735 4.11984C15.024 4.02302 15.3029 4.03099 15.5474 4.14197C15.7919 4.25294 15.9815 4.45758 16.0735 4.70984C16.1331 5.07409 16.1331 5.44559 16.0735 5.80984C16.0069 6.36927 15.8897 6.92152 15.7235 7.45984C15.5935 7.90984 15.4535 8.68984 15.3835 9.05984C15.3135 9.42984 15.1535 10.4398 15.0235 10.8798C14.831 11.4047 14.5651 11.8997 14.2335 12.3498C13.7483 12.8901 13.3472 13.5002 13.0435 14.1598C12.9688 14.4877 12.9352 14.8236 12.9435 15.1598C12.9419 15.4705 12.9823 15.78 13.0635 16.0798C12.6547 16.1234 12.2424 16.1234 11.8335 16.0798C11.4435 16.0198 10.9635 15.2398 10.8335 14.9998C10.7692 14.871 10.6376 14.7895 10.4935 14.7895C10.3495 14.7895 10.2178 14.871 10.1535 14.9998C9.92353 15.3798 9.44353 16.0698 9.10353 16.1098C8.43353 16.1898 7.05353 16.1098 5.96353 16.1098C5.96353 16.1098 6.15353 15.1098 5.73353 14.7498C5.31353 14.3898 4.90353 13.9698 4.59353 13.6898L3.76353 12.7698C3.48353 12.4098 3.13353 11.6798 2.52353 10.7698C2.17353 10.2698 1.52353 9.67984 1.24353 9.18984C1.00845 8.79216 0.940151 8.31767 1.05353 7.86984C1.22333 7.2752 1.81419 6.9043 2.42353 7.00984C2.88703 7.04038 3.32544 7.2313 3.66353 7.54984C3.93124 7.78148 4.18189 8.03213 4.41353 8.29984C4.57353 8.48984 4.61353 8.57984 4.79353 8.80984C4.97353 9.03984 5.09353 9.26984 5.00353 8.92984" stroke="black" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.3555 13.0798V9.62802C12.3555 9.4214 12.1876 9.25391 11.9805 9.25391C11.7734 9.25391 11.6055 9.4214 11.6055 9.62802V13.0798C11.6055 13.2864 11.7734 13.4539 11.9805 13.4539C12.1876 13.4539 12.3555 13.2864 12.3555 13.0798Z" fill="black"/>
<path d="M10.3655 13.0796L10.3555 9.62605C10.3549 9.41993 10.1865 9.25331 9.97939 9.25391C9.77228 9.2545 9.60487 9.42208 9.60547 9.6282L9.61547 13.0818C9.61607 13.2879 9.78444 13.4545 9.99155 13.4539C10.1987 13.4533 10.3661 13.2857 10.3655 13.0796Z" fill="black"/>
<path d="M7.60938 9.62991L7.62938 13.0745C7.63059 13.2831 7.79947 13.4512 8.00657 13.45C8.21367 13.4488 8.38058 13.2787 8.37937 13.0701L8.35937 9.62549C8.35816 9.4169 8.18929 9.24879 7.98218 9.25001C7.77508 9.25123 7.60817 9.42131 7.60938 9.62991Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,8 @@
<svg width="15" height="19" viewBox="0 0 15 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.05747 15.5237L12.1699 12.4692C12.6624 12.1035 12.8895 11.4794 12.7473 10.8827L11.6154 6.13304C11.4864 5.59169 11.0742 5.16222 10.5373 5.01207L6.60637 3.92049L6.2889 3.82351L5.95117 3.71215L5.41868 3.52427L5.05448 3.38923L4.50823 3.17899L3.80899 2.8991L3.04397 2.58152L0.695312 1.46484L1.31131 4.75424L1.37722 5.50451L1.42065 6.0882L1.4447 6.47587L1.47071 7.03993C1.47281 7.1008 1.47463 7.16095 1.47614 7.22024L1.48135 7.56472C1.48174 7.67545 1.48072 7.78174 1.4781 7.88258L1.39007 11.8061C1.37871 12.3635 1.67076 12.8822 2.15175 13.1621L6.37175 15.6181C6.90198 15.9266 7.56502 15.8895 8.05747 15.5237Z" fill="black"/>
<path d="M14.0286 14.2763C14.2617 14.5901 14.2192 15.0235 13.9439 15.2869L13.8703 15.349L10.1771 18.0921C9.83718 18.3445 9.35692 18.2736 9.10442 17.9337C8.87135 17.6199 8.91383 17.1865 9.18912 16.9231L9.26277 16.861L12.9559 14.118C13.2959 13.8654 13.7762 13.9363 14.0286 14.2763Z" fill="black"/>
<path d="M6.89838 8.4252C7.433 8.35384 7.98929 8.56725 8.33371 9.03096C8.83871 9.71082 8.69691 10.6714 8.01701 11.1764C7.33715 11.6814 6.37656 11.5396 5.87162 10.8597C5.52725 10.3961 5.48366 9.80203 5.70629 9.31089C5.65697 9.27113 5.61193 9.22449 5.57242 9.17131L2.94879 5.63894C2.93153 5.61568 2.9212 5.58801 2.91895 5.55913L2.86938 4.96079L2.81691 4.39698C2.80568 4.28142 2.92164 4.19525 3.02905 4.23944C3.11258 4.27381 3.19832 4.30888 3.28586 4.34446L3.82966 4.56235L4.11192 4.67278C4.13889 4.68325 4.16237 4.70113 4.17971 4.7244L6.80347 8.25695C6.8429 8.31007 6.87447 8.36664 6.89838 8.4252Z" fill="black"/>
<path d="M8.05747 15.5237L12.1699 12.4692C12.6624 12.1035 12.8895 11.4794 12.7473 10.8827L11.6154 6.13304C11.4864 5.59169 11.0742 5.16222 10.5373 5.01207L6.60637 3.92049L6.2889 3.82351L5.95117 3.71215L5.41868 3.52427L5.05448 3.38923L4.50823 3.17899L3.80899 2.8991L3.04397 2.58152L0.695312 1.46484L1.31131 4.75424L1.37722 5.50451L1.42065 6.0882L1.4447 6.47587L1.47071 7.03993C1.47281 7.1008 1.47463 7.16095 1.47614 7.22024L1.48135 7.56472C1.48174 7.67545 1.48072 7.78174 1.4781 7.88258L1.39007 11.8061C1.37871 12.3635 1.67076 12.8822 2.15175 13.1621L6.37175 15.6181C6.90198 15.9266 7.56502 15.8895 8.05747 15.5237Z" stroke="white"/>
<path d="M14.0286 14.2763C14.2617 14.5901 14.2192 15.0235 13.9439 15.2869L13.8703 15.349L10.1771 18.0921C9.83718 18.3445 9.35692 18.2736 9.10442 17.9337C8.87135 17.6199 8.91383 17.1865 9.18912 16.9231L9.26277 16.861L12.9559 14.118C13.2959 13.8654 13.7762 13.9363 14.0286 14.2763Z" stroke="white"/>
<path d="M6.89838 8.4252C7.433 8.35384 7.98929 8.56725 8.33371 9.03096C8.83871 9.71082 8.69691 10.6714 8.01701 11.1764C7.33715 11.6814 6.37656 11.5396 5.87162 10.8597C5.52725 10.3961 5.48366 9.80203 5.70629 9.31089C5.65697 9.27113 5.61193 9.22449 5.57242 9.17131L2.94879 5.63894C2.93153 5.61568 2.9212 5.58801 2.91895 5.55913L2.86938 4.96079L2.81691 4.39698C2.80568 4.28142 2.92164 4.19525 3.02905 4.23944C3.11258 4.27381 3.19832 4.30888 3.28586 4.34446L3.82966 4.56235L4.11192 4.67278C4.13889 4.68325 4.16237 4.70113 4.17971 4.7244L6.80347 8.25695C6.8429 8.31007 6.87447 8.36664 6.89838 8.4252Z" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,7 @@
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.90366 12.8932C3.62366 12.5332 3.27366 11.8032 2.66366 10.8932C2.31366 10.3932 1.45366 9.44321 1.19366 8.95321C1.00623 8.65544 0.951847 8.29286 1.04366 7.95321C1.20062 7.30742 1.81322 6.87903 2.47366 6.95321C2.98446 7.05582 3.45388 7.30618 3.82366 7.67321C4.08184 7.91638 4.31933 8.18063 4.53366 8.46321C4.69366 8.66321 4.73366 8.74321 4.91366 8.97321C5.09366 9.20321 5.21366 9.43321 5.12366 9.09321C5.05366 8.59321 4.93366 7.75321 4.76366 7.00321C4.63366 6.43321 4.60366 6.34321 4.48366 5.91321C4.36366 5.48321 4.29366 5.12321 4.16366 4.63321C4.04483 4.15178 3.95137 3.66444 3.88366 3.17321C3.75761 2.54491 3.84932 1.89242 4.14366 1.32321C4.49305 0.994578 5.00559 0.907841 5.44366 1.10321C5.88426 1.42855 6.21276 1.88286 6.38366 2.40321C6.64573 3.0436 6.82062 3.71627 6.90366 4.40321C7.06366 5.40321 7.37366 6.86321 7.38366 7.16321C7.38366 6.79321 7.31366 6.01321 7.38366 5.66321C7.45301 5.29833 7.70662 4.99552 8.05366 4.86321C8.35147 4.77183 8.66651 4.75129 8.97366 4.80321C9.2837 4.86802 9.55832 5.04635 9.74366 5.30321C9.97534 5.8866 10.1039 6.50581 10.1237 7.13321C10.1504 6.5838 10.2445 6.03974 10.4037 5.51321C10.5708 5.27776 10.8148 5.108 11.0937 5.03321C11.4243 4.97276 11.7631 4.97276 12.0937 5.03321C12.3648 5.12384 12.6019 5.29472 12.7737 5.52321C12.9854 6.05355 13.1136 6.61355 13.1537 7.18321C13.1537 7.32321 13.2237 6.79321 13.4437 6.44321C13.558 6.10381 13.8447 5.85118 14.1958 5.78048C14.5469 5.70979 14.909 5.83178 15.1458 6.10048C15.3826 6.36919 15.458 6.74381 15.3437 7.08321C15.3437 7.73321 15.3437 7.70321 15.3437 8.14321C15.3437 8.58321 15.3437 8.97321 15.3437 9.34321C15.3072 9.92839 15.227 10.51 15.1037 11.0832C14.9296 11.5903 14.6874 12.0714 14.3837 12.5132C13.8981 13.0532 13.4969 13.6634 13.1937 14.3232C13.1184 14.651 13.0848 14.987 13.0937 15.3232C13.0927 15.6338 13.133 15.9432 13.2137 16.2432C12.8048 16.2864 12.3925 16.2864 11.9837 16.2432C11.5937 16.1832 11.1137 15.4032 10.9837 15.1632C10.9193 15.0343 10.7877 14.9529 10.6437 14.9529C10.4996 14.9529 10.368 15.0343 10.3037 15.1632C10.0837 15.5432 9.59366 16.2332 9.25366 16.2732C8.58366 16.3532 7.20366 16.2732 6.11366 16.2732C6.11366 16.2732 6.29366 15.2732 5.88366 14.9132C5.47366 14.5532 5.05366 14.1332 4.74366 13.8532L3.90366 12.8932Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.90366 12.8932C3.62366 12.5332 3.27366 11.8032 2.66366 10.8932C2.31366 10.3932 1.45366 9.44321 1.19366 8.95321C1.00623 8.65544 0.951847 8.29286 1.04366 7.95321C1.20062 7.30742 1.81322 6.87903 2.47366 6.95321C2.98446 7.05582 3.45388 7.30618 3.82366 7.67321C4.08184 7.91638 4.31933 8.18063 4.53366 8.46321C4.69366 8.66321 4.73366 8.74321 4.91366 8.97321C5.09366 9.20321 5.21366 9.43321 5.12366 9.09321C5.05366 8.59321 4.93366 7.75321 4.76366 7.00321C4.63366 6.43321 4.60366 6.34321 4.48366 5.91321C4.36366 5.48321 4.29366 5.12321 4.16366 4.63321C4.04483 4.15178 3.95137 3.66444 3.88366 3.17321C3.75761 2.54491 3.84932 1.89242 4.14366 1.32321C4.49305 0.994578 5.00559 0.907841 5.44366 1.10321C5.88426 1.42855 6.21276 1.88286 6.38366 2.40321C6.64573 3.0436 6.82062 3.71627 6.90366 4.40321C7.06366 5.40321 7.37366 6.86321 7.38366 7.16321C7.38366 6.79321 7.31366 6.01321 7.38366 5.66321C7.45301 5.29833 7.70662 4.99552 8.05366 4.86321C8.35147 4.77183 8.66651 4.75129 8.97366 4.80321C9.2837 4.86802 9.55832 5.04635 9.74366 5.30321C9.97534 5.8866 10.1039 6.50581 10.1237 7.13321C10.1504 6.5838 10.2445 6.03974 10.4037 5.51321C10.5708 5.27776 10.8148 5.108 11.0937 5.03321C11.4243 4.97276 11.7631 4.97276 12.0937 5.03321C12.3648 5.12384 12.6019 5.29472 12.7737 5.52321C12.9854 6.05355 13.1136 6.61355 13.1537 7.18321C13.1537 7.32321 13.2237 6.79321 13.4437 6.44321C13.558 6.10381 13.8447 5.85118 14.1958 5.78048C14.5469 5.70979 14.909 5.83178 15.1458 6.10048C15.3826 6.36919 15.458 6.74381 15.3437 7.08321C15.3437 7.73321 15.3437 7.70321 15.3437 8.14321C15.3437 8.58321 15.3437 8.97321 15.3437 9.34321C15.3072 9.92839 15.227 10.51 15.1037 11.0832C14.9296 11.5903 14.6874 12.0714 14.3837 12.5132C13.8981 13.0532 13.4969 13.6634 13.1937 14.3232C13.1184 14.651 13.0848 14.987 13.0937 15.3232C13.0927 15.6338 13.133 15.9432 13.2137 16.2432C12.8048 16.2864 12.3925 16.2864 11.9837 16.2432C11.5937 16.1832 11.1137 15.4032 10.9837 15.1632C10.9193 15.0343 10.7877 14.9529 10.6437 14.9529C10.4996 14.9529 10.368 15.0343 10.3037 15.1632C10.0837 15.5432 9.59366 16.2332 9.25366 16.2732C8.58366 16.3532 7.20366 16.2732 6.11366 16.2732C6.11366 16.2732 6.29366 15.2732 5.88366 14.9132C5.47366 14.5532 5.05366 14.1332 4.74366 13.8532L3.90366 12.8932Z" stroke="black" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.3828 13.4392V9.98739C12.3828 9.78078 12.2149 9.61328 12.0078 9.61328C11.8007 9.61328 11.6328 9.78078 11.6328 9.98739V13.4392C11.6328 13.6458 11.8007 13.8133 12.0078 13.8133C12.2149 13.8133 12.3828 13.6458 12.3828 13.4392Z" fill="black"/>
<path d="M10.4028 13.4379L10.3828 9.98435C10.3816 9.77823 10.2128 9.6121 10.0057 9.61329C9.79855 9.61448 9.63163 9.78253 9.63282 9.98865L9.65282 13.4422C9.65401 13.6483 9.82287 13.8145 10.03 13.8133C10.2371 13.8121 10.404 13.644 10.4028 13.4379Z" fill="black"/>
<path d="M7.63282 9.99227L7.65282 13.4387C7.65403 13.6468 7.8229 13.8145 8.03 13.8133C8.2371 13.8121 8.40401 13.6424 8.40281 13.4343L8.38281 9.98788C8.3816 9.77978 8.21273 9.61207 8.00563 9.61329C7.79852 9.6145 7.63161 9.78418 7.63282 9.99227Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -38,9 +38,11 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
const handleCreateNewProject = async () => {
const token = localStorage.getItem("token");
const refreshToken = localStorage.getItem("refreshToken")
console.log('refreshToken: ', refreshToken);
try {
const projectId = generateProjectId();
useSocketStore.getState().initializeSocket(email, organization, token);
useSocketStore.getState().initializeSocket(email, organization, token, refreshToken);
//API for creating new Project
// const project = await createProject(
@@ -56,7 +58,8 @@ const SidePannel: React.FC<SidePannelProps> = ({ setActiveTab, activeTab }) => {
organization: organization,
projectUuid: projectId,
};
console.log('projectSocket: ', projectSocket);
if (projectSocket) {
const handleResponse = (data: any) => {
if (data.message === "Project created successfully") {

View File

@@ -1,4 +1,4 @@
import React from "react";
import React, { useEffect } from "react";
import { HelpIcon } from "../icons/DashboardIcon";
import { useLogger } from "../ui/log/LoggerContext";
import { GetLogIcon } from "./getLogIcons";
@@ -8,10 +8,14 @@ import {
CurserRightIcon,
} from "../icons/LogIcons";
import ShortcutHelper from "./shortcutHelper";
import useVersionHistoryVisibleStore, { useShortcutStore } from "../../store/builder/store";
import useVersionHistoryVisibleStore, {
useShortcutStore,
} from "../../store/builder/store";
import { usePlayButtonStore } from "../../store/usePlayButtonStore";
import useModuleStore, { useSubModuleStore } from "../../store/useModuleStore";
import { useVersionContext } from "../../modules/builder/version/versionContext";
import { mouseActionHelper } from "../../utils/mouseUtils/mouseHelper";
import { useMouseNoteStore } from "../../store/useUIToggleStore";
const Footer: React.FC = () => {
const { logs, setIsLogListVisible } = useLogger();
@@ -25,28 +29,41 @@ const Footer: React.FC = () => {
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { Leftnote, Middlenote, Rightnote } = useMouseNoteStore();
const mouseButtons = [
{
icon: <CurserLeftIcon />,
label: Leftnote !== "" ? Leftnote : "Pan",
mouse: "left",
},
{
icon: <CurserMiddleIcon />,
label: Middlenote !== "" ? Middlenote : "Scroll Zoom",
mouse: "middle",
},
{
icon: <CurserRightIcon />,
label: Rightnote !== "" ? Rightnote : "Orbit / Cancel action",
mouse: "right",
},
];
useEffect(() => {
const cleanup = mouseActionHelper();
return () => cleanup();
}, []);
return (
<div className="footer-container">
<div className="footer-wrapper">
<div className="selection-wrapper">
<div className="selector-wrapper">
<div className="icon">
<CurserLeftIcon />
{mouseButtons.map(({ icon, label, mouse }) => (
<div className="selector-wrapper" key={mouse}>
<div className="icon">{icon}</div>
<div className="selector">{label}</div>
</div>
<div className="selector">Selection</div>
</div>
<div className="selector-wrapper">
<div className="icon">
<CurserMiddleIcon />
</div>
<div className="selector">Rotate/Zoom</div>
</div>
<div className="selector-wrapper">
<div className="icon">
<CurserRightIcon />
</div>
<div className="selector">Pan/Context Menu</div>
</div>
))}
</div>
<div className="logs-wrapper">
@@ -68,12 +85,15 @@ const Footer: React.FC = () => {
)}
</button>
</div>
<div className="version" onClick={() => {
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule('builder');
}}>
{(selectedVersion?.version) ?? 'v 0.0.0'}
<div
className="version"
onClick={() => {
setVersionHistoryVisible(true);
setSubModule("properties");
setActiveModule("builder");
}}
>
{selectedVersion?.version ?? "v 0.0.0"}
<div className="icon">
<HelpIcon />
</div>
@@ -83,8 +103,9 @@ const Footer: React.FC = () => {
{!isPlaying && (
<div
className={`shortcut-helper-overlay ${showShortcuts ? "visible" : ""
}`}
className={`shortcut-helper-overlay ${
showShortcuts ? "visible" : ""
}`}
>
<ShortcutHelper setShowShortcuts={setShowShortcuts} />
</div>

View File

@@ -9,13 +9,13 @@ export function NotificationIcon() {
>
<path
d="M10 12.8335C10 13.3639 9.78927 13.8726 9.4142 14.2477C9.03913 14.6228 8.5304 14.8335 8 14.8335C7.4696 14.8335 6.96087 14.6228 6.58579 14.2477C6.21072 13.8726 6 13.3639 6 12.8335"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M3.72064 12.1667C3.39434 12.0974 3.10586 11.9084 2.91209 11.6369C2.71832 11.3653 2.63337 11.0311 2.67399 10.7L3.34066 5.29332C3.51087 4.18175 4.07672 3.16901 4.93414 2.44143C5.79156 1.71384 6.88287 1.32036 8.00734 1.33332C9.1318 1.32036 10.2231 1.71384 11.0805 2.44143C11.9379 3.16901 12.5038 4.18175 12.674 5.29332L13.3407 10.7C13.3815 11.0301 13.2975 11.3636 13.1051 11.635C12.9127 11.9063 12.6257 12.096 12.3007 12.1667C9.47907 12.8297 6.54222 12.8297 3.72064 12.1667Z"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>
@@ -34,7 +34,7 @@ export function HomeIcon() {
>
<path
d="M6.91304 13.5V12.8333C6.91304 12.281 7.36076 11.8333 7.91304 11.8333H8.95652C9.50881 11.8333 9.95652 12.281 9.95652 12.8333V13.5C9.95652 14.0523 10.4042 14.5 10.9565 14.5H12C12.5523 14.5 13 14.0523 13 13.5V7.38889L8.21739 2.5L3 7.38889V13.5C3 14.0523 3.44772 14.5 4 14.5H5.91304C6.46533 14.5 6.91304 14.0523 6.91304 13.5Z"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
/>
</svg>
);
@@ -51,7 +51,7 @@ export function ProjectsIcon() {
>
<path
d="M12.1538 1.5H5.69231C5.20268 1.5 4.7331 1.68437 4.38688 2.01256C4.04066 2.34075 3.84615 2.78587 3.84615 3.25C3.35652 3.25 2.88695 3.43437 2.54073 3.76256C2.1945 4.09075 2 4.53587 2 5V13.75C2 14.2141 2.1945 14.6592 2.54073 14.9874C2.88695 15.3156 3.35652 15.5 3.84615 15.5H10.3077C10.7973 15.5 11.2669 15.3156 11.6131 14.9874C11.9593 14.6592 12.1538 14.2141 12.1538 13.75C12.6435 13.75 13.1131 13.5656 13.4593 13.2374C13.8055 12.9092 14 12.4641 14 12V3.25C14 2.78587 13.8055 2.34075 13.4593 2.01256C13.1131 1.68437 12.6435 1.5 12.1538 1.5ZM12.1538 12.875V5C12.1538 4.53587 11.9593 4.09075 11.6131 3.76256C11.2669 3.43437 10.7973 3.25 10.3077 3.25H4.76923C4.76923 3.01794 4.86648 2.79538 5.03959 2.63128C5.2127 2.46719 5.44749 2.375 5.69231 2.375H12.1538C12.3987 2.375 12.6334 2.46719 12.8066 2.63128C12.9797 2.79538 13.0769 3.01794 13.0769 3.25V12C13.0769 12.2321 12.9797 12.4546 12.8066 12.6187C12.6334 12.7828 12.3987 12.875 12.1538 12.875ZM2.92308 5C2.92308 4.76794 3.02033 4.54538 3.19344 4.38128C3.36655 4.21719 3.60134 4.125 3.84615 4.125H10.3077C10.5525 4.125 10.7873 4.21719 10.9604 4.38128C11.1335 4.54538 11.2308 4.76794 11.2308 5V13.75C11.2308 13.9821 11.1335 14.2046 10.9604 14.3687C10.7873 14.5328 10.5525 14.625 10.3077 14.625H3.84615C3.60134 14.625 3.36655 14.5328 3.19344 14.3687C3.02033 14.2046 2.92308 13.9821 2.92308 13.75V5Z"
fill="var(--text-color)"
fill="var(--text-button-color)"
/>
</svg>
);
@@ -70,103 +70,103 @@ export function TutorialsIcon() {
cx="8.157"
cy="8.35866"
r="6.17928"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M7.31894 7.8336L7.30273 7.72125C10.0583 7.32407 11.5796 5.74901 12.1058 5.09033L12.1945 5.1612C11.6598 5.83032 10.1146 7.43067 7.31894 7.8336Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M7.3313 8.19434C7.56713 8.19434 7.7583 8.00316 7.7583 7.76734C7.7583 7.53151 7.56713 7.34033 7.3313 7.34033C7.09547 7.34033 6.9043 7.53151 6.9043 7.76734C6.9043 8.00316 7.09547 8.19434 7.3313 8.19434Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M12.134 5.56787C12.3699 5.56787 12.561 5.3767 12.561 5.14087C12.561 4.90504 12.3699 4.71387 12.134 4.71387C11.8982 4.71387 11.707 4.90504 11.707 5.14087C11.707 5.3767 11.8982 5.56787 12.134 5.56787Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M5.67763 13.0492C5.15009 12.385 4.31304 10.9992 4.63359 9.18018L4.74534 9.20001C4.43251 10.9751 5.25078 12.3292 5.76636 12.9785L5.67763 13.0492Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M4.68921 9.63867C4.92504 9.63867 5.11621 9.4475 5.11621 9.21167C5.11621 8.97584 4.92504 8.78467 4.68921 8.78467C4.45338 8.78467 4.26221 8.97584 4.26221 9.21167C4.26221 9.4475 4.45338 9.63867 4.68921 9.63867Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M5.70923 13.4238C5.94506 13.4238 6.13623 13.2327 6.13623 12.9968C6.13623 12.761 5.94506 12.5698 5.70923 12.5698C5.4734 12.5698 5.28223 12.761 5.28223 12.9968C5.28223 13.2327 5.4734 13.4238 5.70923 13.4238Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M12.4429 9.6101L12.3293 9.60692C12.369 8.18736 11.8263 6.82867 10.801 5.7813C9.73352 4.69047 8.2434 4.07147 6.70876 4.0804L6.70801 3.96684C8.27081 3.96078 9.79333 4.58917 10.8822 5.70181C11.9291 6.77143 12.4833 8.1595 12.4429 9.6101Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M12.3792 10.0142C12.615 10.0142 12.8062 9.82299 12.8062 9.58716C12.8062 9.35133 12.615 9.16016 12.3792 9.16016C12.1433 9.16016 11.9521 9.35133 11.9521 9.58716C11.9521 9.82299 12.1433 10.0142 12.3792 10.0142Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M6.72974 4.4585C6.96556 4.4585 7.15674 4.26732 7.15674 4.0315C7.15674 3.79567 6.96556 3.60449 6.72974 3.60449C6.49391 3.60449 6.30273 3.79567 6.30273 4.0315C6.30273 4.26732 6.49391 4.4585 6.72974 4.4585Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M8.93738 12.7561C5.51197 12.5871 3.18964 10.3443 2.15833 8.30167C1.40017 6.79989 1.28161 5.33657 1.84898 4.48256C2.21511 3.93139 2.7529 3.64179 3.57572 3.69903L3.45825 3.81649C2.67632 3.76183 2.28567 4.03042 1.94346 4.5454C1.39865 5.36549 1.51979 6.78505 2.25963 8.25049C3.27641 10.2647 5.56617 12.476 8.94298 12.6426L8.93738 12.7561Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M4.12372 13.5272C2.54078 13.2677 1.46328 11.9915 1.38697 10.4835C1.31368 9.03292 2.2066 7.3084 4.36675 6.72559L4.39628 6.83521C2.2973 7.40152 1.42936 9.07259 1.50053 10.4778C1.54767 11.4101 2.02721 12.4642 3.18398 12.9967C3.46147 13.1244 3.45807 13.0965 3.77132 13.2139L4.12372 13.5272Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M4.36157 7.21436C4.5974 7.21436 4.78858 7.02318 4.78858 6.78735C4.78858 6.55153 4.5974 6.36035 4.36157 6.36035C4.12575 6.36035 3.93457 6.55153 3.93457 6.78735C3.93457 7.02318 4.12575 7.21436 4.36157 7.21436Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M11.5155 15.1026C11.4663 15.1026 11.4165 15.1003 11.3659 15.0956C10.4065 15.0064 9.53752 14.1202 9.04102 12.7247L9.14807 12.6865C9.62928 14.0393 10.4622 14.8976 11.3764 14.9825C11.8685 15.0293 12.3041 14.8309 12.5152 14.4681C12.7337 14.0928 12.7265 13.7453 12.3977 13.2744L12.5152 13.1569C12.8703 13.6657 12.8548 14.1099 12.6133 14.5252C12.4016 14.8889 11.9895 15.1026 11.5155 15.1026Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M8.9187 13.1187C9.15453 13.1187 9.34571 12.9275 9.34571 12.6917C9.34571 12.4558 9.15453 12.2646 8.9187 12.2646C8.68287 12.2646 8.4917 12.4558 8.4917 12.6917C8.4917 12.9275 8.68287 13.1187 8.9187 13.1187Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M10.0987 3.65056L9.99072 3.61513C10.2487 2.83274 10.7045 2.32867 11.2414 2.23252C11.572 2.17286 11.8969 2.28566 12.0886 2.52597C12.2781 2.76339 12.4042 2.98817 12.2684 3.30782L12.1509 3.19035C12.2699 2.91023 12.1625 2.80064 12.0001 2.59683C11.8344 2.38923 11.5514 2.29248 11.2616 2.34441C10.7669 2.43284 10.3432 2.90906 10.0987 3.65056Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
<path
d="M10.0535 4.04004C10.2893 4.04004 10.4805 3.84887 10.4805 3.61304C10.4805 3.37721 10.2893 3.18604 10.0535 3.18604C9.81764 3.18604 9.62646 3.37721 9.62646 3.61304C9.62646 3.84887 9.81764 4.04004 10.0535 4.04004Z"
fill="var(--text-color)"
stroke="var(--text-color)"
fill="var(--text-button-color)"
stroke="var(--text-button-color)"
strokeWidth="0.562865"
/>
</svg>
@@ -184,12 +184,12 @@ export function DocumentationIcon() {
>
<path
d="M8 5.10589C7.2666 4.17245 6.13604 3.23901 3.33413 3.17051C3.15009 3.16602 3 3.3155 3 3.4996C3 4.86525 3 10.0354 3 11.5645C3 11.7486 3.1501 11.8932 3.33409 11.8992C6.13603 11.9908 7.2666 13.233 8 14.1665M8 5.10589C8.7334 4.17245 9.86393 3.23901 12.6659 3.17051C12.8499 3.16602 13 3.31214 13 3.49624C13 5.02281 13 10.0374 13 11.564C13 11.7481 12.8499 11.8932 12.6659 11.8992C9.864 11.9908 8.7334 13.233 8 14.1665M8 5.10589V14.1665"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
strokeLinejoin="round"
/>
<path
d="M12.8232 4.5H14.333C14.5171 4.5 14.6663 4.64924 14.6663 4.83333V13.526C14.6663 13.7957 14.3485 13.9749 14.102 13.8654C13.5719 13.6299 12.6873 13.3421 11.5291 13.3421C9.56827 13.3421 7.99967 14.5 7.99967 14.5C7.99967 14.5 6.43105 13.3421 4.47026 13.3421C3.31197 13.3421 2.42738 13.6299 1.89732 13.8654C1.65079 13.9749 1.33301 13.7957 1.33301 13.526V4.83333C1.33301 4.64924 1.48225 4.5 1.66634 4.5H3.17615"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
strokeLinejoin="round"
/>
</svg>
@@ -208,7 +208,7 @@ export function HelpIcon() {
<g clipPath="url(#clip0_764_1941)">
<path
d="M6 12.5C2.6862 12.5 0 9.8138 0 6.5C0 3.1862 2.6862 0.5 6 0.5C9.3138 0.5 12 3.1862 12 6.5C12 9.8138 9.3138 12.5 6 12.5ZM3.552 4.8404V4.9016C3.552 4.98117 3.58361 5.05747 3.63987 5.11373C3.69613 5.16999 3.77244 5.2016 3.852 5.2016H4.4502C4.48952 5.2016 4.52845 5.19386 4.56478 5.17881C4.6011 5.16376 4.63411 5.14171 4.66191 5.11391C4.68971 5.08611 4.71176 5.0531 4.72681 5.01678C4.74186 4.98045 4.7496 4.94152 4.7496 4.9022C4.7496 4.1282 5.3484 3.7148 6.1536 3.7148C6.9384 3.7148 7.4544 4.1282 7.4544 4.7168C7.4544 5.2736 7.1652 5.5322 6.4428 5.8628L6.2364 5.9552C5.6274 6.224 5.4 6.626 5.4 7.3286V7.4C5.4 7.47957 5.43161 7.55587 5.48787 7.61213C5.54413 7.66839 5.62044 7.7 5.7 7.7H6.2982C6.33752 7.7 6.37645 7.69226 6.41278 7.67721C6.4491 7.66216 6.48211 7.64011 6.50991 7.61231C6.53771 7.58451 6.55976 7.5515 6.57481 7.51518C6.58986 7.47885 6.5976 7.43992 6.5976 7.4006C6.5976 7.091 6.6804 6.9668 6.9276 6.8534L7.1346 6.7604C8.0016 6.368 8.652 5.852 8.652 4.7264V4.6646C8.652 3.4778 7.62 2.6 6.1536 2.6C4.6668 2.6 3.552 3.4568 3.552 4.8404ZM5.1 9.4946C5.1 10.0148 5.4954 10.4 5.9946 10.4C6.5046 10.4 6.9 10.0148 6.9 9.4946C6.9 8.9744 6.5046 8.6 5.9946 8.6C5.4954 8.6 5.1 8.9744 5.1 9.4946Z"
fill="var(--text-color)"
fill="var(--text-button-color)"
/>
</g>
<defs>
@@ -236,17 +236,17 @@ export function LogoutIcon() {
>
<path
d="M4 3.5C4.00605 2.41248 4.05428 1.82353 4.43847 1.43934C4.87781 1 5.58489 1 6.99914 1H7.49914C8.91334 1 9.62044 1 10.0598 1.43934C10.4991 1.87868 10.4991 2.58578 10.4991 4V8C10.4991 9.4142 10.4991 10.1213 10.0598 10.5606C9.62044 11 8.91334 11 7.49914 11H6.99914C5.58489 11 4.87781 11 4.43847 10.5606C4.05428 10.1764 4.00605 9.5875 4 8.5"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
strokeLinecap="round"
/>
<path
opacity="0.5"
d="M4 9.75C2.82149 9.75 2.23223 9.75 1.86611 9.3839C1.5 9.01775 1.5 8.4285 1.5 7.25V4.75C1.5 3.57149 1.5 2.98224 1.86611 2.61612C2.23223 2.25 2.82149 2.25 4 2.25"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
/>
<path
d="M7.5 6H3M3 6L4 7M3 6L4 5"
stroke="var(--text-color)"
stroke="var(--text-button-color)"
strokeLinecap="round"
strokeLinejoin="round"
/>

View File

@@ -1,11 +1,10 @@
import React, { useEffect, useState } from "react";
import React, { useEffect } from "react";
import RenameInput from "../../../ui/inputs/RenameInput";
import Vector3Input from "../customInput/Vector3Input";
import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore";
import {
useEditPosition,
usezonePosition,
useZones,
usezoneTarget,
} from "../../../../store/builder/store";
import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation";
@@ -19,12 +18,11 @@ const ZoneProperties: React.FC = () => {
const { selectedZone, setSelectedZone } = useSelectedZoneStore();
const { zonePosition, setZonePosition } = usezonePosition();
const { zoneTarget, setZoneTarget } = usezoneTarget();
// const { zones, setZones } = useZones();
const { assetStore, zoneStore } = useSceneContext();
const { zoneStore } = useSceneContext();
const { zones, setZoneName } = zoneStore()
const { projectId } = useParams();
const { userName, userId, organization, email } = getUserData();
const { organization } = getUserData();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();

View File

@@ -28,7 +28,6 @@ const EventProperties: React.FC = () => {
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
useEffect(() => {
const event = getCurrentEventData();
setCurrentEventData(event);

View File

@@ -13,6 +13,7 @@ interface AssemblyActionProps {
swapOptions: string[];
swapDefaultOption: string;
onSwapSelect: (value: string) => void;
clearPoints: () => void;
}
const AssemblyAction: React.FC<AssemblyActionProps> = ({
@@ -20,6 +21,7 @@ const AssemblyAction: React.FC<AssemblyActionProps> = ({
swapOptions,
swapDefaultOption,
onSwapSelect,
clearPoints
}) => {
return (
<>
@@ -37,6 +39,19 @@ const AssemblyAction: React.FC<AssemblyActionProps> = ({
defaultOption={swapDefaultOption}
onSelect={onSwapSelect}
/>
<div className="selected-actions-list">
<div className="value-field-container">
<div className="label">Reset Points</div>
<button
id="reset-button"
type="button"
className="regularDropdown-container"
onClick={clearPoints}
>
Clear
</button>
</div>
</div>
</>
);
};

View File

@@ -8,18 +8,29 @@ interface WorkerActionProps {
max: number;
step: number;
defaultValue: string;
disabled?: boolean,
disabled?: boolean;
onChange: (value: string) => void;
};
loadCount?: {
value: number;
min: number;
max: number;
step: number;
defaultValue: string,
disabled: false,
onChange: (value: number) => void;
};
clearPoints: () => void;
}
const WorkerAction: React.FC<WorkerActionProps> = ({
loadCapacity,
loadCount,
clearPoints,
}) => {
return (
<>
<div className="worker-action-container">
{/* Load Capacity Input */}
<InputWithDropDown
label="Load Capacity"
value={loadCapacity.value}
@@ -32,23 +43,39 @@ const WorkerAction: React.FC<WorkerActionProps> = ({
onClick={() => { }}
onChange={loadCapacity.onChange}
/>
{/* Load Count Input */}
{loadCount && (
<InputWithDropDown
label="Load Count"
value={loadCount.value.toString()}
min={loadCount.min}
max={loadCount.max}
disabled={loadCount.disabled}
defaultValue={loadCount.defaultValue}
step={loadCount.step}
activeOption="unit"
onClick={() => { }}
onChange={(value) => loadCount.onChange(parseInt(value))}
/>
)}
{/* Clear Points Button */}
<div className="selected-actions-list">
<div className="value-field-container">
<div className="label">Reset</div>
<div className="label">Reset Points</div>
<button
id="rest-button"
id="reset-button"
type="button"
className="regularDropdown-container"
onClick={() => {
clearPoints();
}}
onClick={clearPoints}
>
Clear
</button>
</div>
</div>
</>
</div>
);
};
export default WorkerAction;
export default WorkerAction;

View File

@@ -18,10 +18,17 @@ import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
function ConveyorMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default");
const [speed, setSpeed] = useState("0.5");
const [actionName, setActionName] = useState("Action Name");
const [material, setMaterial] = useState("Default material");
const [spawnCount, setSpawnCount] = useState("1");
const [spawnInterval, setSpawnInterval] = useState("1");
const [delay, setDelay] = useState("0");
const [selectedPointData, setSelectedPointData] = useState<ConveyorPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { productStore } = useSceneContext();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore();
const { getPointByUuid, updateEvent, updateAction, getEventByModelUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
@@ -36,9 +43,21 @@ function ConveyorMechanics() {
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as ConveyorPointSchema | undefined;
if (point && "action" in point) {
const event = getEventByModelUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid
) as ConveyorEventSchema | undefined;
if (point && "action" in point && event) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as | "default" | "spawn" | "swap" | "delay" | "despawn");
setActiveOption(point.action.actionType);
setActionName(point.action.actionName);
setSpeed(event.speed?.toString() || "0.5");
setMaterial(point.action.material || "Default material");
setSpawnCount(point.action.spawnCount?.toString() || "1");
setSpawnInterval(point.action.spawnInterval?.toString() || "1");
setDelay(point.action.delay?.toString() || "0");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
@@ -53,19 +72,25 @@ function ConveyorMechanics() {
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
productName,
productUuid,
projectId,
eventDatas: eventData,
versionId: selectedVersion?.versionId || '',
})
}
versionId: selectedVersion?.versionId || "",
});
};
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
const event = updateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, {
speed: parseFloat(value),
});
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
const event = updateEvent(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
{ speed: numericValue }
);
if (event) {
updateBackend(
@@ -75,16 +100,20 @@ function ConveyorMechanics() {
event
);
}
setSpeed(value);
};
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn";
if (!selectedPointData) return;
const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn";
setActiveOption(validOption);
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
actionType: validOption,
});
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ actionType: validOption }
);
if (event) {
updateBackend(
@@ -97,8 +126,14 @@ function ConveyorMechanics() {
};
const handleRenameAction = (newName: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName });
if (!selectedPointData) return;
setActionName(newName);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ actionName: newName }
);
if (event) {
updateBackend(
@@ -111,10 +146,17 @@ function ConveyorMechanics() {
};
const handleSpawnCountChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
spawnCount: parseFloat(value),
});
if (!selectedPointData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setSpawnCount(value);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ spawnCount: numericValue }
);
if (event) {
updateBackend(
@@ -127,10 +169,17 @@ function ConveyorMechanics() {
};
const handleSpawnIntervalChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
spawnInterval: parseFloat(value),
});
if (!selectedPointData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setSpawnInterval(value);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ spawnInterval: numericValue }
);
if (event) {
updateBackend(
@@ -142,9 +191,15 @@ function ConveyorMechanics() {
}
};
const handleMaterialSelect = (material: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { material });
const handleMaterialSelect = (selectedMaterial: string) => {
if (!selectedPointData) return;
setMaterial(selectedMaterial);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ material: selectedMaterial }
);
if (event) {
updateBackend(
@@ -157,10 +212,17 @@ function ConveyorMechanics() {
};
const handleDelayChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
delay: parseFloat(value),
});
if (!selectedPointData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setDelay(value);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ delay: numericValue }
);
if (event) {
updateBackend(
@@ -177,31 +239,6 @@ function ConveyorMechanics() {
options: ["default", "spawn", "swap", "delay", "despawn"],
};
// Get current values from store
const currentSpeed = (getEventByModelUuid(
selectedProduct.productUuid, selectedEventData?.data.modelUuid || ""
) as ConveyorEventSchema | undefined)?.speed?.toString() || "0.5";
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentMaterial = selectedPointData
? selectedPointData.action.material
: "Default material";
const currentSpawnCount = selectedPointData
? selectedPointData.action.spawnCount?.toString() || "1"
: "1";
const currentSpawnInterval = selectedPointData
? selectedPointData.action.spawnInterval?.toString() || "1"
: "1";
const currentDelay = selectedPointData
? selectedPointData.action.delay?.toString() || "0"
: "0";
return (
<>
<div key={selectedPointData?.uuid} className="global-props section">
@@ -209,10 +246,10 @@ function ConveyorMechanics() {
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
value={speed}
min={0}
step={0.1}
defaultValue={"0.5"}
defaultValue="0.5"
max={10}
activeOption="m/s"
onClick={() => { }}
@@ -222,24 +259,18 @@ function ConveyorMechanics() {
</div>
</div>
<section>
<ActionsList
selectedPointData={selectedPointData}
/>
<ActionsList selectedPointData={selectedPointData} />
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
value={actionName}
canEdit={false}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption={
selectedPointData
? selectedPointData.action.actionType
: "default"
}
defaultOption={activeOption}
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
@@ -248,11 +279,11 @@ function ConveyorMechanics() {
<SpawnAction
onChangeCount={handleSpawnCountChange}
options={["Default material", "Material 1", "Material 2", "Material 3"]}
defaultOption={currentMaterial}
defaultOption={material}
onSelect={handleMaterialSelect}
onChangeInterval={handleSpawnIntervalChange}
intervalValue={currentSpawnInterval}
countValue={currentSpawnCount}
intervalValue={spawnInterval}
countValue={spawnCount}
intervalMin={1}
intervalMax={60}
intervalDefaultValue="1"
@@ -264,14 +295,14 @@ function ConveyorMechanics() {
{activeOption === "swap" && (
<SwapAction
options={["Default material", "Material 1", "Material 2", "Material 3"]}
defaultOption={currentMaterial}
defaultOption={material}
onSelect={handleMaterialSelect}
/>
)}
{activeOption === "despawn" && <DespawnAction />}
{activeOption === "delay" && (
<DelayAction
value={currentDelay}
value={delay}
defaultValue="0"
min={0}
max={60}
@@ -288,4 +319,4 @@ function ConveyorMechanics() {
);
}
export default ConveyorMechanics;
export default ConveyorMechanics;

View File

@@ -1,22 +1,25 @@
import { useEffect, useState } from "react";
import { MathUtils } from "three";
import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import ActionsList from "../components/ActionsList";
import WorkerAction from "../actions/workerAction";
import AssemblyAction from "../actions/assemblyAction";
import { useSelectedEventData, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../../../../modules/simulation/products/productContext";
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
import { useParams } from "react-router-dom";
import WorkerAction from "../actions/workerAction";
import AssemblyAction from "../actions/assemblyAction";
function HumanMechanics() {
const [activeOption, setActiveOption] = useState<"worker" | "assembly">("worker");
const [speed, setSpeed] = useState("0.5");
const [loadCount, setLoadCount] = useState(0);
const [loadCapacity, setLoadCapacity] = useState("1");
const [processTime, setProcessTime] = useState(10);
const [swappedMaterial, setSwappedMaterial] = useState("Default material");
@@ -24,7 +27,7 @@ function HumanMechanics() {
const [selectedPointData, setSelectedPointData] = useState<HumanPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { productStore } = useSceneContext();
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction, getEventByModelUuid } = productStore();
const { getPointByUuid, updateEvent, updateAction, addAction, removeAction, getEventByModelUuid, getActionByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
@@ -40,19 +43,21 @@ function HumanMechanics() {
selectedEventData.selectedPoint
) as HumanPointSchema | undefined;
if (point?.action) {
if (point?.actions?.length) {
setSelectedPointData(point);
setCurrentAction(point.action);
setSelectedAction(point.action.actionUuid, point.action.actionName);
const firstAction = point.actions[0];
setCurrentAction(firstAction);
setSpeed((
getEventByModelUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid || ""
) as HumanEventSchema | undefined
)?.speed?.toString() || "1");
setLoadCapacity(point.action.loadCapacity.toString());
setProcessTime(point.action.processTime || 10);
setSwappedMaterial(point.action.swapMaterial || "Default material");
setLoadCapacity(firstAction.loadCapacity.toString());
setActiveOption(firstAction.actionType);
setLoadCount(firstAction.loadCount || 0);
setProcessTime(firstAction.processTime || 10);
setSwappedMaterial(firstAction.swapMaterial || "Default material");
}
} else {
clearSelectedAction();
@@ -60,26 +65,36 @@ function HumanMechanics() {
}, [selectedEventData, selectedProduct]);
useEffect(() => {
if (selectedEventData && selectedProduct.productUuid) {
if (selectedEventData && selectedEventData.data.type === "human") {
const point = getPointByUuid(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint
) as HumanPointSchema | undefined;
if (point?.action) {
setSelectedPointData(point);
setCurrentAction(point.action);
setActiveOption(point.action.actionType);
setSelectedAction(point.action.actionUuid, point.action.actionName);
const actionUuid = selectedAction.actionId || point?.actions[0].actionUuid || '';
const newCurrentAction = getActionByUuid(selectedProduct.productUuid, actionUuid);
if (newCurrentAction && (newCurrentAction.actionType === 'assembly' || newCurrentAction?.actionType === 'worker')) {
if (!selectedAction.actionId) {
setSelectedAction(newCurrentAction.actionUuid, newCurrentAction.actionName);
}
setCurrentAction(newCurrentAction);
setActiveOption(newCurrentAction.actionType);
setLoadCapacity(newCurrentAction.loadCapacity.toString());
setLoadCount(newCurrentAction.loadCount || 0);
if (newCurrentAction.actionType === 'assembly') {
setProcessTime(newCurrentAction.processTime || 10);
setSwappedMaterial(newCurrentAction.swapMaterial || "Default material");
}
} else {
clearSelectedAction();
setCurrentAction(undefined);
}
} else {
clearSelectedAction();
setCurrentAction(undefined);
setSpeed("0.5");
setLoadCapacity("1");
}
}, [selectedEventData, selectedProduct, selectedAction]);
}, [selectedAction, selectedProduct, selectedEventData]);
const updateBackend = (
productName: string,
@@ -99,8 +114,9 @@ function HumanMechanics() {
const handleSelectActionType = (actionType: string) => {
if (!selectedAction.actionId || !currentAction || !selectedPointData) return;
const updatedAction = { ...currentAction, actionType: actionType as "worker" };
const updatedPoint = { ...selectedPointData, action: updatedAction };
const updatedAction = { ...currentAction, actionType: actionType as "worker" | "assembly" };
const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = updateAction(
selectedProduct.productUuid,
@@ -143,10 +159,9 @@ function HumanMechanics() {
const handleLoadCapacityChange = (value: string) => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAction = { ...currentAction };
updatedAction.loadCapacity = parseInt(value)
const updatedPoint = { ...selectedPointData, action: updatedAction };
const updatedAction = { ...currentAction, loadCapacity: parseInt(value) };
const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = updateAction(
selectedProduct.productUuid,
@@ -163,13 +178,34 @@ function HumanMechanics() {
setLoadCapacity(value);
};
const handleLoadCountChange = (value: number) => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAction = { ...currentAction, loadCount: value };
const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
updatedAction
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
setCurrentAction(updatedAction);
setSelectedPointData(updatedPoint);
setLoadCount(value);
};
const handleProcessTimeChange = (value: number) => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAction = { ...currentAction };
updatedAction.processTime = value
const updatedPoint = { ...selectedPointData, action: updatedAction };
const updatedAction = { ...currentAction, processTime: value };
const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = updateAction(
selectedProduct.productUuid,
@@ -189,10 +225,9 @@ function HumanMechanics() {
const handleMaterialChange = (value: string) => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAction = { ...currentAction };
updatedAction.swapMaterial = value
const updatedPoint = { ...selectedPointData, action: updatedAction };
const updatedAction = { ...currentAction, swapMaterial: value };
const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = updateAction(
selectedProduct.productUuid,
@@ -212,11 +247,17 @@ function HumanMechanics() {
const handleClearPoints = () => {
if (!currentAction || !selectedPointData || !selectedAction.actionId) return;
const updatedAction = { ...currentAction };
delete updatedAction.pickUpPoint;
delete updatedAction.dropPoint;
const updatedAction: HumanAction = JSON.parse(JSON.stringify(currentAction));
const updatedPoint = { ...selectedPointData, action: updatedAction };
if (updatedAction.actionType === 'assembly') {
updatedAction.assemblyPoint = { position: null, rotation: null, }
} else {
updatedAction.pickUpPoint = { position: null, rotation: null, };
updatedAction.dropPoint = { position: null, rotation: null, }
}
const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action);
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = updateAction(
selectedProduct.productUuid,
@@ -237,12 +278,17 @@ function HumanMechanics() {
const newAction: HumanAction = {
actionUuid: MathUtils.generateUUID(),
actionName: `Action`,
actionName: `Action ${selectedPointData.actions.length + 1}`,
actionType: "worker",
loadCount: 1,
loadCapacity: 1,
processTime: 10,
triggers: [],
};
const updatedActions = [...(selectedPointData.actions || []), newAction];
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = addAction(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
@@ -254,27 +300,39 @@ function HumanMechanics() {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
const updatedPoint = { ...selectedPointData, action: newAction };
setSelectedPointData(updatedPoint);
setSelectedAction(newAction.actionUuid, newAction.actionName);
};
const handleDeleteAction = () => {
if (!selectedPointData) return;
if (!selectedPointData || !selectedAction.actionId) return;
const updatedActions = selectedPointData.actions.filter(action => action.actionUuid !== selectedAction.actionId);
const updatedPoint = { ...selectedPointData, actions: updatedActions };
const event = removeAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid
selectedAction.actionId
);
if (event) {
updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event);
}
const updatedPoint = { ...selectedPointData, action: undefined as any };
setSelectedPointData(updatedPoint);
clearSelectedAction();
setCurrentAction(undefined);
const index = selectedPointData.actions.findIndex((a) => a.actionUuid === selectedAction.actionId);
const nextAction = updatedPoint.actions[index] || updatedPoint.actions[index - 1];
if (nextAction) {
setSelectedAction(nextAction.actionUuid, nextAction.actionName);
const action = getActionByUuid(selectedProduct.productUuid, nextAction.actionUuid);
if (action) {
setCurrentAction(action as HumanAction);
}
} else {
clearSelectedAction();
setCurrentAction(undefined);
}
};
return (
@@ -299,7 +357,7 @@ function HumanMechanics() {
<section>
<ActionsList
selectedPointData={selectedPointData}
multipleAction={false}
multipleAction={true}
handleAddAction={handleAddAction}
handleDeleteAction={handleDeleteAction}
/>
@@ -315,7 +373,7 @@ function HumanMechanics() {
defaultOption={activeOption}
options={["worker", "assembly"]}
onSelect={handleSelectActionType}
disabled={true}
disabled={false}
/>
</div>
{currentAction.actionType === 'worker' &&
@@ -323,12 +381,21 @@ function HumanMechanics() {
loadCapacity={{
value: loadCapacity,
min: 1,
max: 5,
max: 20,
step: 1,
defaultValue: "10",
defaultValue: "1",
disabled: true,
onChange: handleLoadCapacityChange,
}}
loadCount={{
value: loadCount,
min: 0,
max: 20,
step: 1,
defaultValue: "1",
disabled: false,
onChange: handleLoadCountChange,
}}
clearPoints={handleClearPoints}
/>
}
@@ -343,6 +410,7 @@ function HumanMechanics() {
swapOptions={["Default material", "Material 1", "Material 2", "Material 3"]}
swapDefaultOption={swappedMaterial}
onSwapSelect={handleMaterialChange}
clearPoints={handleClearPoints}
/>
}
<div className="tirgger">

View File

@@ -12,8 +12,12 @@ import { useVersionContext } from "../../../../../../modules/builder/version/ver
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
function MachineMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "process">("default");
const [activeOption, setActiveOption] = useState<"process">("process");
const [actionName, setActionName] = useState("Action Name");
const [processTime, setProcessTime] = useState("1");
const [material, setMaterial] = useState("Default material");
const [selectedPointData, setSelectedPointData] = useState<MachinePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { productStore } = useSceneContext();
const { getPointByUuid, updateAction } = productStore();
@@ -31,9 +35,13 @@ function MachineMechanics() {
selectedEventData?.data.modelUuid,
selectedEventData?.selectedPoint
) as MachinePointSchema | undefined;
if (point && "action" in point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "process");
setActionName(point.action.actionName);
setProcessTime(point.action.processTime?.toString() || "1");
setMaterial(point.action.swapMaterial || "Default material");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
@@ -48,22 +56,25 @@ function MachineMechanics() {
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
productName,
productUuid,
projectId,
eventDatas: eventData,
versionId: selectedVersion?.versionId || '',
})
}
versionId: selectedVersion?.versionId || "",
});
};
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
if (!selectedPointData) return;
const validOption = option as "process";
setActiveOption(validOption);
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
actionType: validOption,
});
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ actionType: validOption }
);
if (event) {
updateBackend(
@@ -77,7 +88,13 @@ function MachineMechanics() {
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName });
setActionName(newName);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ actionName: newName }
);
if (event) {
updateBackend(
@@ -91,9 +108,16 @@ function MachineMechanics() {
const handleProcessTimeChange = (value: string) => {
if (!selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
processTime: parseFloat(value),
});
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setProcessTime(value);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ processTime: numericValue }
);
if (event) {
updateBackend(
@@ -105,11 +129,15 @@ function MachineMechanics() {
}
};
const handleMaterialSelect = (material: string) => {
const handleMaterialSelect = (selectedMaterial: string) => {
if (!selectedPointData) return;
const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, {
swapMaterial: material,
});
setMaterial(selectedMaterial);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{ swapMaterial: selectedMaterial }
);
if (event) {
updateBackend(
@@ -121,19 +149,6 @@ function MachineMechanics() {
}
};
// Get current values from store
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentProcessTime = selectedPointData
? selectedPointData.action.processTime.toString()
: "1";
const currentMaterial = selectedPointData
? selectedPointData.action.swapMaterial
: "Default material";
const availableActions = {
defaultOption: "process",
options: ["process"],
@@ -146,28 +161,26 @@ function MachineMechanics() {
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
value={actionName}
canEdit={false}
/>
</div>
<ActionsList
selectedPointData={selectedPointData}
/>
<ActionsList selectedPointData={selectedPointData} />
<div className="selected-actions-list">
<LabledDropdown
defaultOption="process"
defaultOption={activeOption}
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
{activeOption === "process" && (
<ProcessAction
value={currentProcessTime}
value={processTime}
min={0.1}
max={60}
defaultValue="1"
onChange={handleProcessTimeChange}
swapOptions={["Default material", "Material 1", "Material 2", "Material 3"]}
swapDefaultOption={currentMaterial}
swapDefaultOption={material}
onSwapSelect={handleMaterialSelect}
/>
)}
@@ -182,4 +195,4 @@ function MachineMechanics() {
);
}
export default MachineMechanics;
export default MachineMechanics;

View File

@@ -14,11 +14,13 @@ import { useVersionContext } from "../../../../../../modules/builder/version/ver
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
function RoboticArmMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default");
const [activeOption, setActiveOption] = useState<"pickAndPlace">("pickAndPlace");
const [speed, setSpeed] = useState("0.5");
const [selectedPointData, setSelectedPointData] = useState<RoboticArmPointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { productStore } = useSceneContext();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction, } = productStore();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction();
@@ -33,16 +35,20 @@ function RoboticArmMechanics() {
selectedEventData.data.modelUuid,
selectedEventData.selectedPoint
) as RoboticArmPointSchema | undefined;
if (point?.actions) {
setSelectedPointData(point);
setSpeed(
(getEventByModelUuid(
selectedProduct.productUuid,
selectedEventData.data.modelUuid
) as RoboticArmEventSchema | undefined)?.speed?.toString() || "0.5"
);
if (point.actions.length > 0) {
setActiveOption(
point.actions[0].actionType as "default" | "pickAndPlace"
);
setSelectedAction(
point.actions[0].actionUuid,
point.actions[0].actionName
);
const firstAction = point.actions[0];
setActiveOption(firstAction.actionType);
setSelectedAction(firstAction.actionUuid, firstAction.actionName);
}
}
} else {
@@ -57,33 +63,33 @@ function RoboticArmMechanics() {
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
productName,
productUuid,
projectId,
eventDatas: eventData,
versionId: selectedVersion?.versionId || '',
versionId: selectedVersion?.versionId || "",
});
};
const handleRenameAction = (newName: string) => {
if (!selectedAction.actionId) return;
if (!selectedAction.actionId || !selectedPointData) return;
const event = updateAction(
selectedProduct.productUuid,
selectedAction.actionId,
{ actionName: newName }
);
if (selectedPointData) {
const updatedActions = selectedPointData.actions.map((action) =>
action.actionUuid === selectedAction.actionId
? { ...action, actionName: newName }
: action
);
setSelectedPointData({
...selectedPointData,
actions: updatedActions,
});
}
const updatedActions = selectedPointData.actions.map(action =>
action.actionUuid === selectedAction.actionId
? { ...action, actionName: newName }
: action
);
setSelectedPointData({
...selectedPointData,
actions: updatedActions,
});
if (event) {
updateBackend(
@@ -97,10 +103,15 @@ function RoboticArmMechanics() {
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setSpeed(value);
const event = updateEvent(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
{ speed: parseFloat(value), }
{ speed: numericValue }
);
if (event) {
@@ -112,6 +123,7 @@ function RoboticArmMechanics() {
);
}
};
const handleClearPoints = () => {
if (!selectedAction.actionId || !selectedPointData) return;
@@ -166,15 +178,20 @@ function RoboticArmMechanics() {
);
}
const updatedPoint = { ...selectedPointData, actions: [...selectedPointData.actions, newAction], };
setSelectedPointData(updatedPoint);
setSelectedPointData({
...selectedPointData,
actions: [...selectedPointData.actions, newAction],
});
setSelectedAction(newAction.actionUuid, newAction.actionName);
};
const handleDeleteAction = (actionUuid: string) => {
if (!selectedPointData) return;
const event = removeAction(selectedProduct.productUuid, actionUuid);
const event = removeAction(
selectedProduct.productUuid,
actionUuid
);
if (event) {
updateBackend(
@@ -185,14 +202,13 @@ function RoboticArmMechanics() {
);
}
const index = selectedPointData.actions.findIndex((a) => a.actionUuid === actionUuid);
const newActions = selectedPointData.actions.filter((a) => a.actionUuid !== actionUuid);
const index = selectedPointData.actions.findIndex(a => a.actionUuid === actionUuid);
const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid);
const updatedPoint = {
setSelectedPointData({
...selectedPointData,
actions: newActions,
};
setSelectedPointData(updatedPoint);
});
if (selectedAction.actionId === actionUuid) {
const nextAction = newActions[index] || newActions[index - 1];
@@ -209,16 +225,7 @@ function RoboticArmMechanics() {
options: ["pickAndPlace"],
};
const currentSpeed = (getEventByModelUuid(selectedProduct.productUuid, selectedEventData?.data.modelUuid || "") as RoboticArmEventSchema | undefined)?.speed?.toString() || "0.5";
const currentAction = selectedPointData?.actions.find((a) => a.actionUuid === selectedAction.actionId);
const currentPickPoint = currentAction?.process.startPoint
? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}`
: "";
const currentPlacePoint = currentAction?.process.endPoint
? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}`
: "";
const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId);
return (
<>
@@ -227,10 +234,10 @@ function RoboticArmMechanics() {
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
value={speed}
min={0}
step={0.1}
defaultValue={"0.5"}
defaultValue="0.5"
max={10}
activeOption="m/s"
onClick={() => { }}
@@ -252,7 +259,7 @@ function RoboticArmMechanics() {
<div className="selected-actions-header">
<RenameInput
value={selectedAction.actionName || ""}
onRename={handleRenameAction}
canEdit={false}
/>
</div>
<div className="selected-actions-list">
@@ -277,4 +284,4 @@ function RoboticArmMechanics() {
);
}
export default RoboticArmMechanics;
export default RoboticArmMechanics;

View File

@@ -192,7 +192,7 @@ function StorageMechanics() {
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
canEdit={false}
/>
</div>
<div className="selected-actions-list">

View File

@@ -3,10 +3,7 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown";
import RenameInput from "../../../../../ui/inputs/RenameInput";
import LabledDropdown from "../../../../../ui/inputs/LabledDropdown";
import Trigger from "../trigger/Trigger";
import {
useSelectedAction,
useSelectedEventData,
} from "../../../../../../store/simulation/useSimulationStore";
import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore";
import TravelAction from "../actions/TravelAction";
import ActionsList from "../components/ActionsList";
import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi";
@@ -14,19 +11,26 @@ import { useProductContext } from "../../../../../../modules/simulation/products
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../../../../../modules/builder/version/versionContext";
import { useSceneContext } from "../../../../../../modules/scene/sceneContext";
import { useSelectedPath } from "../../../../../../store/builder/store";
function VehicleMechanics() {
const [activeOption, setActiveOption] = useState<"default" | "travel">("default");
const [activeOption, setActiveOption] = useState<"travel">("travel");
const [speed, setSpeed] = useState("0.5");
const [actionName, setActionName] = useState("Action Name");
const [loadCapacity, setLoadCapacity] = useState("1");
const [unloadDuration, setUnloadDuration] = useState("1");
const [selectedPointData, setSelectedPointData] = useState<VehiclePointSchema | undefined>();
const { selectedEventData } = useSelectedEventData();
const { productStore } = useSceneContext();
const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore();
const { getPointByUuid, updateEvent, updateAction, getEventByModelUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setSelectedAction, clearSelectedAction } = useSelectedAction();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { setSelectedPath } = useSelectedPath();
useEffect(() => {
if (selectedEventData && selectedEventData.data.type === "vehicle") {
@@ -39,6 +43,15 @@ function VehicleMechanics() {
if (point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "travel");
setActionName(point.action.actionName);
setSpeed(
(getEventByModelUuid(
selectedProduct.productUuid,
selectedEventData.data.modelUuid
) as VehicleEventSchema | undefined)?.speed?.toString() || "0.5"
);
setLoadCapacity(point.action.loadCapacity?.toString() || "1");
setUnloadDuration(point.action.unLoadDuration?.toString() || "1");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
@@ -53,22 +66,25 @@ function VehicleMechanics() {
eventData: EventsSchema
) => {
upsertProductOrEventApi({
productName: productName,
productUuid: productUuid,
projectId: projectId,
productName,
productUuid,
projectId,
eventDatas: eventData,
versionId: selectedVersion?.versionId || '',
versionId: selectedVersion?.versionId || "",
});
};
const handleSpeedChange = (value: string) => {
if (!selectedEventData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setSpeed(value);
const event = updateEvent(
selectedProduct.productUuid,
selectedEventData.data.modelUuid,
{
speed: parseFloat(value),
}
{ speed: numericValue }
);
if (event) {
@@ -82,16 +98,15 @@ function VehicleMechanics() {
};
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
if (!selectedPointData) return;
const validOption = option as "travel";
setActiveOption(validOption);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{
actionType: validOption,
}
{ actionType: validOption }
);
if (event) {
@@ -106,6 +121,8 @@ function VehicleMechanics() {
const handleRenameAction = (newName: string) => {
if (!selectedPointData) return;
setActionName(newName);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
@@ -124,12 +141,15 @@ function VehicleMechanics() {
const handleLoadCapacityChange = (value: string) => {
if (!selectedPointData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setLoadCapacity(value);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{
loadCapacity: parseFloat(value),
}
{ loadCapacity: numericValue }
);
if (event) {
@@ -144,12 +164,15 @@ function VehicleMechanics() {
const handleUnloadDurationChange = (value: string) => {
if (!selectedPointData) return;
const numericValue = parseFloat(value);
if (isNaN(numericValue)) return;
setUnloadDuration(value);
const event = updateAction(
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{
unLoadDuration: parseFloat(value),
}
{ unLoadDuration: numericValue }
);
if (event) {
@@ -162,46 +185,18 @@ function VehicleMechanics() {
}
};
const handlePickPointChange = (value: string) => {
const handleClearPoints = () => {
if (!selectedPointData) return;
};
const handleUnloadPointChange = (value: string) => {
if (!selectedPointData) return;
};
// Get current values from store
const currentSpeed =
(
getEventByModelUuid(
selectedProduct.productUuid,
selectedEventData?.data.modelUuid || ""
) as VehicleEventSchema | undefined
)?.speed?.toString() || "0.5";
const currentActionName = selectedPointData
? selectedPointData.action.actionName
: "Action Name";
const currentLoadCapacity = selectedPointData
? selectedPointData.action.loadCapacity.toString()
: "1";
const currentUnloadDuration = selectedPointData
? selectedPointData.action.unLoadDuration.toString()
: "1";
function handleClearPoints() {
if (!selectedEventData || !selectedPointData?.action.actionUuid) return;
const event = updateAction(
selectedProduct.productUuid, selectedPointData.action.actionUuid, {
pickUpPoint: null,
unLoadPoint: null,
steeringAngle: 0,
})
selectedProduct.productUuid,
selectedPointData.action.actionUuid,
{
pickUpPoint: null,
unLoadPoint: null,
steeringAngle: 0,
}
);
if (event) {
updateBackend(
@@ -211,7 +206,7 @@ function VehicleMechanics() {
event
);
}
}
};
const availableActions = {
defaultOption: "travel",
@@ -227,10 +222,10 @@ function VehicleMechanics() {
<div className="property-item">
<InputWithDropDown
label="Speed"
value={currentSpeed}
value={speed}
min={0}
step={0.1}
defaultValue={"0.5"}
defaultValue="0.5"
max={10}
activeOption="m/s"
onClick={() => { }}
@@ -244,13 +239,13 @@ function VehicleMechanics() {
<div className="selected-actions-details">
<div className="selected-actions-header">
<RenameInput
value={currentActionName}
onRename={handleRenameAction}
value={actionName}
canEdit={false}
/>
</div>
<div className="selected-actions-list">
<LabledDropdown
defaultOption="travel"
defaultOption={activeOption}
options={availableActions.options}
onSelect={handleActionTypeChange}
/>
@@ -258,14 +253,14 @@ function VehicleMechanics() {
{activeOption === "travel" && (
<TravelAction
loadCapacity={{
value: currentLoadCapacity,
value: loadCapacity,
min: 1,
max: 100,
defaultValue: "1",
onChange: handleLoadCapacityChange,
}}
unloadDuration={{
value: currentUnloadDuration,
value: unloadDuration,
min: 1,
max: 60,
defaultValue: "1",
@@ -282,6 +277,43 @@ function VehicleMechanics() {
type={"Vehicle"}
/>
</div>
<div style={{
display: "flex",
gap: "10px",
flexDirection: "column",
alignItems: "center"
}}>
<button
style={{
backgroundColor: "#6f42c1",
color: "#f3f3fd",
borderRadius: "15px",
height: "30px",
width: "150px",
border: "none",
cursor: "pointer",
padding: "0 5px",
}}
onClick={() => setSelectedPath("auto")}
>
Auto Generate Path
</button>
<button
style={{
backgroundColor: "#6f42c1",
color: "#f3f3fd",
borderRadius: "15px",
height: "30px",
width: "150px",
border: "none",
cursor: "pointer",
padding: "0 5px",
}}
onClick={() => setSelectedPath("manual")}
>
Create Path
</button>
</div>
</section>
</>
)}
@@ -289,4 +321,4 @@ function VehicleMechanics() {
);
}
export default VehicleMechanics;
export default VehicleMechanics;

View File

@@ -65,8 +65,11 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => {
const action = getActionByUuid(selectedProduct.productUuid, currentAction);
const actionTriggers = action?.triggers || [];
setTriggers(actionTriggers);
if (actionTriggers.length === 0) {
setSelectedTrigger(undefined);
}
setSelectedTrigger(actionTriggers[0]);
}, [currentAction, selectedProduct]);
}, [currentAction, selectedProduct, selectedTrigger, selectedPointData]);
const triggeredModel = useMemo(() => {
if (!selectedProduct || !selectedTrigger?.triggeredAsset?.triggeredModel?.modelUuid)

View File

@@ -22,7 +22,6 @@ import { useSelectedZoneStore } from "../../store/visualization/useZoneStore";
import {
useActiveTool,
useAddAction,
useRefTextUpdate,
useSelectedWallItem,
useSocketStore,
useToggleView,
@@ -75,7 +74,6 @@ const Tools: React.FC = () => {
const { setActiveSubTool, activeSubTool } = useActiveSubTool();
const { setSelectedWallItem } = useSelectedWallItem();
const { setRefTextUpdate } = useRefTextUpdate();
const { setToggleUI } = useToggleStore();
const { setToggleView, toggleView } = useToggleView();
@@ -131,7 +129,6 @@ const Tools: React.FC = () => {
const resetTools = () => {
setToolMode(null);
setAddAction(null);
setRefTextUpdate((prev) => prev - 1);
};
const updateToolBehavior = (tool: string, is2D: boolean) => {
@@ -406,7 +403,6 @@ const useStoreHooks = () => {
...useActiveTool(),
...useToolMode(),
...useAddAction(),
...useRefTextUpdate(),
};
};

View File

@@ -2,93 +2,89 @@ import React, { useState } from "react";
import RenameInput from "./RenameInput";
type InputWithDropDownProps = {
label: string;
value: string;
min?: number;
max?: number;
step?: number;
defaultValue?: string;
disabled?: boolean;
options?: string[]; // Array of dropdown options
activeOption?: string; // The currently active dropdown option
onClick?: () => void;
onChange: (newValue: string) => void;
editableLabel?: boolean;
placeholder?: string; // New placeholder prop
label: string;
value: string;
min?: number;
max?: number;
step?: number;
defaultValue?: string;
disabled?: boolean;
options?: string[];
activeOption?: string;
onClick?: () => void;
onChange: (newValue: string) => void;
editableLabel?: boolean;
placeholder?: string;
};
const InputWithDropDown: React.FC<InputWithDropDownProps> = ({
label,
value,
min,
max,
step,
defaultValue,
disabled = false,
options,
activeOption,
onClick,
onChange,
editableLabel = false,
placeholder = "Inherit", // Default empty placeholder
label,
value,
min,
max,
step,
defaultValue,
disabled = false,
options,
activeOption,
onClick,
onChange,
editableLabel = false,
placeholder = "Inherit",
}) => {
const separatedWords = label
.split(/(?=[A-Z])/)
.map((word) => word.trim())
.toString();
const [openDropdown, setOpenDropdown] = useState(false);
const [openDropdown, setOpenDropdown] = useState(false);
const separatedWords = label
.split(/(?=[A-Z])/)
.map((word) => word.trim())
.join(" ");
return (
<div className="value-field-container">
{editableLabel ? (
<RenameInput value={label} />
) : (
<label htmlFor={separatedWords} className="label">
{label}
</label>
)}
<div className="input default" id={separatedWords}>
<input
min={min}
max={max}
step={step}
type="number"
defaultValue={value}
// value={value}
disabled={disabled}
onChange={(e) => {
onChange(e.target.value);
}}
placeholder={placeholder} // Added placeholder prop
/>
{activeOption && (
<div
className="dropdown"
onClick={() => {
setOpenDropdown(true);
}}
>
<div className="active-option">{activeOption}</div>
{options && openDropdown && (
<div className="dropdown-options-list">
{options.map((option, index) => (
<div
key={index}
className={"dropdown-option"}
onClick={onClick}
>
{option}
</div>
))}
</div>
return (
<div className="value-field-container">
{editableLabel ? (
<RenameInput value={label} />
) : (
<label htmlFor={separatedWords} className="label">
{label}
</label>
)}
</div>
)}
</div>
</div>
);
<div className="input default" id={separatedWords}>
<input
min={min}
max={max}
step={step}
type="number"
value={value} // Controlled input
disabled={disabled}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
/>
{activeOption && (
<div
className="dropdown"
onClick={() => setOpenDropdown((prev) => !prev)}
>
<div className="active-option">{activeOption}</div>
{options && openDropdown && (
<div className="dropdown-options-list">
{options.map((option, index) => (
<div
key={index}
className="dropdown-option"
onClick={onClick}
>
{option}
</div>
))}
</div>
)}
</div>
)}
</div>
</div>
);
};
export default InputWithDropDown;
export default InputWithDropDown;

View File

@@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react";
import List from "./List";
import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons";
import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect";
import { useZones } from "../../../store/builder/store";
import { useSceneContext } from "../../../modules/scene/sceneContext";
interface DropDownListProps {
@@ -44,14 +43,12 @@ const DropDownList: React.FC<DropDownListProps> = ({
remove,
}) => {
const [isOpen, setIsOpen] = useState<boolean>(defaultOpen);
// const { zones } = useZones();
const handleToggle = () => {
setIsOpen((prev) => !prev); // Toggle the state
};
const [zoneDataList, setZoneDataList] = useState<ZoneData[]>([]);
// const { assetStore } = useSceneContext();
const { assetStore, zoneStore } = useSceneContext();
const { assets } = assetStore();
const { zones } = zoneStore()

View File

@@ -14,7 +14,6 @@ import {
} from "../../icons/ExportCommonIcons";
import {
useZoneAssetId,
useZones,
} from "../../../store/builder/store";
import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation";
import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi";

View File

@@ -34,7 +34,7 @@ import { useComparisonProduct } from "../../../store/simulation/useSimulationSto
import InputToggle from "../inputs/InputToggle";
const SimulationPlayer: React.FC = () => {
const MAX_SPEED = 4; // Maximum speed
const MAX_SPEED = 8; // Maximum speed
const isDragging = useRef(false);
const sliderRef = useRef<HTMLDivElement>(null);
@@ -109,12 +109,24 @@ const SimulationPlayer: React.FC = () => {
isDragging.current = false;
};
const handleVisibility = () => {
if (document.visibilityState !== 'visible' && isPlaying) {
setIsPaused(!isPaused);
if (isPaused) {
setIsPlaying(true);
}
echo.warn(`Simulation is ${isPaused ? "Resumed" : "Paused"}`);
}
}
useEffect(() => {
document.addEventListener("mousemove", handleMouseMove);
document.addEventListener("mouseup", handleMouseUp);
document.addEventListener('visibilitychange', handleVisibility);
return () => {
document.removeEventListener("mousemove", handleMouseMove);
document.removeEventListener("mouseup", handleMouseUp);
document.removeEventListener('visibilitychange', handleVisibility);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

View File

@@ -139,6 +139,11 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: []
}
}
@@ -256,14 +261,17 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) {
uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(),
position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0],
rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCapacity: 1,
triggers: []
}
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCount: 1,
loadCapacity: 1,
processTime: 10,
triggers: []
}
]
}
}
addEvent(humanEvent);

View File

@@ -262,6 +262,11 @@ async function handleModelLoad(
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: [],
},
},
@@ -373,14 +378,17 @@ async function handleModelLoad(
uuid: THREE.MathUtils.generateUUID(),
position: [data.points[0].x, data.points[0].y, data.points[0].z],
rotation: [0, 0, 0],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCapacity: 1,
triggers: []
}
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCount: 1,
loadCapacity: 1,
processTime: 10,
triggers: []
}
]
}
}
addEvent(humanEvent);

View File

@@ -17,7 +17,7 @@ import { useParams } from 'react-router-dom';
import { getUserData } from '../../../../../functions/getUserData';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useVersionContext } from '../../../version/versionContext';
import { useAnimationPlaySpeed } from '../../../../../store/usePlayButtonStore';
import { useAnimationPlaySpeed, usePauseButtonStore } from '../../../../../store/usePlayButtonStore';
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';
import { getAssetIksApi } from '../../../../../services/simulation/ik/getAssetIKs';
import ConveyorCollider from './conveyorCollider';
@@ -31,6 +31,7 @@ function Model({ asset }: { readonly asset: Asset }) {
const { subModule } = useSubModuleStore();
const { activeModule } = useModuleStore();
const { speed } = useAnimationPlaySpeed();
const { isPaused } = usePauseButtonStore();
const { assetStore, eventStore, productStore } = useSceneContext();
const { removeAsset, setAnimations, resetAnimation, setAnimationComplete } = assetStore();
const { setTop } = useTopData();
@@ -395,7 +396,7 @@ function Model({ asset }: { readonly asset: Asset }) {
const currentAction = actions.current[current];
const previousAction = previousAnimation ? actions.current[previousAnimation] : null;
if (isPlaying && currentAction) {
if (isPlaying && currentAction && activeModule === 'simulation' && !isPaused) {
blendFactor.current = 0;
currentAction.reset();
@@ -418,7 +419,7 @@ function Model({ asset }: { readonly asset: Asset }) {
mixerRef.current.removeEventListener('finished', handleAnimationComplete);
}
};
}, [asset.animationState?.current, asset.animationState?.isPlaying]);
}, [asset.animationState?.current, asset.animationState?.isCompleted, asset.animationState?.isPlaying, isPaused, activeModule]);
useEffect(() => {
const canvasElement = gl.domElement;
@@ -526,15 +527,7 @@ function Model({ asset }: { readonly asset: Asset }) {
<ConveyorCollider boundingBox={boundingBox}
asset={asset}
conveyorPlaneSize={conveyorPlaneSize}
onReachEnd={(rigidBody) => {
// Option A: Reset the same object
rigidBody.setTranslation({ x: 0, y: 10, z: 0 }, true);
rigidBody.setLinvel({ x: 0, y: 0, z: 0 }, true);
rigidBody.setAngvel({ x: 0, y: 0, z: 0 }, true);
rigidBody.wakeUp();
// Option B: You can also call a function that sets a state to "add a new rigid body"
}} />
/>
</>
)}
</group>

View File

@@ -1,9 +1,8 @@
import { useEffect, useRef } from 'react';
import { useActiveLayer, useDfxUpload, useSocketStore, useToggleView, useUpdateScene } from '../../../store/builder/store';
import { useActiveLayer, useDfxUpload, useSocketStore, useToggleView } from '../../../store/builder/store';
import { LineBasicMaterial, Line } from 'three';
import { TransformControls } from '@react-three/drei';
import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBlueprint';
import * as Types from '../../../types/world/worldTypes';
import { useParams } from 'react-router-dom';
import { getUserData } from '../../../functions/getUserData';
import { useVersionContext } from '../version/versionContext';

View File

@@ -9,6 +9,8 @@ import * as Constants from '../../../types/world/worldConstants';
import { useVersionContext } from '../version/versionContext';
import { useParams } from 'react-router-dom';
import { getUserData } from '../../../functions/getUserData';
import { handleCanvasCursors } from '../../../utils/mouseUtils/handleCanvasCursors';
import { useSelectedPoints } from '../../../store/simulation/useSimulationStore';
// import { upsertWallApi } from '../../../services/factoryBuilder/wall/upsertWallApi';
// import { deleteWallApi } from '../../../services/factoryBuilder/wall/deleteWallApi';
@@ -23,7 +25,7 @@ interface LineProps {
function Line({ points }: Readonly<LineProps>) {
const [isHovered, setIsHovered] = useState(false);
const { raycaster, camera, pointer, gl } = useThree();
const { raycaster, camera, pointer } = useThree();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const [isDeletable, setIsDeletable] = useState(false);
const { socket } = useSocketStore();
@@ -38,6 +40,7 @@ function Line({ points }: Readonly<LineProps>) {
const { projectId } = useParams();
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
const { hoveredLine, setHoveredLine, hoveredPoint } = useBuilderStore();
const { selectedPoints } = useSelectedPoints();
const path = useMemo(() => {
const [start, end] = points.map(p => new THREE.Vector3(...p.position));
@@ -213,7 +216,7 @@ function Line({ points }: Readonly<LineProps>) {
});
}
}
gl.domElement.style.cursor = 'default';
handleCanvasCursors('default');
}
}
@@ -224,7 +227,7 @@ function Line({ points }: Readonly<LineProps>) {
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) {
gl.domElement.style.cursor = 'move';
handleCanvasCursors('grabbing');
const positionWithOffset = new THREE.Vector3().addVectors(hit, dragOffset);
const start = new THREE.Vector3(...points[0].position);
@@ -269,7 +272,7 @@ function Line({ points }: Readonly<LineProps>) {
const handleDragEnd = (points: [Point, Point]) => {
if (toolMode !== 'move' || !dragOffset) return;
gl.domElement.style.cursor = 'default';
handleCanvasCursors('default');
setDragOffset(null);
if (points[0].pointType === 'Wall' && points[1].pointType === 'Wall') {
const updatedWalls1 = getWallsByPointId(points[0].pointUuid);
@@ -372,19 +375,21 @@ function Line({ points }: Readonly<LineProps>) {
onClick={() => {
handlePointClick(points);
}}
onPointerOver={() => {
if (!hoveredLine) {
onPointerOver={(e) => {
if (selectedPoints.length === 0 && e.buttons === 0 && !e.ctrlKey) {
setHoveredLine(points);
setIsHovered(true)
if (toolMode === 'move' && !hoveredPoint) {
gl.domElement.style.cursor = 'pointer';
handleCanvasCursors('grab');
}
}
}}
onPointerOut={() => {
if (hoveredLine) {
if (hoveredLine && isHovered) {
setHoveredLine(null);
gl.domElement.style.cursor = 'default';
if (!hoveredPoint) {
handleCanvasCursors('default');
}
}
setIsHovered(false)
}}

View File

@@ -5,6 +5,7 @@ import { useSocketStore, useToolMode } from '../../../store/builder/store';
import { DragControls } from '@react-three/drei';
import { useThree } from '@react-three/fiber';
import { useBuilderStore } from '../../../store/builder/useBuilderStore';
import { useSelectedPoints } from '../../../store/simulation/useSimulationStore';
import { usePointSnapping } from './helpers/usePointSnapping';
import { useParams } from 'react-router-dom';
import { useVersionContext } from '../version/versionContext';
@@ -20,12 +21,14 @@ import { useSceneContext } from '../../scene/sceneContext';
// import { deleteZoneApi } from '../../../services/factoryBuilder/zone/deleteZoneApi';
import { getUserData } from '../../../functions/getUserData';
import { handleCanvasCursors } from '../../../utils/mouseUtils/handleCanvasCursors';
function Point({ point }: { readonly point: Point }) {
const materialRef = useRef<THREE.ShaderMaterial>(null);
const { raycaster, camera, pointer, gl } = useThree();
const { raycaster, camera, pointer } = useThree();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const [isHovered, setIsHovered] = useState(false);
const [isSelected, setIsSelected] = useState(false);
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
const { socket } = useSocketStore();
const { toolMode } = useToolMode();
@@ -35,7 +38,8 @@ function Point({ point }: { readonly point: Point }) {
const { setPosition: setFloorPosition, removePoint: removeFloorPoint, getFloorsByPointId } = floorStore();
const { setPosition: setZonePosition, removePoint: removeZonePoint, getZonesByPointId } = zoneStore();
const { snapAislePoint, snapAisleAngle, snapWallPoint, snapWallAngle, snapFloorPoint, snapFloorAngle, snapZonePoint, snapZoneAngle } = usePointSnapping({ uuid: point.pointUuid, pointType: point.pointType, position: point.position });
const { hoveredPoint, setHoveredPoint } = useBuilderStore();
const { hoveredPoint,hoveredLine, setHoveredPoint } = useBuilderStore();
const { selectedPoints } = useSelectedPoints();
const { userId, organization } = getUserData();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
@@ -44,7 +48,7 @@ function Point({ point }: { readonly point: Point }) {
const colors = getColor(point);
useEffect(() => {
gl.domElement.style.cursor = 'default';
handleCanvasCursors('default');
}, [toolMode])
function getColor(point: Point) {
@@ -114,7 +118,7 @@ function Point({ point }: { readonly point: Point }) {
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) {
gl.domElement.style.cursor = 'move';
handleCanvasCursors('grabbing');
const positionWithOffset = new THREE.Vector3().addVectors(hit, dragOffset);
const newPosition: [number, number, number] = [positionWithOffset.x, positionWithOffset.y, positionWithOffset.z];
@@ -152,7 +156,7 @@ function Point({ point }: { readonly point: Point }) {
};
const handleDragEnd = (point: Point) => {
gl.domElement.style.cursor = 'default';
handleCanvasCursors('default');
setDragOffset(null);
if (toolMode !== 'move') return;
if (point.pointType === 'Aisle') {
@@ -396,7 +400,7 @@ function Point({ point }: { readonly point: Point }) {
});
}
}
gl.domElement.style.cursor = 'default';
handleCanvasCursors('default');
}
}
@@ -406,50 +410,63 @@ function Point({ point }: { readonly point: Point }) {
}
}, [hoveredPoint])
useEffect(() => {
if (selectedPoints.length > 0 && selectedPoints.some((selectedPoint) => (selectedPoint.userData.pointUuid && selectedPoint.userData.pointUuid === point.pointUuid))) {
setIsSelected(true);
} else {
setIsSelected(false);
}
}, [selectedPoints])
if (!point) {
return null;
}
return (
<DragControls
axisLock='y'
autoTransform={false}
onDragStart={() => handleDragStart(point)}
onDrag={() => handleDrag(point)}
onDragEnd={() => handleDragEnd(point)}
>
<mesh
key={point.pointUuid}
uuid={point.pointUuid}
name={`${point.pointType}-Point`}
position={new THREE.Vector3(...point.position)}
onClick={() => {
handlePointClick(point);
}}
onPointerOver={() => {
if (!hoveredPoint) {
setHoveredPoint(point);
setIsHovered(true);
if (toolMode === 'move') {
gl.domElement.style.cursor = 'pointer';
}
}
}}
onPointerOut={() => {
if (hoveredPoint) {
setHoveredPoint(null);
gl.domElement.style.cursor = 'default';
}
setIsHovered(false)
}}
userData={point}
>
<boxGeometry args={boxScale} />
<shaderMaterial
ref={materialRef}
uniforms={uniforms}
vertexShader={
`
<>
{!isSelected ?
<DragControls
axisLock='y'
autoTransform={false}
onDragStart={() => handleDragStart(point)}
onDrag={() => handleDrag(point)}
onDragEnd={() => handleDragEnd(point)}
>
<mesh
key={point.pointUuid}
uuid={point.pointUuid}
name={`${point.pointType}-Point`}
position={[...point.position]}
onClick={() => {
handlePointClick(point);
}}
onPointerOver={(e) => {
if (!hoveredPoint && selectedPoints.length === 0 && e.buttons === 0 && !e.ctrlKey) {
setHoveredPoint(point);
setIsHovered(true);
if (toolMode === 'move') {
handleCanvasCursors('grab');
}
}
}}
onPointerOut={() => {
if (hoveredPoint) {
setHoveredPoint(null);
if(!hoveredLine){
handleCanvasCursors('default');
}
}
setIsHovered(false)
}}
userData={point}
>
<boxGeometry args={boxScale} />
<shaderMaterial
ref={materialRef}
uniforms={uniforms}
vertexShader={
`
varying vec2 vUv;
void main() {
@@ -457,9 +474,9 @@ function Point({ point }: { readonly point: Point }) {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`
}
fragmentShader={
`
}
fragmentShader={
`
varying vec2 vUv;
uniform vec3 uOuterColor;
uniform vec3 uInnerColor;
@@ -474,10 +491,32 @@ function Point({ point }: { readonly point: Point }) {
}
}
`
}
/>
</mesh>
</DragControls>
}
/>
</mesh>
</DragControls>
:
<group
key={point.pointUuid}
uuid={point.pointUuid}
name={`${point.pointType}-Point`}
position={[point.position[0], 0.3, point.position[2]]}
userData={point}
rotation={[Math.PI / 2, 0, 0]}
>
<mesh>
<torusGeometry args={[0.4, 0.1, 2, 16]} />
<meshBasicMaterial color="#6F42C1" />
</mesh>
<mesh position={[0, 0, 0]}>
<sphereGeometry args={[0.3, 8, 16]} />
<meshBasicMaterial color="white" />
</mesh>
</group>
}
</>
);
}

View File

@@ -85,13 +85,45 @@ export function useWallClassification(walls: Walls) {
}));
}
const allCoords = mergedLineStrings.flatMap(ls => ls.geometry.coordinates);
const uniqueCoords = Array.from(new Set(allCoords.map(coord => coord.join(','))));
if (uniqueCoords.length < 4) return [];
const validLineStrings = mergedLineStrings.map(ls => {
const coords = ls.geometry.coordinates.map(coord => coord.join(','));
const lineStrings = turf.featureCollection(mergedLineStrings);
if (coords.length < 2) return null;
const polygons = turf.polygonize(lineStrings);
const start = coords[0];
const end = coords[coords.length - 1];
const middle = coords.slice(1, -1);
const seen = new Set<string>([start, end]);
const filteredMiddle: string[] = [];
for (const point of middle) {
if (!seen.has(point)) {
seen.add(point);
filteredMiddle.push(point);
}
}
const newCoords = [start, ...filteredMiddle, end];
if (newCoords.length >= 4) {
const resultCoords = newCoords.map(str => str.split(',').map(Number));
return {
...ls,
geometry: {
...ls.geometry,
coordinates: resultCoords,
},
};
}
return null;
}).filter(Boolean);
if (validLineStrings.length === 0) return [];
const lineStrings = turf.featureCollection(validLineStrings as any);
const polygons = turf.polygonize(lineStrings as any);
const rooms: Point[][] = [];

View File

@@ -152,9 +152,9 @@ function Wall({ wall }: { readonly wall: Wall }) {
>
<MeshDiscardMaterial />
{wall.decals.map((decal) => (
{/* {wall.decals.map((decal) => (
<DecalInstance zPosition={wall.wallThickness / 2 + 0.001} visible={visible} key={decal.decalUuid} decal={decal} />
))}
))} */}
</mesh>
</mesh>
);

View File

@@ -255,6 +255,8 @@ const CamModelsGroup = () => {
setCams((prev) => dedupeCams([...prev, ...newCams]));
});
}
}).catch(() => {
console.log('Error fetching active users data')
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

View File

@@ -9,10 +9,11 @@ import { getCamera } from "../../../services/factoryBuilder/camera/getCameraApi"
import updateCamPosition from "../camera/updateCameraPosition";
import CamMode from "../camera/camMode";
import SwitchView from "../camera/switchView";
import SelectionControls from "./selectionControls/selectionControls";
import SelectionControls3D from "./selectionControls/selection3D/selectionControls3D";
import TransformControl from "./transformControls/transformControls";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../functions/getUserData";
import SelectionControls2D from "./selectionControls/selection2D/selectionControls2D";
export default function Controls() {
const controlsRef = useRef<CameraControls>(null);
@@ -137,7 +138,9 @@ export default function Controls() {
</CameraControls>
<SelectionControls />
<SelectionControls3D />
<SelectionControls2D />
<TransformControl />

View File

@@ -0,0 +1,341 @@
import * as THREE from "three";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
import { useSelectedPoints } from "../../../../../store/simulation/useSimulationStore";
import useModuleStore from "../../../../../store/useModuleStore";
// import { upsertAisleApi } from "../../../../../services/factoryBuilder/aisle/upsertAisleApi";
// import { upsertWallApi } from "../../../../../services/factoryBuilder/wall/upsertWallApi";
// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
function MoveControls2D({
movedObjects,
setMovedObjects,
pastedObjects,
setpastedObjects,
duplicatedObjects,
setDuplicatedObjects,
rotatedObjects,
setRotatedObjects,
}: any) {
const { camera, controls, gl, scene, pointer, raycaster } = useThree();
const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []);
const { toolMode } = useToolMode();
const { toggleView } = useToggleView();
const { activeModule } = useModuleStore();
const { selectedPoints, clearSelectedPoints } = useSelectedPoints();
const { socket } = useSocketStore();
const { userId, organization } = getUserData();
const { projectId } = useParams();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
const { setPosition: setAislePosition, getAislesByPointId } = aisleStore();
const { setPosition: setWallPosition, getWallsByPointId } = wallStore();
const { setPosition: setFloorPosition, getFloorsByPointId } = floorStore();
const { setPosition: setZonePosition, getZonesByPointId } = zoneStore();
const [dragOffset, setDragOffset] = useState<THREE.Vector3 | null>(null);
const [initialPositions, setInitialPositions] = useState<Record<string, THREE.Vector3>>({});
const [initialStates, setInitialStates] = useState<Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }>>({});
const [isMoving, setIsMoving] = useState(false);
useEffect(() => {
if (!camera || !scene || !toggleView) return;
const canvasElement = gl.domElement;
canvasElement.tabIndex = 0;
let isMoving = false;
const onPointerDown = () => {
isMoving = false;
};
const onPointerMove = () => {
isMoving = true;
};
const onPointerUp = (event: PointerEvent) => {
if (!isMoving && movedObjects.length > 0 && event.button === 0) {
event.preventDefault();
placeMovedAssets();
}
if (!isMoving && movedObjects.length > 0 && event.button === 2) {
event.preventDefault();
clearSelection();
setMovedObjects([]);
resetToInitialPositions();
}
};
const onKeyDown = (event: KeyboardEvent) => {
const keyCombination = detectModifierKeys(event);
if (pastedObjects.length > 0 || duplicatedObjects.length > 0 || rotatedObjects.length > 0) return;
if (keyCombination === "G") {
if (selectedPoints.length > 0) {
moveAssets();
}
}
if (keyCombination === "ESCAPE") {
event.preventDefault();
clearSelection();
setMovedObjects([]);
resetToInitialPositions();
}
};
if (toggleView && selectedPoints.length > 0) {
canvasElement.addEventListener("pointerdown", onPointerDown);
canvasElement.addEventListener("pointermove", onPointerMove);
canvasElement.addEventListener("pointerup", onPointerUp);
canvasElement.addEventListener("keydown", onKeyDown);
}
return () => {
canvasElement.removeEventListener("pointerdown", onPointerDown);
canvasElement.removeEventListener("pointermove", onPointerMove);
canvasElement.removeEventListener("pointerup", onPointerUp);
canvasElement.removeEventListener("keydown", onKeyDown);
};
}, [camera, controls, scene, toggleView, selectedPoints, socket, pastedObjects, duplicatedObjects, movedObjects, rotatedObjects]);
useEffect(() => {
if (toolMode !== 'move' || !toggleView) {
if (movedObjects.length > 0) {
resetToInitialPositions();
}
clearSelection();
}
}, [activeModule, toolMode, toggleView, movedObjects]);
useFrame(() => {
if (!isMoving || movedObjects.length === 0 || !dragOffset) return;
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit) {
const baseNewPosition = new THREE.Vector3().addVectors(hit, dragOffset);
movedObjects.forEach((movedPoint: THREE.Object3D) => {
if (movedPoint.userData.pointUuid) {
const point: Point = movedPoint.userData as Point;
const initialPosition = initialPositions[movedPoint.uuid];
if (initialPosition) {
const relativeOffset = new THREE.Vector3().subVectors(
initialPosition,
initialPositions[movedObjects[0].uuid]
);
const newPosition = new THREE.Vector3().addVectors(baseNewPosition, relativeOffset);
const positionArray: [number, number, number] = [newPosition.x, newPosition.y, newPosition.z];
if (point.pointType === 'Aisle') {
setAislePosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Wall') {
setWallPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Floor') {
setFloorPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Zone') {
setZonePosition(point.pointUuid, positionArray);
}
}
}
});
}
});
const calculateDragOffset = useCallback((point: THREE.Object3D, hitPoint: THREE.Vector3) => {
const pointPosition = new THREE.Vector3().copy(point.position);
return new THREE.Vector3().subVectors(pointPosition, hitPoint);
}, []);
const moveAssets = useCallback(() => {
if (selectedPoints.length === 0) return;
const states: Record<string, { position: THREE.Vector3; rotation?: THREE.Euler; }> = {};
selectedPoints.forEach((point: THREE.Object3D) => {
states[point.uuid] = {
position: new THREE.Vector3().copy(point.position),
rotation: point.rotation ? new THREE.Euler().copy(point.rotation) : undefined
};
});
setInitialStates(states);
const positions: Record<string, THREE.Vector3> = {};
selectedPoints.forEach((point: THREE.Object3D) => { positions[point.uuid] = new THREE.Vector3().copy(point.position); });
setInitialPositions(positions);
raycaster.setFromCamera(pointer, camera);
const intersectionPoint = new THREE.Vector3();
const hit = raycaster.ray.intersectPlane(plane, intersectionPoint);
if (hit && selectedPoints[0]) {
const offset = calculateDragOffset(selectedPoints[0], hit);
setDragOffset(offset);
}
setMovedObjects(selectedPoints);
setIsMoving(true);
}, [selectedPoints, camera, pointer, plane, raycaster, calculateDragOffset]);
const resetToInitialPositions = useCallback(() => {
setTimeout(() => {
movedObjects.forEach((movedPoint: THREE.Object3D) => {
if (movedPoint.userData.pointUuid && initialStates[movedPoint.uuid]) {
const point: Point = movedPoint.userData as Point;
const initialState = initialStates[movedPoint.uuid];
const positionArray: [number, number, number] = [
initialState.position.x,
initialState.position.y,
initialState.position.z
];
if (point.pointType === 'Aisle') {
setAislePosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Wall') {
setWallPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Floor') {
setFloorPosition(point.pointUuid, positionArray);
} else if (point.pointType === 'Zone') {
setZonePosition(point.pointUuid, positionArray);
}
}
});
}, 0)
}, [movedObjects, initialStates, setAislePosition, setWallPosition, setFloorPosition, setZonePosition]);
const placeMovedAssets = () => {
if (movedObjects.length === 0) return;
movedObjects.forEach((movedObject: THREE.Object3D) => {
if (movedObject.userData.pointUuid) {
const point: Point = movedObject.userData as Point;
if (point.pointType === 'Aisle') {
const updatedAisles = getAislesByPointId(point.pointUuid);
if (updatedAisles.length > 0 && projectId) {
updatedAisles.forEach((updatedAisle) => {
// API
// upsertAisleApi(updatedAisle.aisleUuid, updatedAisle.points, updatedAisle.type, projectId, selectedVersion?.versionId || '');
// SOCKET
socket.emit('v1:model-aisle:add', {
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization,
aisleUuid: updatedAisle.aisleUuid,
points: updatedAisle.points,
type: updatedAisle.type
})
})
}
} else if (point.pointType === 'Wall') {
const updatedWalls = getWallsByPointId(point.pointUuid);
if (updatedWalls && updatedWalls.length > 0 && projectId) {
updatedWalls.forEach((updatedWall) => {
// API
// upsertWallApi(projectId, selectedVersion?.versionId || '', updatedWall);
// SOCKET
const data = {
wallData: updatedWall,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Wall:add', data);
});
}
} else if (point.pointType === 'Floor') {
const updatedFloors = getFloorsByPointId(point.pointUuid);
if (updatedFloors && updatedFloors.length > 0 && projectId) {
updatedFloors.forEach((updatedFloor) => {
// API
// upsertFloorApi(projectId, selectedVersion?.versionId || '', updatedFloor);
// SOCKET
const data = {
floorData: updatedFloor,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Floor:add', data);
});
}
} else if (point.pointType === 'Zone') {
const updatedZones = getZonesByPointId(point.pointUuid);
if (updatedZones && updatedZones.length > 0 && projectId) {
updatedZones.forEach((updatedZone) => {
// API
// upsertZoneApi(projectId, selectedVersion?.versionId || '', updatedZone);
// SOCKET
const data = {
zoneData: updatedZone,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:zone:add', data);
});
}
}
}
})
echo.success("Object moved!");
clearSelection();
};
const clearSelection = () => {
setpastedObjects([]);
setDuplicatedObjects([]);
setMovedObjects([]);
setRotatedObjects([]);
clearSelectedPoints();
};
return (
<>
</>
);
}
export default MoveControls2D;

View File

@@ -0,0 +1,389 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import { SelectionHelper } from "../selectionHelper";
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
import useModuleStore from "../../../../../store/useModuleStore";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
import { useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
import { useSelectedPoints } from "../../../../../store/simulation/useSimulationStore";
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
import MoveControls2D from "./moveControls2D";
// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
// import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi";
// import { deleteFloorApi } from "../../../../../services/factoryBuilder/floor/deleteFloorApi";
// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
// import { deleteZoneApi } from "../../../../../services/factoryBuilder/zone/deleteZoneApi";
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";
const SelectionControls2D: React.FC = () => {
const { camera, controls, gl, scene, raycaster, pointer } = useThree();
const { toggleView } = useToggleView();
const { selectedPoints, setSelectedPoints, clearSelectedPoints } = useSelectedPoints();
const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
const [copiedObjects, setCopiedObjects] = useState<THREE.Object3D[]>([]);
const [pastedObjects, setpastedObjects] = useState<THREE.Object3D[]>([]);
const [duplicatedObjects, setDuplicatedObjects] = useState<THREE.Object3D[]>([]);
const { activeModule } = useModuleStore();
const { socket } = useSocketStore();
const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
const { toolMode } = useToolMode();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const { hoveredLine, hoveredPoint } = useBuilderStore();
const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
const { removePoint: removeAislePoint } = aisleStore();
const { removePoint: removeWallPoint } = wallStore();
const { removePoint: removeFloorPoint } = floorStore();
const { removePoint: removeZonePoint } = zoneStore();
const isDragging = useRef(false);
const isLeftMouseDown = useRef(false);
const isSelecting = useRef(false);
const isRightClick = useRef(false);
const rightClickMoved = useRef(false);
const isCtrlSelecting = useRef(false);
const isShiftSelecting = useRef(false);
const { userId, organization } = getUserData();
useEffect(() => {
if (!camera || !scene || !toggleView) return;
const canvasElement = gl.domElement;
canvasElement.tabIndex = 0;
const helper = new SelectionHelper(gl);
const onPointerDown = (event: PointerEvent) => {
if (event.button === 2) {
isRightClick.current = true;
rightClickMoved.current = false;
} else if (event.button === 0) {
isSelecting.current = false;
isCtrlSelecting.current = event.ctrlKey;
isShiftSelecting.current = event.shiftKey;
isLeftMouseDown.current = true;
isDragging.current = false;
if (event.ctrlKey && duplicatedObjects.length === 0) {
if (controls) (controls as any).enabled = false;
selectionBox.startPoint.set(pointer.x, pointer.y, 0);
}
}
};
const onPointerMove = (event: PointerEvent) => {
if (isRightClick.current) {
rightClickMoved.current = true;
}
if (isLeftMouseDown.current) {
isDragging.current = true;
}
isSelecting.current = true;
if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting.current) {
selectionBox.endPoint.set(pointer.x, pointer.y, 0);
}
};
const onPointerUp = (event: PointerEvent) => {
if (event.button === 2 && !event.ctrlKey && !event.shiftKey) {
isRightClick.current = false;
if (!rightClickMoved.current) {
clearSelection();
}
return;
}
if (isSelecting.current && isCtrlSelecting.current) {
isCtrlSelecting.current = false;
isSelecting.current = false;
if (event.ctrlKey && duplicatedObjects.length === 0) {
selectAssets();
}
} else if (!isSelecting.current && selectedPoints.length > 0 && ((!event.ctrlKey && !event.shiftKey && pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) || event.button !== 0)) {
clearSelection();
helper.enabled = true;
isCtrlSelecting.current = false;
} else if (controls) {
(controls as any).enabled = true;
}
if (!isDragging.current && isLeftMouseDown.current && isShiftSelecting.current && event.shiftKey) {
isShiftSelecting.current = false;
isLeftMouseDown.current = false;
isDragging.current = false;
} else if (controls) {
(controls as any).enabled = true;
}
};
const onKeyDown = (event: KeyboardEvent) => {
if (movedObjects.length > 0 || rotatedObjects.length > 0) return;
if (event.key.toLowerCase() === "escape") {
event.preventDefault();
clearSelection();
}
if (event.key.toLowerCase() === "delete") {
event.preventDefault();
deleteSelection();
}
};
const onContextMenu = (event: MouseEvent) => {
event.preventDefault();
if (!rightClickMoved.current) {
clearSelection();
}
rightClickMoved.current = false;
};
if (toggleView && toolMode === 'move') {
helper.enabled = true;
canvasElement.addEventListener("pointermove", onPointerMove);
canvasElement.addEventListener("pointerup", onPointerUp);
canvasElement.addEventListener("pointerdown", onPointerDown);
canvasElement.addEventListener("contextmenu", onContextMenu);
canvasElement.addEventListener("keydown", onKeyDown);
} else {
helper.enabled = false;
helper.dispose();
}
return () => {
canvasElement.removeEventListener("pointerdown", onPointerDown);
canvasElement.removeEventListener("pointermove", onPointerMove);
canvasElement.removeEventListener("contextmenu", onContextMenu);
canvasElement.removeEventListener("pointerup", onPointerUp);
canvasElement.removeEventListener("keydown", onKeyDown);
helper.enabled = false;
helper.dispose();
};
}, [camera, controls, scene, toggleView, selectedPoints, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, rotatedObjects, toolMode, hoveredLine, hoveredPoint]);
useEffect(() => {
if (toolMode !== 'move' || !toggleView) {
clearSelection();
}
}, [activeModule, toolMode, toggleView]);
const selectAssets = useCallback(() => {
selectionBox.endPoint.set(pointer.x, pointer.y, 0);
if (controls) (controls as any).enabled = true;
let selectedObjects = selectionBox.select();
let Objects = new Set<THREE.Object3D>();
selectedObjects.forEach((object) => {
let currentObject: THREE.Object3D | null = object;
while (currentObject) {
if (currentObject.userData.pointUuid) {
Objects.add(currentObject);
break;
}
currentObject = currentObject.parent || null;
}
});
if (Objects.size === 0) {
clearSelection();
return;
}
const updatedSelections = new Set<THREE.Object3D>(selectedPoints);
Objects.forEach((obj) => {
const existing = Array.from(updatedSelections).find((o) => o.userData?.pointUuid === obj.userData?.pointUuid);
if (existing) {
updatedSelections.delete(existing);
} else {
updatedSelections.add(obj);
}
});
const selected = Array.from(updatedSelections);
setSelectedPoints(selected);
}, [selectionBox, pointer, controls, selectedPoints, setSelectedPoints]);
const clearSelection = () => {
setpastedObjects([]);
setDuplicatedObjects([]);
clearSelectedPoints();
};
const deleteSelection = () => {
if (selectedPoints.length > 0 && duplicatedObjects.length === 0) {
selectedPoints.forEach((selectedPoint) => {
if (selectedPoint.userData.pointUuid) {
const point: Point = selectedPoint.userData as Point;
if (point.pointType === 'Aisle') {
const removedAisles = removeAislePoint(point.pointUuid);
if (removedAisles.length > 0) {
removedAisles.forEach(aisle => {
if (projectId) {
// API
// deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '');
// SOCKET
const data = {
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization,
aisleUuid: aisle.aisleUuid
}
socket.emit('v1:model-aisle:delete', data);
}
});
}
}
if (point.pointType === 'Wall') {
const removedWalls = removeWallPoint(point.pointUuid);
if (removedWalls.length > 0) {
removedWalls.forEach(wall => {
if (projectId) {
// API
// deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);
// SOCKET
const data = {
wallUuid: wall.wallUuid,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Wall:delete', data);
}
});
}
}
if (point.pointType === 'Floor') {
const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid);
if (removedFloors.length > 0) {
removedFloors.forEach(floor => {
if (projectId) {
// API
// deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);
// SOCKET
const data = {
floorUuid: floor.floorUuid,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Floor:delete', data);
}
});
}
if (updatedFloors.length > 0) {
updatedFloors.forEach(floor => {
if (projectId) {
// API
// upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);
// SOCKET
const data = {
floorData: floor,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:model-Floor:add', data);
}
});
}
}
if (point.pointType === 'Zone') {
const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
if (removedZones.length > 0) {
removedZones.forEach(zone => {
if (projectId) {
// API
// deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);
// SOCKET
const data = {
zoneUuid: zone.zoneUuid,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:zone:delete', data);
}
});
}
if (updatedZones.length > 0) {
updatedZones.forEach(zone => {
if (projectId) {
// API
// upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);
// SOCKET
const data = {
zoneData: zone,
projectId: projectId,
versionId: selectedVersion?.versionId || '',
userId: userId,
organization: organization
}
socket.emit('v1:zone:add', data);
}
});
}
}
}
})
}
echo.success("Selected points removed!");
clearSelection();
};
return (
<>
<MoveControls2D movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} />
</>
);
};
export default SelectionControls2D;

View File

@@ -1,7 +1,7 @@
import { Line } from "@react-three/drei";
import { useMemo } from "react";
import * as THREE from "three";
import { useSelectedAssets } from "../../../../store/builder/store";
import { useSelectedAssets } from "../../../../../store/builder/store";
interface BoundingBoxProps {
boundingBoxRef?: any;

View File

@@ -2,17 +2,17 @@ import * as THREE from "three";
import { useEffect, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { SkeletonUtils } from "three-stdlib";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store";
import * as Types from "../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
import * as Types from "../../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../functions/getUserData";
import { useSceneContext } from "../../sceneContext";
import { useVersionContext } from "../../../builder/version/versionContext";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
const CopyPasteControls = ({
const CopyPasteControls3D = ({
copiedObjects,
setCopiedObjects,
pastedObjects,
@@ -239,6 +239,11 @@ const CopyPasteControls = ({
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: []
}
}
@@ -352,13 +357,17 @@ const CopyPasteControls = ({
uuid: THREE.MathUtils.generateUUID(),
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCapacity: 1,
triggers: []
}
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCapacity: 1,
loadCount: 1,
processTime: 10,
triggers: []
}
]
}
}
addEvent(humanEvent);
@@ -495,4 +504,4 @@ const CopyPasteControls = ({
return null;
};
export default CopyPasteControls;
export default CopyPasteControls3D;

View File

@@ -2,17 +2,17 @@ import * as THREE from "three";
import { useEffect, useMemo } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { SkeletonUtils } from "three-stdlib";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store";
import * as Types from "../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
import * as Types from "../../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../functions/getUserData";
import { useSceneContext } from "../../sceneContext";
import { useVersionContext } from "../../../builder/version/versionContext";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
const DuplicationControls = ({
const DuplicationControls3D = ({
duplicatedObjects,
setDuplicatedObjects,
setpastedObjects,
@@ -213,6 +213,11 @@ const DuplicationControls = ({
steeringAngle: 0,
pickUpPoint: null,
unLoadPoint: null,
paths: {
initPickup: [],
pickupDrop: [],
dropPickup: [],
},
triggers: []
}
}
@@ -326,13 +331,17 @@ const DuplicationControls = ({
uuid: THREE.MathUtils.generateUUID(),
position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]],
rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]],
action: {
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCapacity: 1,
triggers: []
}
actions: [
{
actionUuid: THREE.MathUtils.generateUUID(),
actionName: "Action 1",
actionType: "worker",
loadCapacity: 1,
loadCount: 1,
processTime: 10,
triggers: []
}
]
}
}
addEvent(humanEvent);
@@ -464,4 +473,4 @@ const DuplicationControls = ({
return null;
};
export default DuplicationControls;
export default DuplicationControls3D;

View File

@@ -1,20 +1,21 @@
import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useSelectedAssets, useSocketStore, useToggleView, } from "../../../../store/builder/store";
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
import * as Types from "../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { snapControls } from "../../../../utils/handleSnap";
import { useSelectedAssets, useSocketStore, useToggleView, } from "../../../../../store/builder/store";
import * as Types from "../../../../../types/world/worldTypes";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
import { snapControls } from "../../../../../utils/handleSnap";
import DistanceFindingControls from "./distanceFindingControls";
import { useParams } from "react-router-dom";
import { useProductContext } from "../../../simulation/products/productContext";
import { getUserData } from "../../../../functions/getUserData";
import { useSceneContext } from "../../sceneContext";
import { useVersionContext } from "../../../builder/version/versionContext";
import { useProductContext } from "../../../../simulation/products/productContext";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
function MoveControls({
// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
function MoveControls3D({
movedObjects,
setMovedObjects,
pastedObjects,
@@ -364,4 +365,4 @@ function MoveControls({
);
}
export default MoveControls;
export default MoveControls3D;

View File

@@ -1,17 +1,18 @@
import * as THREE from "three";
import { useEffect, useMemo, useRef } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/builder/store";
// import { setAssetsApi } from '../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
import * as Types from "../../../../types/world/worldTypes";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { useSelectedAssets, useSocketStore, useToggleView } from "../../../../../store/builder/store";
import * as Types from "../../../../../types/world/worldTypes";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useParams } from "react-router-dom";
import { useProductContext } from "../../../simulation/products/productContext";
import { getUserData } from "../../../../functions/getUserData";
import { useSceneContext } from "../../sceneContext";
import { useVersionContext } from "../../../builder/version/versionContext";
import { useProductContext } from "../../../../simulation/products/productContext";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
function RotateControls({
// import { setAssetsApi } from '../../../../../services/factoryBuilder/asset/floorAsset/setAssetsApi';
function RotateControls3D({
rotatedObjects,
setRotatedObjects,
movedObjects,
@@ -300,4 +301,4 @@ function RotateControls({
return null;
}
export default RotateControls
export default RotateControls3D

View File

@@ -1,26 +1,27 @@
import * as THREE from "three";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
import { SelectionHelper } from "./selectionHelper";
import * as THREE from "three";
import { useFrame, useThree } from "@react-three/fiber";
import { useSelectedAssets, useSocketStore, useToggleView, useToolMode, } from "../../../../store/builder/store";
import BoundingBox from "./boundingBoxHelper";
// import { deleteFloorItem } from '../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi';
import * as Types from "../../../../types/world/worldTypes";
import { SelectionHelper } from "../selectionHelper";
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";
import * as Types from "../../../../../types/world/worldTypes";
import DuplicationControls from "./duplicationControls";
import CopyPasteControls from "./copyPasteControls";
import MoveControls from "./moveControls";
import RotateControls from "./rotateControls";
import useModuleStore from "../../../../store/useModuleStore";
import useModuleStore from "../../../../../store/useModuleStore";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../functions/getUserData";
import { useSceneContext } from "../../sceneContext";
import { useVersionContext } from "../../../builder/version/versionContext";
import { useProductContext } from "../../../simulation/products/productContext";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
import { useProductContext } from "../../../../simulation/products/productContext";
import { useSelectedAssets, useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
import BoundingBox from "./boundingBoxHelper3D";
import DuplicationControls3D from "./duplicationControls3D";
import CopyPasteControls3D from "./copyPasteControls3D";
import MoveControls3D from "./moveControls3D";
import RotateControls3D from "./rotateControls3D";
const SelectionControls: React.FC = () => {
// import { deleteFloorItem } from '../../../../../services/factoryBuilder/asset/floorAsset/deleteFloorItemApi';
const SelectionControls3D: React.FC = () => {
const { camera, controls, gl, scene, raycaster, pointer } = useThree();
const selectionGroup = useRef() as Types.RefGroup;
const { toggleView } = useToggleView();
@@ -253,7 +254,7 @@ const SelectionControls: React.FC = () => {
});
if (Objects.size === 0) {
clearSelection();
// clearSelection();
return;
}
@@ -350,15 +351,15 @@ const SelectionControls: React.FC = () => {
</group>
</group>
<MoveControls movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} selectionGroup={selectionGroup} boundingBoxRef={boundingBoxRef} />
<MoveControls3D movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} selectionGroup={selectionGroup} boundingBoxRef={boundingBoxRef} />
<RotateControls rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} selectionGroup={selectionGroup} />
<RotateControls3D rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} selectionGroup={selectionGroup} />
<DuplicationControls duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} setpastedObjects={setpastedObjects} selectionGroup={selectionGroup} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
<DuplicationControls3D duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} setpastedObjects={setpastedObjects} selectionGroup={selectionGroup} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
<CopyPasteControls copiedObjects={copiedObjects} setCopiedObjects={setCopiedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} selectionGroup={selectionGroup} setDuplicatedObjects={setDuplicatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
<CopyPasteControls3D copiedObjects={copiedObjects} setCopiedObjects={setCopiedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} selectionGroup={selectionGroup} setDuplicatedObjects={setDuplicatedObjects} movedObjects={movedObjects} setMovedObjects={setMovedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} boundingBoxRef={boundingBoxRef} />
</>
);
};
export default SelectionControls;
export default SelectionControls3D;

View File

@@ -6,7 +6,6 @@ import {
useElevation,
useShadows,
useSunPosition,
useWallItems,
useTileDistance,
} from "../../../store/builder/store";
import * as CONSTANTS from "../../../types/world/worldConstants";
@@ -25,13 +24,12 @@ export default function Shadows() {
const { controls, gl } = useThree();
const { elevation, setElevation } = useElevation();
const { azimuth, setAzimuth } = useAzimuth();
const { wallItems } = useWallItems();
const { planeValue } = useTileDistance();
useEffect(() => {
gl.shadowMap.enabled = true;
gl.shadowMap.type = THREE.PCFShadowMap;
}, [gl, wallItems]);
}, [gl]);
useEffect(() => {
if (lightRef.current && targetRef.current) {

View File

@@ -6,11 +6,12 @@ import {
useSelectedFloorItem,
} from "../../../store/builder/store";
import * as CONSTANTS from "../../../types/world/worldConstants";
import { useDeletableEventSphere, useSelectedEventSphere } from "../../../store/simulation/useSimulationStore";
import { useDeletableEventSphere, useSelectedEventSphere, useSelectedPoints } from "../../../store/simulation/useSimulationStore";
import { useEffect } from "react";
import { useBuilderStore } from "../../../store/builder/useBuilderStore";
export default function PostProcessing() {
const { selectedPoints } = useSelectedPoints();
const { deletableFloorItem } = useDeletableFloorItem();
const { selectedWallItem } = useSelectedWallItem();
const { selectedFloorItem } = useSelectedFloorItem();
@@ -61,6 +62,10 @@ export default function PostProcessing() {
// console.log('deletableEventSphere: ', deletableEventSphere);
}, [deletableEventSphere])
useEffect(() => {
// console.log('selectedPoints: ', selectedPoints);
}, [selectedPoints])
return (
<EffectComposer autoClear={false}>
<N8AO

View File

@@ -3,7 +3,7 @@ import { useSceneContext } from "../../../../scene/sceneContext";
export function useDespawnHandler() {
const { materialStore } = useSceneContext();
const { getMaterialById, removeMaterial, setEndTime } = materialStore();
const { getMaterialById, removeMaterial, setEndTime, clearLocations } = materialStore();
const deSpawnLogStatus = (materialUuid: string, status: string) => {
echo.info(`${materialUuid}, ${status}`);
@@ -17,6 +17,7 @@ export function useDespawnHandler() {
setEndTime(material.materialId, performance.now());
removeMaterial(material.materialId);
clearLocations(material.materialId);
deSpawnLogStatus(material.materialName, `Despawned`);

View File

@@ -8,7 +8,7 @@ export function useAssemblyHandler() {
const { getModelUuidByActionUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { incrementHumanLoad, addCurrentMaterial } = humanStore();
const { incrementHumanLoad, addCurrentMaterial, addCurrentAction } = humanStore();
const assemblyLogStatus = (materialUuid: string, status: string) => {
echo.info(`${materialUuid}, ${status}`);
@@ -24,6 +24,7 @@ export function useAssemblyHandler() {
if (!modelUuid) return;
incrementHumanLoad(modelUuid, 1);
addCurrentAction(modelUuid, action.actionUuid);
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
assemblyLogStatus(material.materialName, `performing assembly action`);

View File

@@ -8,7 +8,7 @@ export function useWorkerHandler() {
const { getModelUuidByActionUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { incrementHumanLoad, addCurrentMaterial } = humanStore();
const { incrementHumanLoad, incrementLoadCount, addCurrentMaterial, addCurrentAction } = humanStore();
const workerLogStatus = (materialUuid: string, status: string) => {
echo.info(`${materialUuid}, ${status}`);
@@ -24,6 +24,8 @@ export function useWorkerHandler() {
if (!modelUuid) return;
incrementHumanLoad(modelUuid, 1);
incrementLoadCount(modelUuid, 1);
addCurrentAction(modelUuid, action.actionUuid);
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
workerLogStatus(material.materialName, `performing worker action`);

View File

@@ -5,12 +5,14 @@ import { useSceneContext } from "../../../../scene/sceneContext";
import { useProductContext } from "../../../products/productContext";
export function useRetrieveHandler() {
const { materialStore, armBotStore, vehicleStore, storageUnitStore, productStore } = useSceneContext();
const { materialStore, armBotStore, vehicleStore, storageUnitStore, productStore, humanStore, assetStore } = useSceneContext();
const { selectedProductStore } = useProductContext();
const { addMaterial } = materialStore();
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore();
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
const { getHumanById, incrementHumanLoad, incrementLoadCount, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore();
const { getAssetById, setCurrentAnimation } = assetStore();
const { selectedProduct } = selectedProductStore();
const { getArmBotById, addCurrentAction } = armBotStore();
const { isPlaying } = usePlayButtonStore();
@@ -269,7 +271,7 @@ export function useRetrieveHandler() {
if (material) {
removeLastMaterial(storageUnit.modelUuid);
updateCurrentLoad(storageUnit.modelUuid, -1)
updateCurrentLoad(storageUnit.modelUuid, -1);
incrementVehicleLoad(vehicle.modelUuid, 1);
addCurrentMaterial(vehicle.modelUuid, material.materialType, material.materialId);
retrieveLogStatus(material.materialName, `is picked by ${vehicle.modelName}`);
@@ -293,6 +295,37 @@ export function useRetrieveHandler() {
retrievalTimeRef.current.delete(actionUuid);
retrievalTimeRef.current.delete(`${actionUuid}_last`);
}
} else if (triggeredModel.type === 'human') {
const human = getHumanById(triggeredModel.modelUuid);
const humanAsset = getAssetById(triggeredModel.modelUuid);
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
if (human && !human.isScheduled && human.state === 'idle' && human.currentLoad < (action as HumanAction).loadCapacity) {
if (humanAsset && humanAsset.animationState?.current === 'idle') {
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
} else if (humanAsset && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) {
const lastMaterial = getLastMaterial(storageUnit.modelUuid);
if (lastMaterial) {
if (action && human.currentLoad < (action as HumanAction).loadCapacity) {
const material = createNewMaterial(
lastMaterial.materialId,
lastMaterial.materialType,
storageUnit.point.action
);
if (material) {
removeLastMaterial(storageUnit.modelUuid);
updateCurrentLoad(storageUnit.modelUuid, -1);
incrementHumanLoad(human.modelUuid, 1);
incrementLoadCount(human.modelUuid, 1);
addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId);
retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`);
}
if (human.currentLoad + 1 < (action as HumanAction).loadCapacity) {
}
}
}
}
}
}
});

View File

@@ -6,65 +6,92 @@ import { useSceneContext } from '../../../scene/sceneContext';
type ConveyorCallback = {
conveyorId: string;
callback: () => void;
except: string[];
};
export function useConveyorEventManager() {
const { conveyorStore } = useSceneContext();
const { getConveyorById } = conveyorStore();
const callbacksRef = useRef<ConveyorCallback[]>([]);
const { materialStore } = useSceneContext();
const { getMaterialsByCurrentModelUuid } = materialStore();
const callbacksRef = useRef<Map<string, ConveyorCallback[]>>(new Map());
const isCooldownRef = useRef<Map<string, boolean>>(new Map());
const isMonitoringRef = useRef(false);
const { isPlaying } = usePlayButtonStore();
const { isPaused } = usePauseButtonStore();
const { isReset } = useResetButtonStore();
useEffect(() => {
if (isReset) {
callbacksRef.current = [];
callbacksRef.current.clear();
isCooldownRef.current.clear();
isMonitoringRef.current = false;
}
}, [isReset])
}, [isReset]);
// Add a new conveyor to monitor
const addConveyorToMonitor = (conveyorId: string, callback: () => void) => {
// Avoid duplicates
if (!callbacksRef.current.some((entry) => entry.conveyorId === conveyorId)) {
callbacksRef.current.push({ conveyorId, callback });
const addConveyorToMonitor = (conveyorId: string, callback: () => void, except?: string[]) => {
if (!callbacksRef.current.has(conveyorId)) {
callbacksRef.current.set(conveyorId, []);
}
// Start monitoring if not already running
if (!isMonitoringRef.current) {
isMonitoringRef.current = true;
}
callbacksRef.current.get(conveyorId)!.push({ conveyorId, callback, except: except || [] });
isMonitoringRef.current = true;
};
// Remove a conveyor from monitoring
const removeConveyorFromMonitor = (conveyorId: string) => {
callbacksRef.current = callbacksRef.current.filter(
(entry) => entry.conveyorId !== conveyorId
);
// Stop monitoring if no more conveyors to track
if (callbacksRef.current.length === 0) {
callbacksRef.current.delete(conveyorId);
isCooldownRef.current.delete(conveyorId);
if (callbacksRef.current.size === 0) {
isMonitoringRef.current = false;
}
};
// Check conveyor states every frame
useFrame(() => {
if (!isMonitoringRef.current || callbacksRef.current.length === 0 || !isPlaying || isPaused) return;
if (!isMonitoringRef.current || !isPlaying || isPaused) return;
callbacksRef.current.forEach(({ conveyorId, callback }) => {
const conveyor = getConveyorById(conveyorId);
if (conveyor?.isPaused === false) {
callback();
removeConveyorFromMonitor(conveyorId); // Remove after triggering
callbacksRef.current.forEach((queue, conveyorId) => {
if (!queue || queue.length === 0) return;
if (isCooldownRef.current.get(conveyorId)) return;
const { callback, except } = queue[0];
const conveyorMaterials = getMaterialsByCurrentModelUuid(conveyorId);
let conditionMet = false;
if (!conveyorMaterials || conveyorMaterials.length === 0) {
conditionMet = true;
} else {
const pausedMaterials = conveyorMaterials.filter(m => m.isPaused);
if (pausedMaterials.length === 0) {
conditionMet = true;
} else {
const allPausedInExcept = pausedMaterials.filter(m => !except.includes(m.materialId));
if (allPausedInExcept.length === 0) {
conditionMet = true;
}
}
}
if (conditionMet) {
queue.shift();
if (callback) callback();
if (queue.length === 0) {
removeConveyorFromMonitor(conveyorId);
} else {
isCooldownRef.current.set(conveyorId, true);
setTimeout(() => {
isCooldownRef.current.set(conveyorId, false);
}, 1000);
}
}
});
});
// Cleanup on unmount
useEffect(() => {
return () => {
callbacksRef.current = [];
callbacksRef.current.clear();
isCooldownRef.current.clear();
isMonitoringRef.current = false;
};
}, []);
@@ -73,4 +100,4 @@ export function useConveyorEventManager() {
addConveyorToMonitor,
removeConveyorFromMonitor,
};
}
}

View File

@@ -103,9 +103,21 @@ export function Arrows({ connections }: { readonly connections: ConnectionLine[]
return (
<group
key={key}
onPointerOver={() => setHoveredArrowTrigger(trigger.triggerUuid)}
onPointerOut={() => setHoveredArrowTrigger(null)}
onClick={() => { removeConnection(trigger) }}
onPointerOver={() => {
if (toolMode === '3D-Delete') {
setHoveredArrowTrigger(trigger.triggerUuid)
}
}}
onPointerOut={() => {
if (toolMode === '3D-Delete') {
setHoveredArrowTrigger(null)
}
}}
onClick={() => {
if (toolMode === '3D-Delete') {
removeConnection(trigger)
}
}}
>
<mesh
geometry={shaftGeometry}

View File

@@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSubModuleStore } from "../../../../store/useModuleStore";
import { useSelectedAction, useSelectedAsset } from "../../../../store/simulation/useSimulationStore";
import { useSelectedAction, useSelectedAsset, useSelectedEventData } from "../../../../store/simulation/useSimulationStore";
import { handleAddEventToProduct } from "../points/functions/handleAddEventToProduct";
import { QuadraticBezierLine } from "@react-three/drei";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
@@ -38,6 +38,7 @@ function TriggerConnector() {
const { selectedAction } = useSelectedAction();
const { selectedVersionStore } = useVersionContext();
const { selectedVersion } = selectedVersionStore();
const { setSelectedEventData } = useSelectedEventData();
const { projectId } = useParams();
const [firstSelectedPoint, setFirstSelectedPoint] = useState<{
@@ -62,6 +63,10 @@ function TriggerConnector() {
eventDatas: eventData,
versionId: selectedVersion?.versionId || '',
})
if (firstSelectedPoint?.pointUuid) {
setSelectedEventData(eventData, firstSelectedPoint.pointUuid)
}
}
useEffect(() => {
@@ -155,8 +160,8 @@ function TriggerConnector() {
// Handle Human point
else if (event.type === "human" && 'point' in event) {
const point = event.point;
if (point.action?.triggers) {
point.action.triggers.forEach(trigger => {
point.actions?.forEach(action => {
action.triggers?.forEach(trigger => {
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
@@ -166,7 +171,7 @@ function TriggerConnector() {
});
}
});
}
});
}
});

View File

@@ -2,76 +2,163 @@ import { useEffect, useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore';
import { useSceneContext } from '../../../scene/sceneContext';
type HumanCallback = {
humanId: string;
callback: () => void;
};
import { useProductContext } from '../../products/productContext';
export function useHumanEventManager() {
const { humanStore } = useSceneContext();
const { getHumanById } = humanStore();
const callbacksRef = useRef<HumanCallback[]>([]);
const { humanStore, productStore, assetStore } = useSceneContext();
const { getHumanById, clearLoadCount, setCurrentPhase } = humanStore();
const { getAssetById } = assetStore();
const { getActionByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const callbacksRef = useRef<Map<string, (() => void)[]>>(new Map());
const actionQueueRef = useRef<Map<string, { actionType: "worker" | "assembly", actionUuid: string }[]>>(new Map());
const isCooldownRef = useRef<Map<string, boolean>>(new Map());
const isMonitoringRef = useRef(false);
const { isPlaying } = usePlayButtonStore();
const { isPaused } = usePauseButtonStore();
const { isReset } = useResetButtonStore();
useEffect(() => {
if (isReset) {
callbacksRef.current = [];
callbacksRef.current.clear();
actionQueueRef.current.clear();
isCooldownRef.current.clear();
isMonitoringRef.current = false;
}
}, [isReset])
}, [isReset]);
// Add a new human to monitor
const addHumanToMonitor = (humanId: string, callback: () => void) => {
// Avoid duplicates
if (!callbacksRef.current.some((entry) => entry.humanId === humanId)) {
callbacksRef.current.push({ humanId, callback });
const addHumanToMonitor = (humanId: string, callback: () => void, actionUuid: string) => {
const action = getActionByUuid(selectedProduct.productUuid, actionUuid || '') as HumanAction | undefined;
if (!action) return;
const actionType = action.actionType;
if (actionType !== "worker" && actionType !== "assembly") return;
if (!callbacksRef.current.has(humanId)) {
callbacksRef.current.set(humanId, []);
actionQueueRef.current.set(humanId, []);
}
// Start monitoring if not already running
if (!isMonitoringRef.current) {
isMonitoringRef.current = true;
}
callbacksRef.current.get(humanId)!.push(callback);
actionQueueRef.current.get(humanId)!.push({ actionType, actionUuid });
isMonitoringRef.current = true;
};
// Remove a human from monitoring
const removeHumanFromMonitor = (humanId: string) => {
callbacksRef.current = callbacksRef.current.filter(
(entry) => entry.humanId !== humanId
);
callbacksRef.current.delete(humanId);
actionQueueRef.current.delete(humanId);
isCooldownRef.current.delete(humanId);
// Stop monitoring if no more humans to track
if (callbacksRef.current.length === 0) {
if (callbacksRef.current.size === 0) {
isMonitoringRef.current = false;
}
};
// Check human states every frame
useFrame(() => {
if (!isMonitoringRef.current || callbacksRef.current.length === 0 || !isPlaying || isPaused) return;
if (!isMonitoringRef.current || !isPlaying || isPaused) return;
callbacksRef.current.forEach(({ humanId, callback }) => {
callbacksRef.current.forEach((queue, humanId) => {
if (queue.length === 0 || isCooldownRef.current.get(humanId)) return;
const actionQueue = actionQueueRef.current.get(humanId);
if (!actionQueue || actionQueue.length === 0) return;
const { actionType: expectedActionType, actionUuid } = actionQueue[0];
const human = getHumanById(humanId);
if (human?.point.action.actionType === 'worker') {
if (human && human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
callback();
removeHumanFromMonitor(humanId); // Remove after triggering
const humanAsset = getAssetById(humanId);
const action = getActionByUuid(selectedProduct.productUuid, actionUuid) as HumanAction | undefined;
if (!humanAsset || !human || !action || action.actionType !== expectedActionType) return;
let conditionMet = false;
const currentAction = getActionByUuid(selectedProduct.productUuid, human.currentAction?.actionUuid || '') as HumanAction | undefined;
if (expectedActionType === "worker") {
if (currentAction && currentAction.actionType === 'worker') {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < currentAction.loadCapacity
);
if (human.totalLoadCount >= currentAction.loadCount && actionUuid === human.currentAction?.actionUuid) {
queue.shift();
actionQueue.shift();
if (queue.length === 0) {
removeHumanFromMonitor(humanId);
}
return;
}
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
setCurrentPhase(human.modelUuid, 'init');
}
} else {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < action.loadCapacity
);
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
setCurrentPhase(human.modelUuid, 'init');
}
}
} else if (human?.point.action.actionType === 'assembly') {
if (human && human.isActive === false && human.state === 'idle') {
callback();
removeHumanFromMonitor(humanId); // Remove after triggering
} else if (expectedActionType === "assembly") {
if (currentAction && currentAction.actionType === 'worker') {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < currentAction.loadCapacity
);
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
setCurrentPhase(human.modelUuid, 'init');
}
} else {
conditionMet = (
!human.isActive &&
human.state === "idle" &&
humanAsset.animationState?.current === 'idle' &&
human.currentLoad < action.loadCapacity
)
}
if (conditionMet) {
clearLoadCount(human.modelUuid);
}
}
if (conditionMet) {
const callback = queue.shift();
actionQueue.shift();
if (callback) callback();
if (queue.length === 0) {
removeHumanFromMonitor(humanId);
} else {
isCooldownRef.current.set(humanId, true);
setTimeout(() => {
isCooldownRef.current.set(humanId, false);
}, 1000);
}
}
});
});
}, 0);
// Cleanup on unmount
useEffect(() => {
return () => {
callbacksRef.current = [];
callbacksRef.current.clear();
actionQueueRef.current.clear();
isCooldownRef.current.clear();
isMonitoringRef.current = false;
};
}, []);
@@ -80,4 +167,4 @@ export function useHumanEventManager() {
addHumanToMonitor,
removeHumanFromMonitor,
};
}
}

View File

@@ -5,18 +5,21 @@ import * as THREE from 'three';
import { Line } from '@react-three/drei';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useProductContext } from '../../../products/productContext';
interface HumanAnimatorProps {
path: [number, number, number][];
handleCallBack: () => void;
reset: () => void;
startUnloadingProcess: () => void;
currentPhase: string;
human: HumanStatus;
}
function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, startUnloadingProcess }: Readonly<HumanAnimatorProps>) {
const { humanStore, assetStore } = useSceneContext();
function HumanAnimator({ path, handleCallBack, human, reset, startUnloadingProcess }: Readonly<HumanAnimatorProps>) {
const { humanStore, assetStore, productStore } = useSceneContext();
const { getActionByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { getHumanById } = humanStore();
const { setCurrentAnimation } = assetStore();
const { isPaused } = usePauseButtonStore();
@@ -26,24 +29,30 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start
const progressRef = useRef<number>(0);
const movingForward = useRef<boolean>(true);
const completedRef = useRef<boolean>(false);
const [objectRotation, setObjectRotation] = useState<[number, number, number] | null>(human.point?.action?.pickUpPoint?.rotation || [0, 0, 0])
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const [objectRotation, setObjectRotation] = useState<[number, number, number] | null>((action as HumanAction)?.pickUpPoint?.rotation || [0, 0, 0])
const [restRotation, setRestingRotation] = useState<boolean>(true);
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
const rigidBodyRef = useRef<RapierRigidBody>(null);
const { scene } = useThree();
useEffect(() => {
if (currentPhase === 'init-pickup' && path.length > 0) {
if (!human.currentAction?.actionUuid) return;
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
if (human.currentPhase === 'init-pickup' && path.length > 0) {
setCurrentPath(path);
setObjectRotation(human.point.action.pickUpPoint?.rotation ?? null)
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
setObjectRotation(human.point.action?.dropPoint?.rotation ?? null)
setObjectRotation((action as HumanAction).pickUpPoint?.rotation ?? null)
} else if (human.currentPhase === 'init-assembly' && path.length > 0) {
setObjectRotation((action as HumanAction)?.assemblyPoint?.rotation ?? null)
setCurrentPath(path);
} else if (currentPhase === 'drop-pickup' && path.length > 0) {
setObjectRotation(human.point.action?.pickUpPoint?.rotation ?? null)
} else if (human.currentPhase === 'pickup-drop' && path.length > 0) {
setObjectRotation((action as HumanAction)?.dropPoint?.rotation ?? null)
setCurrentPath(path);
} else if (human.currentPhase === 'drop-pickup' && path.length > 0) {
setObjectRotation((action as HumanAction)?.pickUpPoint?.rotation ?? null)
setCurrentPath(path);
}
}, [currentPhase, path, objectRotation]);
}, [human.currentPhase, path, objectRotation, selectedProduct, human.currentAction?.actionUuid]);
useEffect(() => {
completedRef.current = false;
@@ -76,7 +85,7 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start
const object = scene.getObjectByProperty('uuid', human.modelUuid);
if (!object || currentPath.length < 2) return;
if (isPaused) return;
if (isPaused || !isPlaying) return;
let totalDistance = 0;
const distances = [];
@@ -127,13 +136,13 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start
const t = (progressRef.current - accumulatedDistance) / segmentDistance;
const position = start.clone().lerp(end, t);
object.position.copy(position);
if (human.currentMaterials.length > 0) {
if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (human.currentPhase !== 'init-pickup' && human.currentPhase !== 'init-assembly' && human.currentPhase !== 'drop-pickup')) {
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
} else {
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
}
} else {
if (human.currentMaterials.length > 0) {
if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (human.currentPhase !== 'init-pickup' && human.currentPhase !== 'init-assembly' && human.currentPhase !== 'drop-pickup')) {
setCurrentAnimation(human.modelUuid, 'idle_with_box', true, true, true);
} else {
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
@@ -180,7 +189,7 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start
movingForward.current = !movingForward.current;
setCurrentPath([]);
handleCallBack();
if (currentPhase === 'pickup-drop') {
if (human.currentPhase === 'pickup-drop') {
requestAnimationFrame(startUnloadingProcess);
}
}

View File

@@ -2,11 +2,18 @@ import { useEffect, useRef, useState } from 'react';
import { useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { MaterialModel } from '../../../materials/instances/material/materialModel';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useProductContext } from '../../../products/productContext';
const MaterialAnimator = ({ human }: { human: HumanStatus }) => {
const MaterialAnimator = ({ human }: { human: HumanStatus; }) => {
const { productStore } = useSceneContext();
const { getActionByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const meshRef = useRef<any>(null!);
const [hasLoad, setHasLoad] = useState(false);
const [isAttached, setIsAttached] = useState(false);
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const { scene } = useThree();
useEffect(() => {
@@ -39,11 +46,11 @@ const MaterialAnimator = ({ human }: { human: HumanStatus }) => {
meshRef.current.visible = true;
setIsAttached(true);
}
}, [hasLoad, human.modelUuid, scene]);
}, [hasLoad, human.modelUuid, scene, human.currentPhase]);
return (
<>
{hasLoad && human.point.action.actionType === 'worker' && human.currentMaterials.length > 0 && (
{hasLoad && (action as HumanAction).actionType === 'worker' && human.currentMaterials.length > 0 && (human.currentPhase !== 'init-pickup' && human.currentPhase !== 'init-assembly' && human.currentPhase !== 'drop-pickup') && (
<MaterialModel
matRef={meshRef}
materialId={human.currentMaterials[0].materialId || ''}

View File

@@ -16,7 +16,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
const { isPlaying } = usePlayButtonStore();
const { scene } = useThree();
const { assetStore, materialStore, armBotStore, conveyorStore, machineStore, vehicleStore, humanStore, storageUnitStore, productStore } = useSceneContext();
const { removeMaterial, setEndTime, setMaterial } = materialStore();
const { removeMaterial, setEndTime, setMaterial, setIsVisible } = materialStore();
const { getStorageUnitById } = storageUnitStore();
const { getArmBotById } = armBotStore();
const { getConveyorById } = conveyorStore();
@@ -27,9 +27,8 @@ function HumanInstance({ human }: { human: HumanStatus }) {
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { setHumanActive, setHumanState, setHumanPicking, clearCurrentMaterials, setHumanLoad, decrementHumanLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = humanStore();
const { setHumanActive, setHumanState, clearCurrentMaterials, setHumanLoad, setHumanScheduled, decrementHumanLoad, removeLastMaterial, incrementIdleTime, incrementActiveTime, resetTime, setCurrentPhase } = humanStore();
const [currentPhase, setCurrentPhase] = useState<string>('init');
const [path, setPath] = useState<[number, number, number][]>([]);
const pauseTimeRef = useRef<number | null>(null);
const idleTimeRef = useRef<number>(0);
@@ -57,37 +56,38 @@ function HumanInstance({ human }: { human: HumanStatus }) {
isSpeedRef.current = speed;
}, [speed]);
const computePath = useCallback(
(start: any, end: any) => {
try {
const navMeshQuery = new NavMeshQuery(navMesh);
const { path: segmentPath } = navMeshQuery.computePath(start, end);
if (
segmentPath.length > 0 &&
Math.round(segmentPath[segmentPath.length - 1].x) == Math.round(end.x) &&
Math.round(segmentPath[segmentPath.length - 1].z) == Math.round(end.z)
) {
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
} else {
console.log("There is no path here...Choose valid path")
const { path: segmentPaths } = navMeshQuery.computePath(start, start);
return segmentPaths.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
}
} catch {
console.error("Failed to compute path");
return [];
const computePath = useCallback((start: [number, number, number], end: [number, number, number]) => {
try {
const navMeshQuery = new NavMeshQuery(navMesh);
let startPoint = new THREE.Vector3(start[0], start[1], start[2]);
let endPoint = new THREE.Vector3(end[0], end[1], end[2]);
const { path: segmentPath } = navMeshQuery.computePath(startPoint, endPoint);
if (
segmentPath.length > 0 &&
Math.round(segmentPath[segmentPath.length - 1].x) == Math.round(endPoint.x) &&
Math.round(segmentPath[segmentPath.length - 1].z) == Math.round(endPoint.z)
) {
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
} else {
console.log("There is no path here...Choose valid path")
const { path: segmentPaths } = navMeshQuery.computePath(startPoint, startPoint);
return segmentPaths.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
}
}, [navMesh]);
} catch {
console.error("Failed to compute path");
return [];
}
}, [navMesh]);
function humanStatus(modelId: string, status: string) {
// console.log(`${modelId} , ${status}`);
}
function reset() {
setCurrentPhase('init');
setCurrentPhase(human.modelUuid, 'init');
setHumanActive(human.modelUuid, false);
setHumanPicking(human.modelUuid, false);
setHumanState(human.modelUuid, 'idle');
setHumanScheduled(human.modelUuid, false);
setHumanLoad(human.modelUuid, 0);
resetAnimation(human.modelUuid);
setPath([]);
@@ -120,25 +120,32 @@ function HumanInstance({ human }: { human: HumanStatus }) {
useEffect(() => {
if (isPlaying) {
if (!human.point.action.assemblyPoint || human.point.action.actionType === 'worker') return;
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
if (!human.isActive && human.state === 'idle' && currentPhase === 'init') {
if (!action || !(action as HumanAction).assemblyPoint || (action as HumanAction).actionType === 'worker') return;
if (!human.isActive && human.state === 'idle' && human.currentPhase === 'init') {
const humanMesh = scene.getObjectByProperty('uuid', human.modelUuid);
if (!humanMesh) return;
const toPickupPath = computePath(humanMesh.position.toArray(), (action as HumanAction)?.assemblyPoint?.position || [0, 0, 0]);
setPath(toPickupPath);
setHumanState(human.modelUuid, 'idle');
setCurrentPhase('waiting');
setHumanPicking(human.modelUuid, false);
setCurrentPhase(human.modelUuid, 'init-assembly');
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
humanStatus(human.modelUuid, 'Human is waiting for material in assembly');
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'waiting') {
} else if (!human.isActive && human.state === 'idle' && human.currentPhase === 'waiting') {
if (human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current !== 'working_standing') {
setCurrentAnimation(human.modelUuid, 'working_standing', true, true, false);
setHumanState(human.modelUuid, 'running');
setCurrentPhase('assembling');
setHumanPicking(human.modelUuid, true);
setCurrentPhase(human.modelUuid, 'assembling');
setHumanActive(human.modelUuid, true);
processStartTimeRef.current = performance.now();
processTimeRef.current = human.point.action.processTime || 0;
processTimeRef.current = (action as HumanAction).processTime || 0;
accumulatedPausedTimeRef.current = 0;
lastPauseTimeRef.current = null;
hasLoggedHalfway.current = false;
@@ -149,18 +156,18 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
}
} else if (human.isActive && human.state === 'running' && human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current === 'working_standing' && humanAsset.animationState?.isCompleted) {
if (human.point.action.assemblyPoint && currentPhase === 'assembling') {
if ((action as HumanAction).assemblyPoint && human.currentPhase === 'assembling') {
setHumanState(human.modelUuid, 'idle');
setCurrentPhase('waiting');
setHumanPicking(human.modelUuid, false);
setCurrentPhase(human.modelUuid, 'waiting');
setHumanActive(human.modelUuid, false);
setHumanScheduled(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
humanStatus(human.modelUuid, 'Human is waiting for material in assembly');
decrementHumanLoad(human.modelUuid, 1);
const material = removeLastMaterial(human.modelUuid);
if (material) {
triggerPointActions(human.point.action, material.materialId);
triggerPointActions((action as HumanAction), material.materialId);
}
}
}
@@ -169,12 +176,14 @@ function HumanInstance({ human }: { human: HumanStatus }) {
reset()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
}, [human, human.currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
const trackAssemblyProcess = useCallback(() => {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const now = performance.now();
if (!processStartTimeRef.current || !human.point.action.processTime) {
if (!processStartTimeRef.current || !(action as HumanAction).processTime || !action) {
return;
}
@@ -190,12 +199,12 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
const elapsed = (now - processStartTimeRef.current - accumulatedPausedTimeRef.current) * isSpeedRef.current;
const totalProcessTimeMs = human.point.action.processTime * 1000;
const totalProcessTimeMs = ((action as HumanAction).processTime || 1) * 1000;
if (elapsed >= totalProcessTimeMs / 2 && !hasLoggedHalfway.current) {
hasLoggedHalfway.current = true;
if (human.currentMaterials.length > 0) {
setMaterial(human.currentMaterials[0].materialId, human.point.action.swapMaterial || 'Default Material');
setMaterial(human.currentMaterials[0].materialId, (action as HumanAction).swapMaterial || 'Default Material');
}
humanStatus(human.modelUuid, `🟡 Human ${human.modelUuid} reached halfway in assembly.`);
}
@@ -212,73 +221,48 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
processAnimationIdRef.current = requestAnimationFrame(trackAssemblyProcess);
}, [human.modelUuid, human.point.action.processTime, human.currentMaterials]);
}, [human.modelUuid, human.currentMaterials]);
useEffect(() => {
if (isPlaying) {
if (!human.point.action.pickUpPoint || !human.point.action.dropPoint || human.point.action.actionType === 'assembly') return;
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
if (!action || action.actionType !== 'worker' || !action.pickUpPoint || !action.dropPoint) return;
if (!human.isActive && human.state === 'idle' && currentPhase === 'init') {
const toPickupPath = computePath(
new THREE.Vector3(human?.position[0], human?.position[1], human?.position[2]),
new THREE.Vector3(
human?.point?.action?.pickUpPoint?.position?.[0] ?? 0,
human?.point?.action?.pickUpPoint?.position?.[1] ?? 0,
human?.point?.action?.pickUpPoint?.position?.[2] ?? 0
)
);
if (!human.isActive && human.state === 'idle' && human.currentPhase === 'init') {
const humanMesh = scene.getObjectByProperty('uuid', human.modelUuid);
if (!humanMesh) return;
const toPickupPath = computePath(humanMesh.position.toArray(), action?.pickUpPoint?.position || [0, 0, 0]);
setPath(toPickupPath);
setCurrentPhase('init-pickup');
setCurrentPhase(human.modelUuid, 'init-pickup');
setHumanState(human.modelUuid, 'running');
setHumanPicking(human.modelUuid, false);
setHumanActive(human.modelUuid, true);
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
humanStatus(human.modelUuid, 'Started from init, heading to pickup');
return;
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'picking') {
if (humanAsset && human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) {
if (human.point.action.pickUpPoint && human.point.action.dropPoint) {
const toDrop = computePath(
new THREE.Vector3(
human.point.action.pickUpPoint.position?.[0] ?? 0,
human.point.action.pickUpPoint.position?.[1] ?? 0,
human.point.action.pickUpPoint.position?.[2] ?? 0
),
new THREE.Vector3(
human.point.action.dropPoint.position?.[0] ?? 0,
human.point.action.dropPoint.position?.[1] ?? 0,
human.point.action.dropPoint.position?.[2] ?? 0
)
);
} else if (!human.isActive && human.state === 'idle' && human.currentPhase === 'picking') {
if (humanAsset && human.currentLoad === action.loadCapacity && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) {
if (action.pickUpPoint && action.dropPoint) {
const toDrop = computePath(action.pickUpPoint.position || [0, 0, 0], action.dropPoint.position || [0, 0, 0]);
setPath(toDrop);
setCurrentPhase('pickup-drop');
setCurrentPhase(human.modelUuid, 'pickup-drop');
setHumanState(human.modelUuid, 'running');
setHumanPicking(human.modelUuid, false);
setHumanPicking(human.modelUuid, true);
setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true);
humanStatus(human.modelUuid, 'Started from pickup point, heading to drop point');
}
} else if (human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0 && humanAsset?.animationState?.current !== 'pickup') {
} else if (human.currentMaterials.length > 0 && humanAsset?.animationState?.current !== 'pickup') {
if (human.currentMaterials[0]?.materialId) {
setIsVisible(human.currentMaterials[0]?.materialId, false);
}
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
}
} else if (!human.isActive && human.state === 'idle' && currentPhase === 'dropping' && human.currentLoad === 0) {
if (human.point.action.pickUpPoint && human.point.action.dropPoint) {
const dropToPickup = computePath(
new THREE.Vector3(
human.point.action.dropPoint.position?.[0] ?? 0,
human.point.action.dropPoint.position?.[1] ?? 0,
human.point.action.dropPoint.position?.[2] ?? 0
),
new THREE.Vector3(
human.point.action.pickUpPoint.position?.[0] ?? 0,
human.point.action.pickUpPoint.position?.[1] ?? 0,
human.point.action.pickUpPoint.position?.[2] ?? 0
)
);
} else if (!human.isActive && human.state === 'idle' && human.currentPhase === 'dropping' && human.currentLoad === 0) {
if (action.pickUpPoint && action.dropPoint) {
const dropToPickup = computePath(action.dropPoint.position || [0, 0, 0], action.pickUpPoint.position || [0, 0, 0]);
setPath(dropToPickup);
setCurrentPhase('drop-pickup');
setCurrentPhase(human.modelUuid, 'drop-pickup');
setHumanState(human.modelUuid, 'running');
setHumanPicking(human.modelUuid, false);
setHumanActive(human.modelUuid, true);
setCurrentAnimation(human.modelUuid, 'walking', true, true, true);
humanStatus(human.modelUuid, 'Started from dropping point, heading to pickup point');
@@ -289,30 +273,35 @@ function HumanInstance({ human }: { human: HumanStatus }) {
reset()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
}, [human, human.currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]);
function handleCallBack() {
if (currentPhase === 'init-pickup') {
setCurrentPhase('picking');
if (human.currentPhase === 'init-pickup') {
setCurrentPhase(human.modelUuid, 'picking');
setHumanState(human.modelUuid, 'idle');
setHumanPicking(human.modelUuid, true);
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
humanStatus(human.modelUuid, 'Reached pickup point, waiting for material');
setPath([]);
} else if (currentPhase === 'pickup-drop') {
setCurrentPhase('dropping');
} if (human.currentPhase === 'init-assembly') {
setCurrentPhase(human.modelUuid, 'waiting');
setHumanState(human.modelUuid, 'idle');
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
humanStatus(human.modelUuid, 'Reached assembly point, waiting for material');
setPath([]);
} else if (human.currentPhase === 'pickup-drop') {
setCurrentPhase(human.modelUuid, 'dropping');
setHumanState(human.modelUuid, 'idle');
setHumanPicking(human.modelUuid, false);
setHumanActive(human.modelUuid, false);
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
humanStatus(human.modelUuid, 'Reached drop point');
setPath([]);
} else if (currentPhase === 'drop-pickup') {
setCurrentPhase('picking');
} else if (human.currentPhase === 'drop-pickup') {
setCurrentPhase(human.modelUuid, 'picking');
setHumanState(human.modelUuid, 'idle');
setHumanPicking(human.modelUuid, true);
setHumanActive(human.modelUuid, false);
setHumanScheduled(human.modelUuid, false);
setPath([]);
clearCurrentMaterials(human.modelUuid);
setCurrentAnimation(human.modelUuid, 'idle', true, true, true);
@@ -365,38 +354,35 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}, [human, isPlaying]);
function startUnloadingProcess() {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const humanAsset = getAssetById(human.modelUuid);
if (humanAsset?.animationState?.current !== 'drop') {
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
}
if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) {
if (human.point.action.triggers.length > 0) {
const trigger = getTriggerByUuid(selectedProduct.productUuid, human.point.action.triggers[0]?.triggerUuid);
if ((action as HumanAction).triggers.length > 0) {
const trigger = getTriggerByUuid(selectedProduct.productUuid, (action as HumanAction).triggers[0]?.triggerUuid);
const model = getEventByModelUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredModel?.modelUuid || '');
if (trigger && model) {
if (model.type === 'transfer') {
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
if (action) {
handleMaterialDropToConveyor(model);
}
} else if (model.type === 'machine') {
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
if (action) {
handleMaterialDropToMachine(model);
}
} else if (model.type === 'roboticArm') {
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
if (action) {
handleMaterialDropToArmBot(model);
}
} else if (model.type === 'storageUnit') {
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
if (action) {
handleMaterialDropToStorageUnit(model);
}
} else if (model.type === 'vehicle') {
const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid);
if (action) {
handleMaterialDropToVehicle(model);
}
@@ -415,6 +401,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
function handleMaterialDropToStorageUnit(model: StorageEventSchema) {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const humanAsset = getAssetById(human.modelUuid);
if (model && humanAsset?.animationState?.current !== 'drop') {
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
@@ -428,7 +415,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
human.currentLoad,
model.modelUuid,
model.point.action.storageCapacity,
human.point.action
(action as HumanAction)
);
}
} else {
@@ -482,6 +469,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
function handleMaterialDropToConveyor(model: ConveyorEventSchema) {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const humanAsset = getAssetById(human.modelUuid);
if (humanAsset?.animationState?.current !== 'drop') {
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
@@ -495,7 +483,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
human.modelUuid,
human.currentLoad,
conveyor.modelUuid,
human.point.action
(action as HumanAction)
);
}
} else {
@@ -547,6 +535,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
function handleMaterialDropToArmBot(model: RoboticArmEventSchema) {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const humanAsset = getAssetById(human.modelUuid);
if (humanAsset?.animationState?.current !== 'drop') {
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
@@ -560,7 +549,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
human.modelUuid,
human.currentLoad,
model.modelUuid,
human.point.action
(action as HumanAction)
);
}
} else {
@@ -617,6 +606,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
function handleMaterialDropToVehicle(model: VehicleEventSchema) {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const humanAsset = getAssetById(human.modelUuid);
if (humanAsset?.animationState?.current !== 'drop') {
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
@@ -630,7 +620,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
human.modelUuid,
human.currentLoad,
model.modelUuid,
human.point.action
(action as HumanAction)
);
}
} else {
@@ -687,6 +677,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
}
function handleMaterialDropToMachine(model: MachineEventSchema) {
const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || '');
const humanAsset = getAssetById(human.modelUuid);
if (humanAsset?.animationState?.current !== 'drop') {
setCurrentAnimation(human.modelUuid, 'drop', true, false, false);
@@ -700,7 +691,7 @@ function HumanInstance({ human }: { human: HumanStatus }) {
human.modelUuid,
human.currentLoad,
model.modelUuid,
human.point.action
(action as HumanAction)
);
}
} else {
@@ -790,7 +781,6 @@ function HumanInstance({ human }: { human: HumanStatus }) {
<HumanAnimator
path={path}
handleCallBack={handleCallBack}
currentPhase={currentPhase}
human={human}
reset={reset}
startUnloadingProcess={startUnloadingProcess}

View File

@@ -27,9 +27,10 @@ function HumanUi() {
const { humanStore, productStore } = useSceneContext();
const { selectedProduct } = selectedProductStore();
const { humans, getHumanById } = humanStore();
const { updateEvent } = productStore();
const { updateEvent, updateAction, getActionByUuid } = productStore();
const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]);
const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]);
const [assemblyPosition, setAssemblyPosition] = useState<[number, number, number]>([0, 1, 0]);
const [startRotation, setStartRotation] = useState<[number, number, number]>([0, Math.PI, 0]);
const [assemblyRotation, setAssemblyRotation] = useState<[number, number, number]>([0, 0, 0]);
const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
@@ -48,9 +49,8 @@ function HumanUi() {
const { selectedVersion } = selectedVersionStore();
const { projectId } = useParams();
const selectedHuman = selectedEventSphere ? getHumanById(selectedEventSphere.userData.modelUuid) : null;
const actionType = selectedHuman?.point?.action?.actionType || null;
const isAssembly = actionType === 'assembly';
const currentAction = getActionByUuid(selectedProduct.productUuid, selectedAction.actionId || '');
const isAssembly = currentAction?.actionType === 'assembly';
const updateBackend = (
productName: string,
@@ -68,10 +68,10 @@ function HumanUi() {
};
useEffect(() => {
if (!selectedEventSphere) return;
if (!selectedEventSphere || !selectedAction?.actionId) return;
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
if (!selectedHuman || !selectedHuman.point?.action) return;
if (!selectedHuman || !selectedHuman.point?.actions) return;
setSelectedHumanData({
position: selectedHuman.position,
@@ -86,42 +86,47 @@ function HumanUi() {
);
}
const action = selectedHuman.point.action;
const action = selectedHuman.point.actions.find(a => a.actionUuid === selectedAction.actionId);
if (!action) return;
if (action.pickUpPoint?.position && outerGroup.current) {
const worldPos = new Vector3(...action.pickUpPoint.position);
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
setStartPosition([localPosition.x, 1, localPosition.z]);
setStartRotation(action.pickUpPoint.rotation || [0, 0, 0]);
if (isAssembly) {
if (action.assemblyPoint?.position && outerGroup.current) {
const worldPos = new Vector3(...action.assemblyPoint.position);
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
setAssemblyPosition([localPosition.x, 1, localPosition.z]);
setAssemblyRotation(action.assemblyPoint.rotation || [0, 0, 0]);
} else {
setAssemblyPosition([0, 1, 0]);
setAssemblyRotation([0, 0, 0]);
}
} else {
setStartPosition([0, 1, 0]);
setStartRotation([0, Math.PI, 0]);
}
if (action.pickUpPoint?.position && outerGroup.current) {
const worldPos = new Vector3(...action.pickUpPoint.position);
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
setStartPosition([localPosition.x, 1, localPosition.z]);
setStartRotation(action.pickUpPoint.rotation || [0, 0, 0]);
} else {
setStartPosition([0, 1, 0]);
setStartRotation([0, Math.PI, 0]);
}
if (action.dropPoint?.position && outerGroup.current) {
const worldPos = new Vector3(...action.dropPoint.position);
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
setEndPosition([localPosition.x, 1, localPosition.z]);
setEndRotation(action.dropPoint.rotation || [0, Math.PI, 0]);
} else {
setEndPosition([0, 1, 0]);
setEndRotation([0, 0, 0]);
if (action.dropPoint?.position && outerGroup.current) {
const worldPos = new Vector3(...action.dropPoint.position);
const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
setEndPosition([localPosition.x, 1, localPosition.z]);
setEndRotation(action.dropPoint.rotation || [0, Math.PI, 0]);
} else {
setEndPosition([0, 1, 0]);
setEndRotation([0, 0, 0]);
}
}
if (action.assemblyPoint?.rotation) {
setAssemblyRotation(action.assemblyPoint.rotation);
} else {
setAssemblyRotation([0, 0, 0]);
}
}, [selectedEventSphere, outerGroup.current, selectedAction, humans]);
const handlePointerDown = (
e: any,
state: "start" | "end",
rotation: "start" | "end"
state: "start" | "end" | "assembly",
rotation: "start" | "end" | "assembly"
) => {
if (isAssembly) return;
e.stopPropagation();
const intersection = new Vector3();
const pointer = new Vector2((e.clientX / window.innerWidth) * 2 - 1, -(e.clientY / window.innerHeight) * 2 + 1);
@@ -144,7 +149,10 @@ function HumanUi() {
if (outerGroup.current) {
localPoint = outerGroup.current.worldToLocal(intersection.clone());
}
const marker = state === "start" ? startMarker.current : endMarker.current;
const marker =
state === "start" ? startMarker.current :
state === "end" ? endMarker.current :
assemblyMarker.current;
if (marker && localPoint) {
const markerPos = new Vector3().copy(marker.position);
dragOffset.current.copy(markerPos.sub(localPoint));
@@ -154,7 +162,6 @@ function HumanUi() {
if (controls) (controls as any).enabled = false;
};
const handlePointerUp = () => {
(controls as any).enabled = true;
setIsDragging(null);
@@ -163,40 +170,46 @@ function HumanUi() {
if (!selectedEventSphere?.userData.modelUuid || !selectedAction?.actionId) return;
const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);
if (!selectedHuman || !outerGroup.current) return;
if (!selectedHuman || !outerGroup.current || !currentAction) return;
const isAssembly = selectedHuman.point?.action?.actionType === 'assembly';
const updatedActions = selectedHuman.point.actions.map(action => {
if (action.actionUuid !== currentAction.actionUuid) return action;
let updatedAction;
if (isAssembly) {
if (!assemblyMarker.current || !outerGroup.current) return action;
if (isAssembly) {
updatedAction = {
...selectedHuman.point.action,
assemblyPoint: {
rotation: assemblyRotation
},
};
} else {
if (!startMarker.current || !endMarker.current) return;
const worldPosAssembly = new Vector3(...assemblyPosition);
const globalAssemblyPosition = outerGroup.current.localToWorld(worldPosAssembly.clone());
const worldPosStart = new Vector3(...startPosition);
const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
return {
...action,
assemblyPoint: {
position: [globalAssemblyPosition.x, globalAssemblyPosition.y, globalAssemblyPosition.z] as [number, number, number],
rotation: assemblyRotation
},
};
} else {
if (!startMarker.current || !endMarker.current || !outerGroup.current) return action;
const worldPosEnd = new Vector3(...endPosition);
const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
const worldPosStart = new Vector3(...startPosition);
const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());
updatedAction = {
...selectedHuman.point.action,
pickUpPoint: {
position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number],
rotation: startRotation,
},
dropPoint: {
position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number],
rotation: endRotation,
},
};
}
const worldPosEnd = new Vector3(...endPosition);
const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());
return {
...action,
pickUpPoint: {
position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number],
rotation: startRotation,
},
dropPoint: {
position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number],
rotation: endRotation,
},
};
}
});
const event = updateEvent(
selectedProduct.productUuid,
@@ -205,7 +218,7 @@ function HumanUi() {
...selectedHuman,
point: {
...selectedHuman.point,
action: updatedAction,
actions: updatedActions,
},
}
);
@@ -221,7 +234,7 @@ function HumanUi() {
};
useFrame(() => {
if (isAssembly || !isDragging || !plane.current || !raycaster || !outerGroup.current) return;
if (!isDragging || !plane.current || !raycaster || !outerGroup.current) return;
const intersectPoint = new Vector3();
const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);
if (!intersects) return;
@@ -232,6 +245,8 @@ function HumanUi() {
setStartPosition([localPoint.x, 1, localPoint.z]);
} else if (isDragging === "end") {
setEndPosition([localPoint.x, 1, localPoint.z]);
} else if (isDragging === "assembly") {
setAssemblyPosition([localPoint.x, 1, localPoint.z]);
}
});
@@ -240,28 +255,34 @@ function HumanUi() {
const currentPointerX = state.pointer.x;
const deltaX = currentPointerX - prevMousePos.current.x;
prevMousePos.current.x = currentPointerX;
const marker = isRotating === "start" ? isAssembly ? assemblyMarker.current : startMarker.current : isAssembly ? assemblyMarker.current : endMarker.current;
const marker =
isRotating === "start" ? startMarker.current :
isRotating === "end" ? endMarker.current :
assemblyMarker.current;
if (marker) {
const rotationSpeed = 10;
marker.rotation.y += deltaX * rotationSpeed;
if (isAssembly && isRotating === "start") {
setAssemblyRotation([
marker.rotation.x,
marker.rotation.y,
marker.rotation.z,
]);
} else if (isRotating === "start") {
if (isRotating === "start") {
setStartRotation([
marker.rotation.x,
marker.rotation.y,
marker.rotation.z,
]);
} else {
} else if (isRotating === "end") {
setEndRotation([
marker.rotation.x,
marker.rotation.y,
marker.rotation.z,
]);
} else {
setAssemblyRotation([
marker.rotation.x,
marker.rotation.y,
marker.rotation.z,
]);
}
}
});
@@ -281,7 +302,7 @@ function HumanUi() {
return () => {
window.removeEventListener("pointerup", handleGlobalPointerUp);
};
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation, assemblyRotation]);
}, [isDragging, isRotating, startPosition, startRotation, endPosition, endRotation, assemblyPosition, assemblyRotation]);
return (
<>
@@ -295,16 +316,13 @@ function HumanUi() {
<primitive
ref={assemblyMarker}
object={assemblyScene}
position={[0, 1, 0]}
position={assemblyPosition}
rotation={assemblyRotation}
onPointerDown={(e: any) => {
if (e.object.parent.name === "handle") {
e.stopPropagation();
const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
prevMousePos.current.x = normalizedX;
setIsRotating("start");
setIsDragging(null);
if (controls) (controls as any).enabled = false;
handlePointerDown(e, "assembly", "assembly");
} else {
handlePointerDown(e, "assembly", "assembly");
}
}}
onPointerMissed={() => {
@@ -322,8 +340,11 @@ function HumanUi() {
position={startPosition}
rotation={startRotation}
onPointerDown={(e: any) => {
e.stopPropagation();
handlePointerDown(e, "start", "start");
if (e.object.parent.name === "handle") {
handlePointerDown(e, "start", "start");
} else {
handlePointerDown(e, "start", "start");
}
}}
onPointerMissed={() => {
setIsDragging(null);
@@ -339,8 +360,11 @@ function HumanUi() {
position={endPosition}
rotation={endRotation}
onPointerDown={(e: any) => {
e.stopPropagation();
handlePointerDown(e, "end", "end");
if (e.object.parent.name === "handle") {
handlePointerDown(e, "end", "end");
} else {
handlePointerDown(e, "end", "end");
}
}}
onPointerMissed={() => {
setIsDragging(null);
@@ -356,4 +380,4 @@ function HumanUi() {
);
}
export default HumanUi
export default HumanUi;

View File

@@ -12,7 +12,8 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) {
const matRef: any = useRef();
const { scene } = useThree();
const { selectedProductStore } = useProductContext();
const { productStore } = useSceneContext();
const { productStore, materialStore } = useSceneContext();
const { setIsPaused } = materialStore();
const { getModelUuidByPointUuid, getPointByUuid, getEventByModelUuid, getActionByPointUuid } = productStore();
const { selectedProduct } = selectedProductStore();
const { speed } = useAnimationPlaySpeed();
@@ -80,16 +81,23 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) {
return 1;
}
if (event.type === 'human') {
return event.speed;
}
} else {
return 1;
}
}
const callTrigger = () => {
if (!material.next) return;
const action = getActionByPointUuid(selectedProduct.productUuid, material.next.pointUuid);
if (action) {
triggerPointActions(action, material.materialId);
if (material.next) {
const action = getActionByPointUuid(selectedProduct.productUuid, material.next.pointUuid);
if (action) {
triggerPointActions(action, material.materialId);
}
} else {
setIsPaused(material.materialId, true);
}
}
@@ -97,7 +105,7 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) {
<>
{material.isRendered &&
<MaterialModel materialId={material.materialId} matRef={matRef} materialType={material.materialType} visible={material.isVisible} position={position} />
<MaterialModel materialId={material.materialId} matRef={matRef} materialType={material.materialType} visible={material.isVisible} position={position} rotation={[rotation.x, rotation.y, rotation.z]} />
}
<MaterialAnimator

View File

@@ -20,7 +20,7 @@ function Products() {
const { addMachine, clearMachines } = machineStore();
const { addConveyor, clearConveyors } = conveyorStore();
const { setCurrentMaterials, clearStorageUnits, updateCurrentLoad, addStorageUnit } = storageUnitStore();
const { addHuman, clearHumans } = humanStore();
const { addHuman, addCurrentAction, clearHumans } = humanStore();
const { isReset } = useResetButtonStore();
const { isPlaying } = usePlayButtonStore();
const { mainProduct } = useMainProduct();
@@ -162,6 +162,10 @@ function Products() {
product.eventDatas.forEach(events => {
if (events.type === 'human') {
addHuman(selectedProduct.productUuid, events);
if (events.point.actions.length > 0) {
addCurrentAction(events.modelUuid, events.point.actions[0].actionUuid);
}
}
});
}

View File

@@ -45,7 +45,8 @@ function IKInstance({ setIkSolver, armBot }: IKInstanceProps) {
rotationMax: link.rotationMax ? new THREE.Vector3(...link.rotationMax) : undefined,
limitation: link.limitation ? new THREE.Vector3(...link.limitation) : undefined,
})),
ringRadius: ik.ringRadius,
minDistance: ik.minDistance,
maxDistance: ik.maxDistance,
maxheight: ik.maxheight,
minheight: ik.minheight,
}));

View File

@@ -171,11 +171,22 @@ const ArmBotUI = () => {
}
}
const { handlePointerDown } = useDraggableGLTF(updatePointToState);
const targetMesh = scene?.getObjectByProperty("uuid", selectedArmBotData?.modelUuid || '');
const { handlePointerDown } = useDraggableGLTF(
updatePointToState,
{
minDistance: targetMesh?.userData?.iks[0]?.minDistance || 1.2,
maxDistance: targetMesh?.userData?.iks[0]?.maxDistance || 2,
maxheight: targetMesh?.userData?.iks[0]?.maxheight || 0.6,
minheight: targetMesh?.userData?.iks[0]?.minheight || 1.9,
}
);
if (!selectedArmBotData || !Array.isArray(selectedArmBotData.point?.actions)) {
return null; // avoid rendering if no data yet
return null;
}
return (
<>
{selectedArmBotData.point.actions.map((action: any) => {

View File

@@ -1,15 +1,26 @@
import { useRef, useState } from "react";
import * as THREE from "three";
import { ThreeEvent, useThree } from "@react-three/fiber";
import {
useSelectedEventData,
} from "../../../../store/simulation/useSimulationStore";
import { useSelectedEventData } from "../../../../store/simulation/useSimulationStore";
import { useProductContext } from "../../products/productContext";
import { useSceneContext } from "../../../scene/sceneContext";
type OnUpdateCallback = (object: THREE.Object3D) => void;
export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
export default function useDraggableGLTF(
onUpdate: OnUpdateCallback,
constraints: {
minDistance?: number;
maxDistance?: number;
maxheight?: number;
minheight?: number;
} = {
minDistance: 1.2,
maxDistance: 2,
minheight: 0.6,
maxheight: 1.9
}
) {
const { productStore } = useSceneContext();
const { getEventByModelUuid } = productStore();
const { selectedEventData } = useSelectedEventData();
@@ -120,8 +131,10 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
// CONSTRAIN MOVEMENT HERE:
const centerX = selectedArmBot.position[0];
const centerZ = selectedArmBot.position[2];
const minDistance = 1.2;
const maxDistance = 2;
const minDistance = constraints.minDistance ?? 1.2;
const maxDistance = constraints.maxDistance ?? 2;
const minHeight = constraints.minheight ?? 0.6;
const maxHeight = constraints.maxheight ?? 1.9;
const delta = new THREE.Vector3(targetPosition.x - centerX, 0, targetPosition.z - centerZ);
@@ -169,9 +182,8 @@ export default function useDraggableGLTF(onUpdate: OnUpdateCallback) {
targetPosition.x = centerX + finalLocal.x;
targetPosition.z = centerZ + finalLocal.z;
// Clamp Y axis if needed
targetPosition.y = Math.min(Math.max(targetPosition.y, 0.6), 1.9);
// Clamp Y axis using variables
targetPosition.y = Math.min(Math.max(targetPosition.y, minHeight), maxHeight);
// Convert to local if parent exists
if (parent) {

View File

@@ -22,7 +22,7 @@ export function useTriggerHandler() {
const { addMachineToMonitor } = useMachineEventManager();
const { addHumanToMonitor } = useHumanEventManager();
const { getVehicleById } = vehicleStore();
const { getHumanById } = humanStore();
const { getHumanById, setHumanScheduled } = humanStore();
const { getMachineById } = machineStore();
const { getStorageUnitById } = storageUnitStore();
const { getMaterialById, setCurrentLocation, setNextLocation, setPreviousLocation, setIsPaused, setIsVisible, setEndTime } = materialStore();
@@ -330,37 +330,29 @@ export function useTriggerHandler() {
if (vehicle) {
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
// Handle current action from vehicle
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
addVehicleToMonitor(vehicle.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
}
)
addVehicleToMonitor(vehicle.modelUuid, () => {
handleAction(action, materialId);
})
}
}
} else {
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
addHumanToMonitor(human.modelUuid, () => {
const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
if (vehicle) {
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
// Handle current action from vehicle
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
setIsPaused(materialId, true);
handleAction(action, materialId);
@@ -369,82 +361,32 @@ export function useTriggerHandler() {
// Handle current action using Event Manager
setIsPaused(materialId, true);
addVehicleToMonitor(vehicle.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
}
)
addVehicleToMonitor(vehicle.modelUuid, () => {
handleAction(action, materialId);
})
}
}
})
}, action.actionUuid)
}
}
} else if (model?.type === 'transfer') {
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
if (human) {
if (human.isActive === false && human.state === 'idle') {
if (human && human.modelUuid === "cc62adae-7000-447b-b845-6d4910de503a") {
console.log(human);
}
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
addHumanToMonitor(human.modelUuid, () => {
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
if (conveyor) {
if (!conveyor.isPaused) {
// Handle current action from vehicle
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
setIsPaused(materialId, true);
handleAction(action, materialId);
// Handle current action using Event Manager
setIsPaused(materialId, true);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
addConveyorToMonitor(conveyor.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
}
)
}
}
} else {
setIsPaused(materialId, true);
addHumanToMonitor(human.modelUuid, () => {
const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
if (conveyor) {
if (!conveyor.isPaused) {
// Handle current action from vehicle
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
setIsPaused(materialId, true);
addConveyorToMonitor(conveyor.modelUuid, () => {
addHumanToMonitor(human.modelUuid, () => {
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
addConveyorToMonitor(conveyor.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
}
)
}
}
})
}
}, action.actionUuid)
}, [materialId])
}
}, action.actionUuid)
}
} else if (model?.type === 'machine') {
const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid);
@@ -454,53 +396,39 @@ export function useTriggerHandler() {
if (machine) {
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
setIsPaused(materialId, true);
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
addMachineToMonitor(machine.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
}
)
addMachineToMonitor(machine.modelUuid, () => {
handleAction(action, materialId);
})
}
}
} else {
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
addHumanToMonitor(human.modelUuid, () => {
const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || '');
if (machine) {
if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) {
setIsPaused(materialId, true);
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
addMachineToMonitor(machine.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
}
)
addMachineToMonitor(machine.modelUuid, () => {
handleAction(action, materialId);
})
}
}
}
);
}, action.actionUuid);
}
}
} else {
@@ -508,23 +436,16 @@ export function useTriggerHandler() {
// Handle current action from arm bot
setIsPaused(materialId, true);
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setHumanScheduled(human.modelUuid, true);
setIsPaused(materialId, true);
addHumanToMonitor(human.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId)
}
);
addHumanToMonitor(human.modelUuid, () => {
handleAction(action, materialId)
}, action.actionUuid);
}
}
@@ -533,23 +454,17 @@ export function useTriggerHandler() {
// Handle current action from arm bot
setIsPaused(materialId, true);
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
addHumanToMonitor(human.modelUuid,
() => {
if (action.actionType === 'worker') {
setIsVisible(materialId, false);
}
handleAction(action, materialId)
}
);
setHumanScheduled(human.modelUuid, true);
addHumanToMonitor(human.modelUuid, () => {
handleAction(action, materialId)
}, action.actionUuid);
}
}
@@ -711,26 +626,13 @@ export function useTriggerHandler() {
setNextLocation(material.materialId, null);
if (action && human) {
if (human.isActive === false && human.state === 'idle') {
// Handle current action from arm bot
setHumanScheduled(human.modelUuid, true);
addHumanToMonitor(human.modelUuid, () => {
setIsVisible(materialId, false);
handleAction(action, materialId);
} else {
addHumanToMonitor(human.modelUuid,
() => {
setIsVisible(materialId, false);
handleAction(action, materialId);
}
)
}
}, action.actionUuid)
}
}
}
@@ -879,8 +781,10 @@ export function useTriggerHandler() {
const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || '');
if (previousModel) {
if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) {
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId)
} else {
setHumanScheduled(human.modelUuid, true);
addConveyorToMonitor(conveyor.modelUuid,
() => {
handleAction(action, materialId)
@@ -888,6 +792,7 @@ export function useTriggerHandler() {
)
}
} else {
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId)
}
// handleAction(action, materialId)
@@ -898,12 +803,14 @@ export function useTriggerHandler() {
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
// Handle current action from vehicle
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
addVehicleToMonitor(vehicle.modelUuid,
() => {
@@ -913,6 +820,7 @@ export function useTriggerHandler() {
}
}
} else {
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId)
}
@@ -928,8 +836,11 @@ export function useTriggerHandler() {
const previousModel = getEventByModelUuid(selectedProduct.productUuid, material.previous?.modelUuid || '');
if (previousModel) {
if (previousModel.type === 'transfer' && previousModel.modelUuid === model.modelUuid) {
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId)
} else {
setHumanScheduled(human.modelUuid, true);
addConveyorToMonitor(conveyor.modelUuid,
() => {
handleAction(action, materialId)
@@ -937,6 +848,7 @@ export function useTriggerHandler() {
)
}
} else {
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId)
}
}
@@ -946,12 +858,14 @@ export function useTriggerHandler() {
if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
// Handle current action from vehicle
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId);
} else {
// Handle current action using Event Manager
setIsPaused(materialId, true);
setHumanScheduled(human.modelUuid, true);
addVehicleToMonitor(vehicle.modelUuid,
() => {
@@ -961,10 +875,10 @@ export function useTriggerHandler() {
}
}
} else {
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId)
}
}
);
}, action.actionUuid);
}
}
}
@@ -1255,11 +1169,11 @@ export function useTriggerHandler() {
setNextLocation(material.materialId, null);
if (action) {
if (action && action.actionType === 'worker') {
if (human) {
if (human.isActive === false && human.state === 'idle' && human.isPicking && human.currentLoad < human.point.action.loadCapacity) {
if (human.isActive === false && human.state === 'idle' && !human.isScheduled && human.currentLoad < action.loadCapacity) {
setIsVisible(materialId, false);
@@ -1276,6 +1190,7 @@ export function useTriggerHandler() {
});
// Handle current action from human
setHumanScheduled(human.modelUuid, true);
handleAction(action, materialId);
} else {
@@ -1460,14 +1375,60 @@ export function useTriggerHandler() {
actionUuid: material.current.actionUuid,
});
setNextLocation(material.materialId, {
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid,
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid,
})
setIsPaused(material.materialId, false);
setIsPaused(material.materialId, true);
setIsVisible(material.materialId, true);
const action = getActionByUuid(selectedProduct.productUuid, trigger.triggeredAsset.triggeredAction.actionUuid);
if (action && action.triggers.length > 0 &&
action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid &&
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid) {
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid);
if (model?.type === 'roboticArm') {
addArmBotToMonitor(model.modelUuid, () => {
setNextLocation(material.materialId, {
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
})
setIsPaused(material.materialId, false);
})
} else if (model?.type === 'vehicle') {
addVehicleToMonitor(model.modelUuid, () => {
setNextLocation(material.materialId, {
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
})
setIsPaused(material.materialId, false);
})
} else if (model?.type === 'transfer') {
setNextLocation(material.materialId, {
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
})
setIsPaused(material.materialId, false);
} else if (model?.type === 'human') {
addHumanToMonitor(model.modelUuid, () => {
setNextLocation(material.materialId, {
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
})
setIsPaused(material.materialId, false);
}, action.actionUuid)
} else {
setNextLocation(material.materialId, {
modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '',
pointUuid: trigger.triggeredAsset?.triggeredPoint?.pointUuid || '',
})
setIsPaused(material.materialId, false);
}
}
}
}
@@ -1510,8 +1471,31 @@ export function useTriggerHandler() {
} else {
// Event Manager Needed
setIsPaused(materialId, true);
addVehicleToMonitor(vehicle.modelUuid,
() => {
setIsPaused(materialId, false);
setIsVisible(materialId, false);
setPreviousLocation(material.materialId, {
modelUuid: material.current.modelUuid,
pointUuid: material.current.pointUuid,
actionUuid: material.current.actionUuid,
})
setCurrentLocation(material.materialId, {
modelUuid: trigger?.triggeredAsset?.triggeredModel.modelUuid || '',
pointUuid: trigger?.triggeredAsset?.triggeredPoint?.pointUuid || '',
actionUuid: trigger.triggeredAsset?.triggeredAction?.actionUuid || '',
});
setNextLocation(material.materialId, null);
// Handle current action from vehicle
handleAction(action, materialId);
}
)
}
}
}

View File

@@ -0,0 +1,328 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import { Canvas, useThree, useFrame, ThreeEvent } from '@react-three/fiber';
import { Line, OrbitControls } from '@react-three/drei';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useActiveTool, useSelectedPath } from '../../../../../store/builder/store';
interface InteractivePointsProps {
agvUuid: string;
}
export default function InteractivePoints({ agvUuid }: InteractivePointsProps) {
const { gl, scene, raycaster } = useThree();
const [points, setPoints] = useState<[number, number, number][]>([]);
const { isPaused } = usePauseButtonStore();
const { isPlaying } = usePlayButtonStore();
const { speed } = useAnimationPlaySpeed();
const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0)); // XZ plane
const progressRef = useRef<number>(0);
const { selectedPath } = useSelectedPath();
const lastTimeRef = useRef(performance.now());
const [isAnyDragging, setIsAnyDragging] = useState<string>("");
const { activeTool } = useActiveTool();
const hasClicked = useRef(false);
useFrame(() => {
if (!isPlaying) return
const now = performance.now();
const delta = (now - lastTimeRef.current) / 1000;
lastTimeRef.current = now;
const object = scene.getObjectByProperty('uuid', agvUuid);
if (!object || points.length < 2) return;
if (isPaused) return;
let totalDistance = 0;
const distances = [];
let accumulatedDistance = 0;
let index = 0;
const rotationSpeed = 1;
for (let i = 0; i < points.length - 1; i++) {
const start = new THREE.Vector3(...points[i]);
const end = new THREE.Vector3(...points[i + 1]);
const segmentDistance = start.distanceTo(end);
distances.push(segmentDistance);
totalDistance += segmentDistance;
}
while (index < distances.length && progressRef.current > accumulatedDistance + distances[index]) {
accumulatedDistance += distances[index];
index++;
}
if (index < distances.length) {
const start = new THREE.Vector3(...points[index]);
const end = new THREE.Vector3(...points[index + 1]);
const segmentDistance = distances[index];
const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
const currentAngle = object.rotation.y;
let angleDifference = targetAngle - currentAngle;
if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI;
if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI;
const maxRotationStep = (rotationSpeed * speed * 2) * delta;
object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep);
const isAligned = Math.abs(angleDifference) < 0.01;
if (isAligned) {
progressRef.current += delta * (speed * 2);
const t = (progressRef.current - accumulatedDistance) / segmentDistance;
const position = start.clone().lerp(end, t);
object.position.copy(position);
}
}
});
const downPosition = useRef<{ x: number; y: number } | null>(null);
const handleMouseDown = useCallback((e: MouseEvent) => {
hasClicked.current = false;
downPosition.current = { x: e.clientX, y: e.clientY };
}, []);
const handleClick = useCallback((e: MouseEvent) => {
if (hasClicked.current) return;
hasClicked.current = true;
if (
!downPosition.current ||
Math.abs(downPosition.current.x - e.clientX) > 2 ||
Math.abs(downPosition.current.y - e.clientY) > 2
) {
return;
}
const intersection = new THREE.Vector3();
if (raycaster.ray.intersectPlane(plane.current, intersection) && activeTool !== "pen") {
const pointArray = intersection.toArray() as [number, number, number];
// ✅ Check if this point already exists
const alreadyExists = points.some((p) =>
Math.abs(p[0] - pointArray[0]) < 0.01 &&
Math.abs(p[1] - pointArray[1]) < 0.01 &&
Math.abs(p[2] - pointArray[2]) < 0.01
);
if (!alreadyExists) {
console.log("pointArray: ", pointArray);
setPoints((prev) => [...prev, pointArray]);
console.log("points created");
}
}
}, [activeTool, raycaster, points]);
useEffect(() => {
if (isPlaying) return;
const domElement = gl.domElement;
domElement.addEventListener('mousedown', handleMouseDown);
domElement.addEventListener('mouseup', handleClick);
return () => {
domElement.removeEventListener('mousedown', handleMouseDown);
domElement.removeEventListener('mouseup', handleClick);
;
};
}, [isPlaying, handleClick, handleMouseDown]);
const updatePoint = (index: number, pos: THREE.Vector3) => {
const updated = [...points];
updated[index] = pos.toArray() as [number, number, number];
setPoints(updated);
};
return (
<>
{selectedPath === "manual" &&
<group>
{points.length > 0 && (
<group >
{points.map((pos, i) =>
(<React.Fragment key={i}>
<DraggableSphere
key={i}
index={i}
position={new THREE.Vector3(...pos)}
onMove={updatePoint}
isAnyDragging={isAnyDragging}
setIsAnyDragging={setIsAnyDragging}
/>
</React.Fragment>)
)}
</group >
)
}
{points && (
points.map((pos, i) => {
if (i < points.length - 1) {
return (
<DraggableLineSegment
key={i}
index={i}
start={new THREE.Vector3(...points[i])}
end={new THREE.Vector3(...points[i + 1])}
updatePoints={(i0, p0, i1, p1) => {
const updated = [...points];
updated[i0] = p0.toArray() as [number, number, number];
updated[i1] = p1.toArray() as [number, number, number];
setPoints(updated);
}}
isAnyDragging={isAnyDragging}
setIsAnyDragging={setIsAnyDragging}
/>
);
}
return null;
})
)}
</group>
}
</>
);
}
function DraggableSphere({
index,
position,
onMove,
isAnyDragging,
setIsAnyDragging,
}: {
index: number;
position: THREE.Vector3;
onMove: (index: number, pos: THREE.Vector3) => void;
isAnyDragging: string;
setIsAnyDragging: (val: string) => void;
}) {
const meshRef = useRef<THREE.Mesh>(null);
const { gl, controls, raycaster } = useThree();
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
const { activeTool } = useActiveTool();
const onPointerDown = (e: ThreeEvent<PointerEvent>) => {
e.stopPropagation()
if (activeTool !== 'pen') return;
setIsAnyDragging("point");
gl.domElement.style.cursor = 'grabbing';
if (controls) (controls as any).enabled = false;
};
const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
if (isAnyDragging !== "point" || activeTool !== 'pen') return;
const intersect = new THREE.Vector3();
if (raycaster.ray.intersectPlane(plane, intersect)) {
meshRef.current!.position.copy(intersect);
onMove(index, intersect);
}
};
const onPointerUp = () => {
if (activeTool !== 'pen') return;
setIsAnyDragging("");
gl.domElement.style.cursor = 'default';
if (controls) (controls as any).enabled = true;
};
useEffect(() => {
gl.domElement.addEventListener("pointerup", onPointerUp);
return (() => {
gl.domElement.removeEventListener("pointerup", onPointerUp);
})
}, [activeTool])
return (
<mesh
ref={meshRef}
position={position}
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
onPointerMissed={onPointerUp}
>
<sphereGeometry args={[0.2, 16, 16]} />
<meshStandardMaterial color="red" />
</mesh>
);
}
function DraggableLineSegment({
index,
start,
end,
updatePoints,
isAnyDragging,
setIsAnyDragging,
}: {
index: number;
start: THREE.Vector3;
end: THREE.Vector3;
updatePoints: (i0: number, p0: THREE.Vector3, i1: number, p1: THREE.Vector3) => void;
isAnyDragging: string;
setIsAnyDragging: (val: string) => void;
}) {
const { gl, raycaster, controls } = useThree();
const { activeTool } = useActiveTool();
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
const dragStart = useRef<THREE.Vector3 | null>(null);
const onPointerDown = () => {
if (activeTool !== 'pen' || isAnyDragging) return;
setIsAnyDragging("line");
gl.domElement.style.cursor = 'grabbing';
if (controls) (controls as any).enabled = false;
};
const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
if (isAnyDragging !== "line" || activeTool !== 'pen') return;
const intersect = new THREE.Vector3();
if (raycaster.ray.intersectPlane(plane, intersect)) {
if (!dragStart.current) dragStart.current = intersect.clone();
const offset = new THREE.Vector3().subVectors(intersect, dragStart.current);
const newStart = start.clone().add(offset);
const newEnd = end.clone().add(offset);
updatePoints(index, newStart, index + 1, newEnd);
}
};
const onPointerUp = () => {
if (activeTool !== 'pen') return;
setIsAnyDragging("");
dragStart.current = null;
gl.domElement.style.cursor = 'default';
if (controls) (controls as any).enabled = true;
};
useEffect(() => {
gl.domElement.addEventListener("pointerup", onPointerUp);
return (() => {
gl.domElement.removeEventListener("pointerup", onPointerUp);
})
}, [activeTool])
return (
<Line
points={[start, end]}
color="blue"
lineWidth={5}
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
onPointerMissed={onPointerUp}
/>
);
}

View File

@@ -1,10 +1,12 @@
import { useEffect, useRef, useState } from 'react'
import { useFrame, useThree } from '@react-three/fiber';
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { useFrame, useThree, ThreeEvent } from '@react-three/fiber';
import * as THREE from 'three';
import { Line } from '@react-three/drei';
import { RapierRigidBody } from '@react-three/rapier';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useActiveTool, useSelectedPath } from '../../../../../store/builder/store';
interface VehicleAnimatorProps {
path: [number, number, number][];
@@ -30,7 +32,9 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
const [restRotation, setRestingRotation] = useState<boolean>(true);
const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
const rigidBodyRef = useRef<RapierRigidBody>(null);
const { scene } = useThree();
const { scene, controls } = useThree();
const { selectedPath } = useSelectedPath();
const [isAnyDragging, setIsAnyDragging] = useState<string>("");
const object = scene.getObjectByProperty('uuid', agvUuid);
@@ -39,7 +43,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
}
useEffect(() => {
if (currentPhase === 'stationed-pickup' && path.length > 0) {
if (currentPhase === 'stationed-pickup' && path.length > 0 && selectedPath === "auto") {
setCurrentPath(path);
setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation)
} else if (currentPhase === 'pickup-drop' && path.length > 0) {
@@ -49,7 +53,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
setObjectRotation(agvDetail.point.action?.pickUpPoint?.rotation)
setCurrentPath(path);
}
}, [currentPhase, path, objectRotation]);
}, [currentPhase, path, objectRotation, selectedPath]);
useEffect(() => {
completedRef.current = false;
@@ -82,6 +86,7 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
const lastTimeRef = useRef(performance.now());
useFrame(() => {
if (!isPlaying) return
const now = performance.now();
const delta = (now - lastTimeRef.current) / 1000;
lastTimeRef.current = now;
@@ -217,26 +222,197 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai
handleCallBack();
if (currentPhase === 'pickup-drop') {
requestAnimationFrame(startUnloadingProcess);
}
}
});
const updatePoint = (index: number, pos: THREE.Vector3) => {
const updated = [...currentPath];
updated[index] = pos.toArray() as [number, number, number];
setCurrentPath(updated);
};
return (
<>
{currentPath.length > 0 && (
// helper
<group visible={false}>
<Line points={currentPath} color="blue" lineWidth={3} />
{currentPath.map((point, index) => (
<mesh key={index} position={point}>
<sphereGeometry args={[0.1, 16, 16]} />
<meshStandardMaterial color="red" />
</mesh>
))}
</group>
)}
{selectedPath === "auto" &&
<group>
{currentPath.map((pos, i) => {
if (i < currentPath.length - 1) {
return (
<DraggableLineSegment
key={i}
index={i}
start={new THREE.Vector3(...currentPath[i])}
end={new THREE.Vector3(...currentPath[i + 1])}
updatePoints={(i0, p0, i1, p1) => {
const updated = [...currentPath];
updated[i0] = p0.toArray() as [number, number, number];
updated[i1] = p1.toArray() as [number, number, number];
setCurrentPath(updated);
}}
isAnyDragging={isAnyDragging}
setIsAnyDragging={setIsAnyDragging}
/>
);
}
return null;
})}
{currentPath.length > 0 && (
<group onPointerMissed={() => { if (controls) (controls as any).enabled = true; }}>
{currentPath.map((pos, i) =>
(
<DraggableSphere
key={i}
index={i}
position={new THREE.Vector3(...pos)}
onMove={updatePoint}
isAnyDragging={isAnyDragging}
setIsAnyDragging={setIsAnyDragging}
/>)
)}
</group >
)}
</group >
}
</>
);
}
export default VehicleAnimator;
export default VehicleAnimator;
function DraggableSphere({
index,
position,
onMove,
isAnyDragging,
setIsAnyDragging,
}: {
index: number;
position: THREE.Vector3;
onMove: (index: number, pos: THREE.Vector3) => void;
isAnyDragging: string;
setIsAnyDragging: (val: string) => void;
}) {
const meshRef = useRef<THREE.Mesh>(null);
const { gl, controls, raycaster } = useThree();
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
const { activeTool } = useActiveTool();
const onPointerDown = (e: ThreeEvent<PointerEvent>) => {
e.stopPropagation()
if (activeTool !== 'pen') return;
setIsAnyDragging("point");
gl.domElement.style.cursor = 'grabbing';
if (controls) (controls as any).enabled = false;
};
const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
if (isAnyDragging !== "point" || activeTool !== 'pen') return;
const intersect = new THREE.Vector3();
if (raycaster.ray.intersectPlane(plane, intersect)) {
meshRef.current!.position.copy(intersect);
onMove(index, intersect);
}
};
const onPointerUp = () => {
if (activeTool !== 'pen') return;
setIsAnyDragging("");
gl.domElement.style.cursor = 'default';
if (controls) (controls as any).enabled = true;
};
useEffect(() => {
gl.domElement.addEventListener("pointerup", onPointerUp);
return (() => {
gl.domElement.removeEventListener("pointerup", onPointerUp);
})
}, [activeTool])
return (
<mesh
ref={meshRef}
position={position}
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
onPointerMissed={onPointerUp}
>
<sphereGeometry args={[0.2, 16, 16]} />
<meshStandardMaterial color="red" />
</mesh>
);
}
function DraggableLineSegment({
index,
start,
end,
updatePoints,
isAnyDragging,
setIsAnyDragging,
}: {
index: number;
start: THREE.Vector3;
end: THREE.Vector3;
updatePoints: (i0: number, p0: THREE.Vector3, i1: number, p1: THREE.Vector3) => void;
isAnyDragging: string;
setIsAnyDragging: (val: string) => void;
}) {
const { gl, raycaster, controls } = useThree();
const { activeTool } = useActiveTool();
const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);
const dragStart = useRef<THREE.Vector3 | null>(null);
const onPointerDown = () => {
if (activeTool !== 'pen' || isAnyDragging) return;
setIsAnyDragging("line");
gl.domElement.style.cursor = 'grabbing';
if (controls) (controls as any).enabled = false;
};
const onPointerMove = (e: ThreeEvent<PointerEvent>) => {
console.log('isAnyDragging: ', isAnyDragging);
if (isAnyDragging !== "line" || activeTool !== 'pen') return;
const intersect = new THREE.Vector3();
if (raycaster.ray.intersectPlane(plane, intersect)) {
if (!dragStart.current) dragStart.current = intersect.clone();
const offset = new THREE.Vector3().subVectors(intersect, dragStart.current);
const newStart = start.clone().add(offset);
const newEnd = end.clone().add(offset);
updatePoints(index, newStart, index + 1, newEnd);
}
};
const onPointerUp = () => {
if (activeTool !== 'pen') return;
setIsAnyDragging("");
dragStart.current = null;
gl.domElement.style.cursor = 'default';
if (controls) (controls as any).enabled = true;
};
useEffect(() => {
gl.domElement.addEventListener("pointerup", onPointerUp);
return (() => {
gl.domElement.removeEventListener("pointerup", onPointerUp);
})
}, [activeTool])
return (
<Line
points={[start, end]}
color="blue"
lineWidth={5}
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
onPointerMissed={onPointerUp}
/>
);
}

View File

@@ -1,30 +1,34 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import { NavMeshQuery } from '@recast-navigation/core';
import { useNavMesh } from '../../../../../store/builder/store';
import { useNavMesh, useSelectedPath } from '../../../../../store/builder/store';
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore } from '../../../../../store/usePlayButtonStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
import { useSceneContext } from '../../../../scene/sceneContext';
import { useProductContext } from '../../../products/productContext';
import InteractivePoints from '../animator/interactivePoint';
import MaterialAnimator from '../animator/materialAnimator';
import VehicleAnimator from '../animator/vehicleAnimator';
import { useHumanEventManager } from '../../../human/eventManager/useHumanEventManager';
function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) {
const { navMesh } = useNavMesh();
const { isPlaying } = usePlayButtonStore();
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore } = useSceneContext();
const { removeMaterial, setEndTime } = materialStore();
const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore, assetStore } = useSceneContext();
const { removeMaterial, setEndTime, setIsVisible } = materialStore();
const { getStorageUnitById } = storageUnitStore();
const { getHumanById } = humanStore();
const { getHumanById, addCurrentAction, addCurrentMaterial, incrementHumanLoad , incrementLoadCount } = humanStore();
const { getArmBotById } = armBotStore();
const { getConveyorById } = conveyorStore();
const { triggerPointActions } = useTriggerHandler();
const { setCurrentAnimation, getAssetById } = assetStore();
const { addHumanToMonitor } = useHumanEventManager();
const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { vehicles, setVehicleActive, setVehicleState, setVehiclePicking, clearCurrentMaterials, setVehicleLoad, decrementVehicleLoad, removeLastMaterial, getLastMaterial, incrementIdleTime, incrementActiveTime, resetTime } = vehicleStore();
const [currentPhase, setCurrentPhase] = useState<string>('stationed');
const [path, setPath] = useState<[number, number, number][]>([]);
const pauseTimeRef = useRef<number | null>(null);
@@ -38,6 +42,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
const { isPaused } = usePauseButtonStore();
const previousTimeRef = useRef<number | null>(null);
const animationFrameIdRef = useRef<number | null>(null);
const { selectedPath, setSelectedPath } = useSelectedPath();
useEffect(() => {
isPausedRef.current = isPaused;
@@ -59,17 +64,15 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
) {
return segmentPath?.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
} else {
console.log("There is no path here...Choose valid path")
const { path: segmentPaths } = navMeshQuery.computePath(start, start);
return segmentPaths.map(({ x, y, z }) => [x, 0, z] as [number, number, number]) || [];
}
} catch {
console.error("Failed to compute path");
return [];
}
},
[navMesh]
);
}, [navMesh]);
function vehicleStatus(modelId: string, status: string) {
// console.log(`${modelId} , ${status}`);
@@ -97,7 +100,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
useEffect(() => {
if (isPlaying) {
if (isPlaying && selectedPath === "auto") {
if (!agvDetail.point.action.unLoadPoint || !agvDetail.point.action.pickUpPoint) return;
if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') {
@@ -105,10 +108,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
agvDetail?.point?.action?.pickUpPoint?.position
);
// const toPickupPath = computePath(
// new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2]),
// new THREE.Vector3(agvDetail?.position[0], agvDetail?.position[1], agvDetail?.position[2])
// );
setPath(toPickupPath);
setCurrentPhase('stationed-pickup');
setVehicleState(agvDetail.modelUuid, 'running');
@@ -149,8 +149,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
else {
reset()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [vehicles, currentPhase, path, isPlaying]);
}, [vehicles, currentPhase, path, isPlaying, selectedPath]);
function animate(currentTime: number) {
if (previousTimeRef.current === null) {
@@ -228,6 +227,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (agvDetail.point.action.triggers.length > 0) {
const trigger = getTriggerByUuid(selectedProduct.productUuid, agvDetail.point.action.triggers[0]?.triggerUuid);
const model = getEventByModelUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredModel?.modelUuid || '');
const triggeredAction = getActionByUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredAction?.actionUuid || '');
if (trigger && model) {
if (model.type === 'transfer') {
@@ -249,8 +249,8 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
} else if (model.type === 'human') {
const action = getActionByUuid(selectedProduct.productUuid, agvDetail.point.action.actionUuid);
if (action) {
handleMaterialDropToHuman(model);
if (action && (triggeredAction?.actionType === 'assembly' || triggeredAction?.actionType === 'worker')) {
handleMaterialDropToHuman(model, triggeredAction);
}
}
} else {
@@ -265,76 +265,59 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
}
}
function handleMaterialDropToHuman(model: HumanEventSchema) {
function handleMaterialDropToHuman(model: HumanEventSchema, action: HumanAction) {
if (model) {
if (model.point.action.actionType === 'worker') {
loopMaterialDropToHuman(
agvDetail.modelUuid,
agvDetail.currentLoad,
agvDetail.point.action.unLoadDuration,
model.modelUuid,
model.point.action.loadCapacity,
agvDetail.point.action
);
if (action.actionType === 'worker') {
addHumanToMonitor(model.modelUuid, () => {
loopMaterialDropToHuman(
agvDetail,
model.modelUuid,
action.actionUuid
);
}, action.actionUuid || '')
}
}
}
function loopMaterialDropToHuman(
vehicleId: string,
vehicleCurrentLoad: number,
unLoadDuration: number,
vehicle: VehicleStatus,
humanId: string,
storageMaxCapacity: number,
action: VehicleAction
humanActionId: string
) {
startTime = performance.now();
const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / isSpeedRef.current));
let currentVehicleLoad = vehicle.currentLoad;
const unloadLoop = () => {
if (isPausedRef.current) {
pauseTimeRef.current ??= performance.now();
requestAnimationFrame(unloadLoop);
const human = getHumanById(humanId);
const humanAsset = getAssetById(humanId);
const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId);
if (!human || human.currentAction?.actionUuid !== humanAction?.actionUuid) return;
if (!human.isActive && human.currentLoad < (humanAction?.loadCapacity || 0) && humanAsset?.animationState?.current === 'idle' && humanAction?.actionType === 'worker') {
setCurrentAnimation(human.modelUuid, 'pickup', true, false, false);
decrementVehicleLoad(vehicle.modelUuid, 1);
currentVehicleLoad -= 1;
const material = removeLastMaterial(vehicle.modelUuid);
if (material) {
setIsVisible(material.materialId, false);
addCurrentMaterial(humanId, material.materialType, material.materialId);
incrementHumanLoad(humanId, 1);
incrementLoadCount(humanId, 1);
}
return;
}
if (pauseTimeRef.current) {
const pauseDuration = performance.now() - pauseTimeRef.current;
startTime += pauseDuration;
pauseTimeRef.current = null;
}
const elapsedTime = performance.now() - startTime;
const human = getHumanById(humanId);
if (elapsedTime >= fixedInterval) {
if (human && agvDetail &&
human.currentLoad < storageMaxCapacity &&
vehicleCurrentLoad > 0) {
decrementVehicleLoad(vehicleId, 1);
vehicleCurrentLoad -= 1;
const material = removeLastMaterial(vehicleId);
if (material) {
triggerPointActions(action, material.materialId);
}
if (vehicleCurrentLoad > 0 && human.currentLoad < storageMaxCapacity) {
startTime = performance.now();
requestAnimationFrame(unloadLoop);
}
}
} else {
setTimeout(() => {
requestAnimationFrame(unloadLoop);
}
}, 500)
};
const human = getHumanById(humanId);
if (human && vehicleCurrentLoad > 0 && human?.currentLoad < storageMaxCapacity) {
unloadLoop();
const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId);
if (human && human.currentAction?.actionUuid !== humanActionId && human.currentLoad < (humanAction?.loadCapacity || 0)) {
addCurrentAction(humanId, humanActionId);
setTimeout(() => {
unloadLoop();
}, 500)
}
}
@@ -600,6 +583,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
reset={reset}
startUnloadingProcess={startUnloadingProcess}
/>
{selectedPath === "manual" && (<InteractivePoints agvUuid={agvDetail?.modelUuid} />)}
<MaterialAnimator agvDetail={agvDetail} />
</>
);

View File

@@ -1,25 +1,32 @@
import { useRef } from "react";
import { useNavMesh } from "../../../../store/builder/store";
import PolygonGenerator from "./polygonGenerator";
import NavMeshDetails from "./navMeshDetails";
import * as CONSTANTS from "../../../../types/world/worldConstants";
import * as Types from "../../../../types/world/worldTypes";
import { useLoadingProgress, useNavMesh, useTileDistance } from "../../../../store/builder/store";
import useModuleStore from "../../../../store/useModuleStore";
import PolygonGenerator from "./polygonGenerator";
import NavMeshDetails from "./navMeshDetails";
function NavMesh() {
let groupRef = useRef() as Types.RefGroup;
const { setNavMesh } = useNavMesh();
const { loadingProgress } = useLoadingProgress();
const { activeModule } = useModuleStore();
const { planeValue, gridValue } = useTileDistance();
return (
<>
<PolygonGenerator groupRef={groupRef} />
<NavMeshDetails setNavMesh={setNavMesh} groupRef={groupRef} />
{activeModule === 'simulation' && loadingProgress === 0 &&
<>
<PolygonGenerator groupRef={groupRef} />
<NavMeshDetails setNavMesh={setNavMesh} groupRef={groupRef} />
<group ref={groupRef} visible={false} name="Meshes">
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} receiveShadow>
<planeGeometry args={[300, 300]} />
<meshBasicMaterial color={CONSTANTS.planeConfig.color} />
</mesh>
</group>
<group ref={groupRef} visible={false} name="Meshes">
<mesh rotation-x={CONSTANTS.planeConfig.rotation} position={CONSTANTS.planeConfig.position3D} receiveShadow>
<planeGeometry args={[planeValue.width, planeValue.height]} />
</mesh>
</group>
</>
}
</>
)
}

View File

@@ -1,53 +1,58 @@
import React, { useEffect } from "react";
import React, { useEffect, useMemo } from "react";
import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import { generateSoloNavMesh } from "@recast-navigation/generators";
import { init as initRecastNavigation } from "@recast-navigation/core";
import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three";
import { useSceneContext } from "../../../scene/sceneContext";
import { useToggleView } from "../../../../store/builder/store";
interface NavMeshDetailsProps {
setNavMesh: (navMesh: any) => void;
groupRef: React.MutableRefObject<THREE.Group | null>;
}
const NAVMESH_CONFIG = {
// cellSize: 0.2,
// cellHeight: 0.7,
// walkableRadius: 0.5,
cellSize: 0.3,
cellHeight: 0.7,
walkableRadius: 0.7,
};
export default function NavMeshDetails({
setNavMesh,
groupRef,
}: NavMeshDetailsProps) {
const { aisleStore, wallStore } = useSceneContext();
const { aisles } = aisleStore();
const { scene } = useThree();
const { walls } = wallStore();
const { toggleView } = useToggleView();
const meshes = useMemo(() => {
return groupRef.current?.children.filter((child): child is THREE.Mesh =>
child instanceof THREE.Mesh
) || [];
}, [groupRef.current?.children]);
useEffect(() => {
if (toggleView || meshes.length === 0) return;
const initializeNavigation = async () => {
try {
await initRecastNavigation();
if (!groupRef.current || groupRef.current.children.length === 0) {
return;
}
const meshes = groupRef?.current?.children as THREE.Mesh[];
const [positions, indices] = getPositionsAndIndices(meshes);
// const cellSize = 0.2;
// const cellHeight = 0.7;
// const walkableRadius = 0.5;
const { cellSize, cellHeight, walkableRadius } = NAVMESH_CONFIG;
const cellSize = 0.3;
const cellHeight = 0.7;
const walkableRadius = 0.7;
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
cs: cellSize,
ch: cellHeight,
walkableRadius: Math.round(walkableRadius / cellHeight),
});
if (!success || !navMesh) {
return;
}
if (!success || !navMesh) return;
setNavMesh(navMesh);
@@ -59,12 +64,12 @@ export default function NavMeshDetails({
debugDrawer.drawNavMesh(navMesh);
// scene.add(debugDrawer);
} catch (error) {
echo.error("Failed to initialize navigation")
console.error("Failed to initialize navigation:", error);
}
};
initializeNavigation();
}, [scene, groupRef, aisles, walls]);
}, [meshes, setNavMesh, toggleView, scene]);
return null;
}

View File

@@ -76,10 +76,16 @@ export default function PolygonGenerator({
turf.lineString(line.map((p: any) => p?.position))
);
const validLineFeatures = lineFeatures.filter((line) => {
let validLineFeatures = lineFeatures.filter((line) => {
const coords = line.geometry.coordinates;
return coords.length >= 2;
});
}).filter((line) => {
if (line.geometry.coordinates[0].toString() !== line.geometry.coordinates[1].toString()) {
return true;
}
})
if (validLineFeatures.length < 3) { validLineFeatures = [] }
const polygons = turf.polygonize(turf.featureCollection(validLineFeatures));

View File

@@ -16,8 +16,9 @@ const Dashboard: React.FC = () => {
useEffect(() => {
const token = localStorage.getItem("token");
const refreshToken = localStorage.getItem("refreshToken")
if (token) {
useSocketStore.getState().initializeSocket(email, organization, token);
useSocketStore.getState().initializeSocket(email, organization, token, refreshToken);
} else {
}

View File

@@ -1,17 +1,12 @@
import React, { useEffect } from "react";
import useModuleStore from "../store/useModuleStore";
import {
useSocketStore,
useOrganization,
useUserName,
useWallItems,
useSaveVersion,
useViewSceneStore,
useProjectName,
useRenameModeStore,
useSelectedFloorItem,
useZones,
useSelectedComment,
useSocketStore,
useOrganization,
useUserName,
useSaveVersion,
useProjectName,
useActiveTool,
} from "../store/builder/store";
import { useNavigate, useParams } from "react-router-dom";
import { useSelectedUserStore } from "../store/collaboration/useCollabStore";
@@ -31,127 +26,134 @@ import { useVersionHistoryStore } from "../store/builder/useVersionHistoryStore"
import { VersionProvider } from "../modules/builder/version/versionContext";
import { sharedWithMeProjects } from "../services/dashboard/sharedWithMeProject";
import SecondaryCanvas from "../modules/secondaryCamera/secondaryCanvas";
import { handleCanvasCursors } from "../utils/mouseUtils/handleCanvasCursors";
const Project: React.FC = () => {
let navigate = useNavigate();
const echo = useLogger();
const { setToggleUI } = useToggleStore();
const { setActiveModule } = useModuleStore();
const { setUserName } = useUserName();
const { setOrganization } = useOrganization();
const { setWallItems } = useWallItems();
const { setZones } = useZones();
const { isVersionSaved } = useSaveVersion();
const { projectId } = useParams();
const { setProjectName } = useProjectName();
const { userId, email, organization, userName } = getUserData();
const { selectedUser } = useSelectedUserStore();
const { isLogListVisible } = useLogger();
const { setVersions } = useVersionHistoryStore();
let navigate = useNavigate();
const echo = useLogger();
const { setToggleUI } = useToggleStore();
const { setActiveModule } = useModuleStore();
const { setUserName } = useUserName();
const { setOrganization } = useOrganization();
const { isVersionSaved } = useSaveVersion();
const { projectId } = useParams();
const { setProjectName } = useProjectName();
const { userId, email, organization, userName } = getUserData();
const { selectedUser } = useSelectedUserStore();
const { isLogListVisible } = useLogger();
const { setVersions } = useVersionHistoryStore();
const { activeTool } = useActiveTool();
useEffect(() => {
if (!email || !userId) {
console.error("User data not found in localStorage");
return;
}
useEffect(() => {
if (!email || !userId) {
console.error("User data not found in localStorage");
return;
}
const fetchProjects = async () => {
try {
const projects = await getAllProjects(userId, organization);
const shared = await sharedWithMeProjects();
const fetchProjects = async () => {
try {
const projects = await getAllProjects(userId, organization);
const shared = await sharedWithMeProjects();
const allProjects = [...(projects?.Projects || []), ...(shared || [])];
const allProjects = [...(projects?.Projects || []), ...(shared || [])];
const matchedProject = allProjects.find(
(val: any) => val.projectUuid === projectId || val._id === projectId
);
const matchedProject = allProjects.find(
(val: any) => val.projectUuid === projectId || val._id === projectId
);
if (matchedProject) {
setProjectName(matchedProject.projectName);
await viewProject(organization, matchedProject._id, userId);
} else {
console.warn("Project not found with given ID:", projectId);
}
} catch (error) {
console.error("Error fetching projects:", error);
}
};
if (matchedProject) {
setProjectName(matchedProject.projectName);
await viewProject(organization, matchedProject._id, userId);
} else {
console.warn("Project not found with given ID:", projectId);
}
} catch (error) {
console.error("Error fetching projects:", error);
}
};
fetchProjects();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
fetchProjects();
}, []);
useEffect(() => {
if (!projectId) return;
getVersionHistoryApi(projectId)
.then((data) => {
const versions: VersionHistory = [];
data.versions.forEach((version: any) => {
versions.push({
version: version.version,
versionId: version.versionId,
versionName: version.versionName,
versionDescription: version.description,
timeStamp: version.createdAt,
createdBy: version.createdBy.userName,
});
});
setVersions(versions);
})
.catch(() => {
console.error("Error fetching version history");
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectId]);
useEffect(() => {
if (!isVersionSaved) {
setToggleUI(true, true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isVersionSaved]);
useEffect(() => {
if (!projectId) return;
getVersionHistoryApi(projectId).then((data) => {
const versions: VersionHistory = [];
data.versions.forEach((version: any) => {
versions.push({
version: version.version,
versionId: version.versionId,
versionName: version.versionName,
versionDescription: version.description,
timeStamp: version.createdAt,
createdBy: version.createdBy.userName
})
})
setVersions(versions);
}).catch(() => {
console.error("Error fetching version history")
})
}, [projectId])
useEffect(() => {
setActiveModule("builder");
if (email) {
const token = localStorage.getItem("token");
const refreshToken = localStorage.getItem("refreshToken");
if (token) {
useSocketStore
.getState()
.initializeSocket(email, organization, token, refreshToken);
}
if (organization && userName) {
setOrganization(organization);
setUserName(userName);
}
echo.success("Log in successful");
} else {
navigate("/");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (!isVersionSaved) {
setToggleUI(true, true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isVersionSaved]);
useEffect(() => {
handleCanvasCursors(activeTool);
}, [activeTool]);
useEffect(() => {
setWallItems([]);
setZones([]);
setActiveModule("builder");
if (email) {
const token = localStorage.getItem("token");
if (token) {
useSocketStore.getState().initializeSocket(email, organization, token);
}
if (organization && userName) {
setOrganization(organization);
setUserName(userName);
}
echo.success("Log in successful");
} else {
navigate("/");
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<div className="project-main">
<SceneProvider layout="Main Layout">
<VersionProvider>
<MainSceneProvider />
</VersionProvider>
</SceneProvider>
<SceneProvider layout="Comparison Layout">
<VersionProvider>
<ComparisonSceneProvider />
</VersionProvider>
</SceneProvider>
return (
<div className="project-main">
<SceneProvider layout="Main Layout">
<VersionProvider>
<MainSceneProvider />
</VersionProvider>
</SceneProvider>
<SceneProvider layout="Comparison Layout">
<VersionProvider>
<ComparisonSceneProvider />
</VersionProvider>
</SceneProvider>
<SecondaryCanvas />
<SecondaryCanvas />
{selectedUser && <FollowPerson />}
{isLogListVisible && (
<RenderOverlay>
<LogList />
</RenderOverlay>
)}
</div>
);
{selectedUser && <FollowPerson />}
{isLogListVisible && (
<RenderOverlay>
<LogList />
</RenderOverlay>
)}
</div>
);
};
export default Project;

View File

@@ -1,11 +1,15 @@
import * as THREE from "three";
import { create } from "zustand";
import { io } from "socket.io-client";
import * as CONSTANTS from "../../types/world/worldConstants";
export const useSocketStore = create<any>((set: any, get: any) => ({
socket: null,
initializeSocket: (email?: string, organization?: string, token?: string) => {
initializeSocket: (
email?: string,
organization?: string,
token?: string,
refreshToken?: string
) => {
const existingSocket = get().socket;
if (existingSocket) {
return;
@@ -15,7 +19,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Builder_v1`,
{
reconnection: true,
auth: { token },
auth: { token, refreshToken },
}
);
@@ -23,7 +27,7 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/Visualization_v1`,
{
reconnection: true,
auth: { token },
auth: { token, refreshToken },
}
);
@@ -31,21 +35,21 @@ export const useSocketStore = create<any>((set: any, get: any) => ({
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/dashboard`,
{
reconnection: true,
auth: { token },
auth: { token, refreshToken },
}
);
const projectSocket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/project`,
{
reconnection: true,
auth: { token },
auth: { token, refreshToken },
}
);
const threadSocket = io(
`http://${process.env.REACT_APP_SERVER_SOCKET_API_BASE_URL}/thread`,
{
reconnection: true,
auth: { token },
auth: { token, refreshToken },
}
);
@@ -141,39 +145,11 @@ export const useToggleView = create<any>((set: any) => ({
setToggleView: (x: any) => set(() => ({ toggleView: x })),
}));
export const useUpdateScene = create<any>((set: any) => ({
updateScene: false,
setUpdateScene: (x: any) => set(() => ({ updateScene: x })),
}));
export const useWalls = create<any>((set: any) => ({
walls: [],
setWalls: (x: any) => set(() => ({ walls: x })),
}));
export const useRoomsState = create<any>((set: any) => ({
roomsState: [],
setRoomsState: (x: any) => set(() => ({ roomsState: x })),
}));
export const useZones = create<any>((set: any) => ({
zones: [],
setZones: (callback: any) =>
set((state: any) => ({
zones: typeof callback === "function" ? callback(state.zones) : callback,
})),
}));
interface ZonePointsState {
zonePoints: THREE.Vector3[];
setZonePoints: (points: THREE.Vector3[]) => void;
}
export const useZonePoints = create<ZonePointsState>((set) => ({
zonePoints: [],
setZonePoints: (points) => set({ zonePoints: points }),
}));
export const useSelectedItem = create<any>((set: any) => ({
selectedItem: {
name: "",
@@ -210,45 +186,11 @@ export const useMenuVisible = create<any>((set: any) => ({
setMenuVisible: (x: any) => set(() => ({ menuVisible: x })),
}));
// export const useDeleteTool = create<any>((set: any) => ({
// deleteTool: false,
// setDeleteTool: (x: any) => set(() => ({ deleteTool: x })),
// }));
export const useToolMode = create<any>((set: any) => ({
toolMode: null,
setToolMode: (x: any) => set(() => ({ toolMode: x })),
}));
export const useNewLines = create<any>((set: any) => ({
newLines: [],
setNewLines: (x: any) => set(() => ({ newLines: x })),
}));
export const useDeletedLines = create<any>((set: any) => ({
deletedLines: [],
setDeletedLines: (x: any) => set(() => ({ deletedLines: x })),
}));
export const useMovePoint = create<any>((set: any) => ({
movePoint: false,
setMovePoint: (x: any) => set(() => ({ movePoint: x })),
}));
// export const useDeletePointOrLine = create<any>((set: any) => ({
// deletePointOrLine: false,
// setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })),
// }));
export const useWallItems = create<any>((set: any) => ({
wallItems: [],
setWallItems: (callback: any) =>
set((state: any) => ({
wallItems:
typeof callback === "function" ? callback(state.wallItems) : callback,
})),
}));
export const useSelectedWallItem = create<any>((set: any) => ({
selectedWallItem: null,
setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })),
@@ -310,24 +252,6 @@ export const useActiveLayer = create<any>((set: any) => ({
setActiveLayer: (x: any) => set({ activeLayer: x }),
}));
interface RefTextUpdateState {
refTextupdate: number;
setRefTextUpdate: (
callback: (currentValue: number) => number | number
) => void;
}
export const useRefTextUpdate = create<RefTextUpdateState>((set) => ({
refTextupdate: -1000,
setRefTextUpdate: (callback) =>
set((state) => ({
refTextupdate:
typeof callback === "function"
? callback(state.refTextupdate)
: callback,
})),
}));
export const useResetCamera = create<any>((set: any) => ({
resetCamera: false,
setResetCamera: (x: any) => set({ resetCamera: x }),
@@ -348,11 +272,6 @@ export const useActiveSubTool = create<any>((set: any) => ({
setActiveSubTool: (x: any) => set({ activeSubTool: x }),
}));
export const use2DUndoRedo = create<any>((set: any) => ({
is2DUndoRedo: null,
set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }),
}));
export const useElevation = create<any>((set: any) => ({
elevation: 45,
setElevation: (x: any) => set({ elevation: x }),
@@ -429,21 +348,6 @@ export const useDrieUIValue = create<any>((set: any) => ({
})),
}));
export const useStartSimulation = create<any>((set: any) => ({
startSimulation: false,
setStartSimulation: (x: any) => set({ startSimulation: x }),
}));
export const useEyeDropMode = create<any>((set: any) => ({
eyeDropMode: false,
setEyeDropMode: (x: any) => set({ eyeDropMode: x }),
}));
export const useEditingPoint = create<any>((set: any) => ({
editingPoint: false,
setEditingPoint: (x: any) => set({ editingPoint: x }),
}));
export const usezoneTarget = create<any>((set: any) => ({
zoneTarget: [],
setZoneTarget: (x: any) => set({ zoneTarget: x }),
@@ -769,4 +673,8 @@ export const useSecondaryCameraState = create<SecondaryCameraState>((set) => ({
export const useSecondaryCameraEdit = create<any>((set) => ({
secondaryCameraEdit: false,
setSecondaryCameraEdit: (x: boolean) => set({ secondaryCameraEdit: x }),
}));
}));
export const useSelectedPath = create<any>((set: any) => ({
selectedPath: "auto",
setSelectedPath: (x: any) => set({ selectedPath: x }),
}));

View File

@@ -12,8 +12,13 @@ interface HumansStore {
) => void;
clearHumans: () => void;
setCurrentPhase: (modelUuid: string, phase: string) => void;
addCurrentAction: (modelUuid: string, actionUuid: string) => void;
removeCurrentAction: (modelUuid: string) => void;
setHumanActive: (modelUuid: string, isActive: boolean) => void;
setHumanPicking: (modelUuid: string, isPicking: boolean) => void;
setHumanScheduled: (modelUuid: string, isPicking: boolean) => void;
setHumanLoad: (modelUuid: string, load: number) => void;
setHumanState: (
modelUuid: string,
@@ -22,6 +27,11 @@ interface HumansStore {
incrementHumanLoad: (modelUuid: string, incrementBy: number) => void;
decrementHumanLoad: (modelUuid: string, decrementBy: number) => void;
incrementLoadCount: (modelUuid: string, incrementBy: number) => void;
decrementLoadCount: (modelUuid: string, decrementBy: number) => void;
clearLoadCount: (modelUuid: string) => void;
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void;
removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined;
@@ -50,10 +60,12 @@ export const createHumanStore = () => {
state.humans.push({
...event,
productUuid,
currentPhase: 'init',
isActive: false,
isPicking: false,
isScheduled: false,
idleTime: 0,
activeTime: 0,
totalLoadCount: 0,
currentLoad: 0,
currentMaterials: [],
distanceTraveled: 0
@@ -83,6 +95,39 @@ export const createHumanStore = () => {
});
},
setCurrentPhase: (modelUuid, phase) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentPhase = phase;
}
});
},
addCurrentAction: (modelUuid, actionUuid) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
const action = human.point.actions.find(h => h.actionUuid === actionUuid);
if (action) {
human.currentAction = {
actionUuid: action.actionUuid,
actionName: action.actionName
};
}
}
});
},
removeCurrentAction: (modelUuid) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.currentAction = undefined;
}
});
},
setHumanActive: (modelUuid, isActive) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
@@ -92,11 +137,11 @@ export const createHumanStore = () => {
});
},
setHumanPicking: (modelUuid, isPicking) => {
setHumanScheduled: (modelUuid, isScheduled) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.isPicking = isPicking;
human.isScheduled = isScheduled;
}
});
},
@@ -137,6 +182,33 @@ export const createHumanStore = () => {
});
},
incrementLoadCount: (modelUuid, incrementBy) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.totalLoadCount += incrementBy;
}
});
},
decrementLoadCount: (modelUuid, decrementBy) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.totalLoadCount -= decrementBy;
}
});
},
clearLoadCount: (modelUuid) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);
if (human) {
human.totalLoadCount = 0;
}
});
},
addCurrentMaterial: (modelUuid, materialType, materialId) => {
set((state) => {
const human = state.humans.find(h => h.modelUuid === modelUuid);

View File

@@ -36,6 +36,8 @@ type MaterialsStore = {
} | null
) => MaterialSchema | undefined;
clearLocations: (materialId: string) => void;
setMaterial: (materialId: string, materialType: string) => MaterialSchema | undefined;
setStartTime: (materialId: string, startTime: number) => MaterialSchema | undefined;
setEndTime: (materialId: string, endTime: number) => MaterialSchema | undefined;
@@ -140,6 +142,18 @@ export const createMaterialStore = () => {
return updatedMaterial;
},
clearLocations: (materialId) => {
let updatedMaterial: MaterialSchema | undefined;
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
if (material) {
delete material.previous;
delete material.next;
updatedMaterial = JSON.parse(JSON.stringify(material));
}
});
return updatedMaterial;
},
setMaterial: (materialId, materialType) => {
let updatedMaterial: MaterialSchema | undefined;
set((state) => {

View File

@@ -32,13 +32,13 @@ type ProductsStore = {
productUuid: string,
modelUuid: string,
pointUuid: string,
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']
action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]
) => EventsSchema | undefined;
removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined;
updateAction: (
productUuid: string,
actionUuid: string,
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']>
updates: Partial<ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]>
) => EventsSchema | undefined;
// Trigger-level actionss
@@ -66,8 +66,8 @@ type ProductsStore = {
getEventByTriggerUuid: (productUuid: string, triggerUuid: string) => EventsSchema | undefined;
getEventByPointUuid: (productUuid: string, pointUuid: string) => EventsSchema | undefined;
getPointByUuid: (productUuid: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema | undefined;
getActionByUuid: (productUuid: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']) | undefined;
getActionByPointUuid: (productUuid: string, pointUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']) | undefined;
getActionByUuid: (productUuid: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]) | undefined;
getActionByPointUuid: (productUuid: string, pointUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]) | undefined;
getModelUuidByPointUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
getModelUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;
getPointUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined;

View File

@@ -203,8 +203,8 @@ export const useSelectedAnimation = create<SelectedAnimationState>()(
);
interface IsDraggingState {
isDragging: "start" | "end" | null;
setIsDragging: (state: "start" | "end" | null) => void;
isDragging: "start" | "end" | "assembly" | null;
setIsDragging: (state: "start" | "end" | "assembly" | null) => void;
}
export const useIsDragging = create<IsDraggingState>()(
@@ -219,8 +219,8 @@ export const useIsDragging = create<IsDraggingState>()(
);
interface IsRotatingState {
isRotating: "start" | "end" | null;
setIsRotating: (state: "start" | "end" | null) => void;
isRotating: "start" | "end" | "assembly" | null;
setIsRotating: (state: "start" | "end" | "assembly" | null) => void;
}
export const useIsRotating = create<IsRotatingState>()(
@@ -276,4 +276,40 @@ export const useComparisonProduct = create<ComparisonProductState>()(
});
},
}))
);
interface SelectedPointsState {
selectedPoints: THREE.Object3D[];
setSelectedPoints: (points: THREE.Object3D[]) => void;
addSelectedPoint: (point: THREE.Object3D) => void;
removeSelectedPoint: (uuid: string) => void;
clearSelectedPoints: () => void;
}
export const useSelectedPoints = create<SelectedPointsState>()(
immer((set) => ({
selectedPoints: [],
setSelectedPoints: (points) => {
set((state) => {
state.selectedPoints = points;
});
},
addSelectedPoint: (point) => {
set((state) => {
if (!state.selectedPoints.find(p => p.uuid === point.uuid)) {
state.selectedPoints.push(point);
}
});
},
removeSelectedPoint: (uuid) => {
set((state) => {
state.selectedPoints = state.selectedPoints.filter(p => p.uuid !== uuid);
});
},
clearSelectedPoints: () => {
set((state) => {
state.selectedPoints = [];
});
},
}))
);

View File

@@ -10,6 +10,9 @@ interface VehiclesStore {
modelUuid: string,
updates: Partial<Omit<VehicleStatus, "modelUuid" | "productUuid">>
) => void;
addPathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], point: VehicleAction["paths"]["initPickup"][number]) => VehicleAction["paths"];
updatePathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], pointId: string, updates: Partial<VehicleAction["paths"]["initPickup"][number]>) => VehicleAction["paths"];
deletePathPoint: (modelUuid: string, pathKey: keyof VehicleAction["paths"], pointId: string) => VehicleAction["paths"];
clearVehicles: () => void;
setVehicleActive: (modelUuid: string, isActive: boolean) => void;
@@ -79,6 +82,48 @@ export const createVehicleStore = () => {
});
},
addPathPoint: (modelUuid, pathKey, point) => {
let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] };
set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
if (vehicle) {
const path = vehicle.point.action.paths[pathKey];
path.push(point);
updatedPaths = vehicle.point.action.paths;
}
});
return updatedPaths;
},
updatePathPoint: (modelUuid, pathKey, pointId, updates) => {
let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] };
set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
if (vehicle) {
const path = vehicle.point.action.paths[pathKey];
const index = path.findIndex(p => p.pointId === pointId);
if (index !== -1) {
Object.assign(path[index], updates);
updatedPaths = vehicle.point.action.paths;
}
}
});
return updatedPaths;
},
deletePathPoint: (modelUuid, pathKey, pointId) => {
let updatedPaths: VehicleAction["paths"] = { initPickup: [], pickupDrop: [], dropPickup: [] };
set((state) => {
const vehicle = state.vehicles.find(v => v.modelUuid === modelUuid);
if (vehicle) {
const path = vehicle.point.action.paths[pathKey];
vehicle.point.action.paths[pathKey] = path.filter(p => p.pointId !== pointId);
updatedPaths = vehicle.point.action.paths;
}
});
return updatedPaths;
},
clearVehicles: () => {
set((state) => {
state.vehicles = [];

View File

@@ -24,3 +24,30 @@ export const usePlayerStore = create<PlayerState>((set) => ({
hidePlayer: false, // initial state
setHidePlayer: (hide) => set({ hidePlayer: hide }), // state updater
}));
interface MouseNoteState {
Leftnote: string;
Middlenote: string;
Rightnote: string;
setNotes: (notes: {
Leftnote: string;
Middlenote: string;
Rightnote: string;
}) => void;
setLeftnote: (note: string) => void;
setMiddlenote: (note: string) => void;
setRightnote: (note: string) => void;
resetNotes: () => void;
}
export const useMouseNoteStore = create<MouseNoteState>((set) => ({
Leftnote: '',
Middlenote: '',
Rightnote: '',
setNotes: (notes) => set(notes),
setLeftnote: (note) => set({ Leftnote: note }),
setMiddlenote: (note) => set({ Middlenote: note }),
setRightnote: (note) => set({ Rightnote: note }),
resetNotes: () =>
set({ Leftnote: '', Middlenote: '', Rightnote: '' }),
}));

View File

@@ -45,4 +45,5 @@
//
@use "./scene/scene";
@use "./scene/comments";
@use "./scene/comments";
@use "./scene/cursors.scss";

View File

@@ -84,12 +84,6 @@
font-weight: var(--font-weight-medium);
background: var(--background-color-button);
svg {
path {
stroke: var(--background-color-selected);
}
}
&:hover {
background: var(--background-color-button);
}

View File

@@ -0,0 +1,60 @@
$cursor-default: url("../../assets/cursors/default.svg") 0 0, default;
$cursor-pen: url("../../assets/cursors/pen.svg") 0 0, default;
$cursor-delete: url("../../assets/cursors/pointing.svg") 4 0, default;
$cursor-comment: url("../../assets/cursors/comment.svg") 0 16, default;
$cursor-draw: url("../../assets/cursors/cell.svg") 8 8, default;
$cursor-cross: url("../../assets/cursors/cross.svg") 8 8, default;
$cursor-grab: url("../../assets/cursors/open.svg") 8 8, default;
$cursor-grabing: url("../../assets/cursors/close.svg") 8 8, default;
.scene-container {
canvas {
cursor: $cursor-default !important;
}
}
.scene-container.draw {
canvas {
cursor: $cursor-draw !important;
}
}
.scene-container.pointer {
canvas {
cursor: $cursor-delete !important;
}
}
.scene-container.pen {
canvas {
cursor: $cursor-pen !important;
}
}
.scene-container.measure {
canvas {
cursor: $cursor-cross !important;
}
}
.scene-container.hand {
canvas {
cursor: $cursor-grab !important;
&:active{
cursor: $cursor-grabing !important;
}
}
}
.scene-container.hand-closed {
canvas {
cursor: $cursor-grabing !important;
}
}
.scene-container.comment {
canvas {
cursor: $cursor-comment !important;
}
}

View File

@@ -40,6 +40,29 @@ interface VehicleAction {
steeringAngle: number;
pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
paths: {
initPickup: {
pointId: string;
position: [number, number, number];
isCurved: boolean;
handleA: [number, number, number] | null;
handleB: [number, number, number] | null;
}[],
pickupDrop: {
pointId: string;
position: [number, number, number];
isCurved: boolean;
handleA: [number, number, number] | null;
handleB: [number, number, number] | null;
}[],
dropPickup: {
pointId: string;
position: [number, number, number];
isCurved: boolean;
handleA: [number, number, number] | null;
handleB: [number, number, number] | null;
}[],
}
triggers: TriggerSchema[];
}
@@ -73,11 +96,12 @@ interface HumanAction {
actionUuid: string;
actionName: string;
actionType: "worker" | "assembly";
processTime?: number;
processTime: number;
swapMaterial?: string;
assemblyPoint?: { rotation: [number, number, number] | null; }
assemblyPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; }
pickUpPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; }
dropPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; }
loadCount: number;
loadCapacity: number;
triggers: TriggerSchema[];
}
@@ -124,7 +148,7 @@ interface HumanPointSchema {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
action: HumanAction;
actions: HumanAction[];
}
type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema;
@@ -223,19 +247,18 @@ interface StorageUnitStatus extends StorageEventSchema {
interface HumanStatus extends HumanEventSchema {
productUuid: string;
currentPhase: string;
isActive: boolean;
isPicking: boolean;
isScheduled: boolean;
idleTime: number;
activeTime: number;
totalLoadCount: number;
currentLoad: number;
currentMaterials: { materialType: string; materialId: string; }[];
distanceTraveled: number;
currentAction?: {
actionUuid: string;
actionName: string;
animationUuid: string;
materialType?: string | null;
materialId?: string | null;
};
}
@@ -302,7 +325,8 @@ type IK = {
target: number;
effector: number;
links: Link[];
ringRadius?: number;
minDistance?: number;
maxDistance?: number;
maxheight?: number;
minheight?: number;
} ;
};

View File

@@ -0,0 +1,37 @@
export const handleCanvasCursors = (name: string) => {
const canvas = document.getElementById('work-space-three-d-canvas');
if (!canvas) return;
const cursorMap: Record<string, string> = {
default: '',
'draw-wall': 'draw',
'draw-aisle': 'draw',
'draw-zone': 'draw',
'draw-floor': 'draw',
measure: 'measure',
delete: 'pointer',
pointer: 'pointer',
grab: 'hand',
grabbing: 'hand-closed',
pen: 'pen',
'free-hand': 'hand',
move: 'move',
comment: 'comment',
// Add more mappings as needed
};
const validCursorClasses = new Set(Object.values(cursorMap));
// Remove previously applied cursor-related classes
canvas.classList.forEach((cls) => {
if (validCursorClasses.has(cls)) {
canvas.classList.remove(cls);
}
});
// Add the new cursor class
const newCursorClass = cursorMap[name];
if (newCursorClass) {
canvas.classList.add(newCursorClass);
}
};

View File

@@ -0,0 +1,45 @@
import { useMouseNoteStore } from "../../store/useUIToggleStore";
const actionNotes: Record<string, string> = {
'left+CONTROL': 'Box Select',
'left+SHIFT': 'Multi Select',
'middle+CONTROL': 'Zoom In',
};
export function mouseActionHelper() {
const setNotes = useMouseNoteStore.getState().setNotes;
const activeKeys = new Set<string>();
function updateNotesFromKeys() {
const sortedKeys = Array.from(activeKeys).sort();
const leftKey = ['left', ...sortedKeys].join('+');
const middleKey = ['middle', ...sortedKeys].join('+');
const rightKey = ['right', ...sortedKeys].join('+');
setNotes({
Leftnote: actionNotes[leftKey] || '',
Middlenote: actionNotes[middleKey] || '',
Rightnote: actionNotes[rightKey] || '',
});
}
function handleKeyDown(event: KeyboardEvent) {
activeKeys.add(event.key.toUpperCase());
updateNotesFromKeys();
}
function handleKeyUp(event: KeyboardEvent) {
activeKeys.delete(event.key.toUpperCase());
updateNotesFromKeys();
}
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
return () => {
window.removeEventListener('keydown', handleKeyDown);
window.removeEventListener('keyup', handleKeyUp);
};
}

View File

@@ -53,7 +53,7 @@ const KeyPressListener: React.FC = () => {
const { setCreateNewVersion } = useVersionHistoryStore();
const { setVersionHistoryVisible } = useVersionHistoryVisibleStore();
const { setSelectedComment } = useSelectedComment();
const { setDfxUploaded, setDxfWallGenerate } = useDfxUpload();
const { setDfxUploaded } = useDfxUpload();
const isTextInput = (element: Element | null): boolean =>
element instanceof HTMLInputElement ||
element instanceof HTMLTextAreaElement ||
@@ -128,6 +128,9 @@ const KeyPressListener: React.FC = () => {
setActiveTool("measure");
setToolMode("MeasurementScale");
}
if (key === "C") {
setActiveTool("comment");
}
};
const handleSidebarShortcuts = (key: string) => {