From 7fff074a5c9abd0a679850fdbc237c88a04a2443 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Fri, 24 Oct 2025 22:59:30 -0700 Subject: [PATCH 01/14] created project file --- .gitattributes | 33 +++++++++++++++ .gitignore | 40 +++++++++++++++++++ REGION_TYPE.m => geometries/REGION_TYPE.m | 0 .../rectangularPrismConstraint.m | 0 miSim.prj | 2 + .../HYICfq4P1rcDM3M3ck-Bdx9axZ8d.xml | 2 + .../HYICfq4P1rcDM3M3ck-Bdx9axZ8p.xml | 2 + .../LBBP3VzTDNqtmQGoBzn8TyGr_JYd.xml | 2 + .../LBBP3VzTDNqtmQGoBzn8TyGr_JYp.xml | 2 + .../bC9JguT7xdg6hTVY9GqmttWOU6Ud.xml | 2 + .../bC9JguT7xdg6hTVY9GqmttWOU6Up.xml | 2 + .../2C0ooPmXaSISA_J0x7PMu2uZ660d.xml | 2 + .../2C0ooPmXaSISA_J0x7PMu2uZ660p.xml | 2 + .../ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml | 6 +++ .../ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml | 2 + .../dcQXSYjif37BKJ8bynJny6jq5-sd.xml | 6 +++ .../dcQXSYjif37BKJ8bynJny6jq5-sp.xml | 2 + .../oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml | 6 +++ .../oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml | 2 + .../aUjk9RtIbQ9S9PboEHDBe8PRzPId.xml | 6 +++ .../aUjk9RtIbQ9S9PboEHDBe8PRzPIp.xml | 2 + .../ia5FvKngd_-0tJFYAO64kIgybSkd.xml | 6 +++ .../ia5FvKngd_-0tJFYAO64kIgybSkp.xml | 2 + .../p3X7RLZlL9TzzpK7fJIwY38rB_Yd.xml | 2 + .../p3X7RLZlL9TzzpK7fJIwY38rB_Yp.xml | 2 + .../2kj09UetkV_lru3gvSPXnY6-nM4d.xml | 2 + .../2kj09UetkV_lru3gvSPXnY6-nM4p.xml | 2 + .../KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml | 2 + .../KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml | 2 + .../QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml | 2 + .../QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml | 2 + .../R1RggVhA72agIvELiuhWPRS8F0Id.xml | 2 + .../R1RggVhA72agIvELiuhWPRS8F0Ip.xml | 2 + .../aEHSZBIY-yve10yGis12Zr5DLZod.xml | 2 + .../aEHSZBIY-yve10yGis12Zr5DLZop.xml | 2 + .../j4xwF_j8iFTVayUMfxLgMnTbencd.xml | 2 + .../j4xwF_j8iFTVayUMfxLgMnTbencp.xml | 2 + .../r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml | 2 + .../r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml | 2 + resources/project/Project.xml | 2 + .../NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml | 2 + .../NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml | 2 + .../DnSrh-_-SnAVM_QmOB_8JskdVJUd.xml | 6 +++ .../DnSrh-_-SnAVM_QmOB_8JskdVJUp.xml | 2 + .../IkPyncn3ZGRxjBV47QmicBzm2kUd.xml | 6 +++ .../IkPyncn3ZGRxjBV47QmicBzm2kUp.xml | 2 + .../M3axfhPiVFfHfWnq8PF7Q8OtKAUd.xml | 2 + .../M3axfhPiVFfHfWnq8PF7Q8OtKAUp.xml | 2 + .../NRbCR7m2f1_2pHz6LyHrTz7eFpcd.xml | 2 + .../NRbCR7m2f1_2pHz6LyHrTz7eFpcp.xml | 2 + .../NSdjf1q7sJuLYHZ864kCIhygPfId.xml | 6 +++ .../NSdjf1q7sJuLYHZ864kCIhygPfIp.xml | 2 + .../QMJD9OLFzxcTTbPOoh-ahQ4zTRUd.xml | 2 + .../QMJD9OLFzxcTTbPOoh-ahQ4zTRUp.xml | 2 + .../TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml | 2 + .../TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml | 2 + .../qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml | 2 + .../qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml | 2 + .../raP7OV2lamoMNbKeDBUa13s5Imwd.xml | 6 +++ .../raP7OV2lamoMNbKeDBUa13s5Imwp.xml | 2 + .../u_8f8riMl9bapFIdVg6GQo796t8d.xml | 6 +++ .../u_8f8riMl9bapFIdVg6GQo796t8p.xml | 2 + .../wdgofbR4UWdlJ0HwKeczjlphIxQd.xml | 6 +++ .../wdgofbR4UWdlJ0HwKeczjlphIxQp.xml | 2 + .../root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml | 2 + .../root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml | 2 + .../root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml | 2 + .../root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml | 2 + .../root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml | 2 + resources/project/rootp.xml | 2 + startup.m | 2 +- 71 files changed, 250 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 .gitignore rename REGION_TYPE.m => geometries/REGION_TYPE.m (100%) rename rectangularPrismConstraint.m => geometries/rectangularPrismConstraint.m (100%) create mode 100644 miSim.prj create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8d.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8p.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYd.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYp.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Ud.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Up.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660d.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660p.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sd.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml create mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPId.xml create mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPIp.xml create mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkd.xml create mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml create mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yd.xml create mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yp.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml create mode 100644 resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml create mode 100644 resources/project/Project.xml create mode 100644 resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml create mode 100644 resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfId.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfIp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8d.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8p.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQp.xml create mode 100644 resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml create mode 100644 resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml create mode 100644 resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml create mode 100644 resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml create mode 100644 resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml create mode 100644 resources/project/rootp.xml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7815091 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,33 @@ +* text=auto + +*.fig binary +*.mat binary +*.mdl binary diff merge=mlAutoMerge +*.mdlp binary +*.mex* binary +*.mlapp binary +*.mldatx binary merge=mlAutoMerge +*.mlproj binary +*.mlx binary +*.p binary +*.plprj binary +*.sbproj binary +*.sfx binary +*.sldd binary +*.slreqx binary merge=mlAutoMerge +*.slmx binary merge=mlAutoMerge +*.sltx binary +*.slxc binary +*.slx binary merge=mlAutoMerge +*.slxp binary + +## MATLAB Project metadata files use LF line endings +/resources/project/**/*.xml text eol=lf + +## Other common binary file types +*.docx binary +*.exe binary +*.jpg binary +*.pdf binary +*.png binary +*.xlsx binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aac549e --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Autosave files +*.asv +*.m~ +*.autosave +*.slx.r* +*.mdl.r* + +# Derived content-obscured files +*.p + +# Compiled MEX files +*.mex* + +# Packaged app and toolbox files +*.mlappinstall +*.mltbx + +# Deployable archives +*.ctf + +# Generated helpsearch folders +helpsearch*/ + +# Code generation folders +slprj/ +sccprj/ +codegen/ + +# Cache files +*.slxc + +# Cloud based storage dotfile +.MATLABDriveTag + +# buildtool cache folder +.buildtool/ + +# SimBiology backup files +*.sbproj.backup +*.sbproj.bak diff --git a/REGION_TYPE.m b/geometries/REGION_TYPE.m similarity index 100% rename from REGION_TYPE.m rename to geometries/REGION_TYPE.m diff --git a/rectangularPrismConstraint.m b/geometries/rectangularPrismConstraint.m similarity index 100% rename from rectangularPrismConstraint.m rename to geometries/rectangularPrismConstraint.m diff --git a/miSim.prj b/miSim.prj new file mode 100644 index 0000000..6b95f98 --- /dev/null +++ b/miSim.prj @@ -0,0 +1,2 @@ + + diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8d.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8d.xml new file mode 100644 index 0000000..077e35c --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8p.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8p.xml new file mode 100644 index 0000000..5efa405 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/HYICfq4P1rcDM3M3ck-Bdx9axZ8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYd.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYd.xml new file mode 100644 index 0000000..cdddfcf --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYp.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYp.xml new file mode 100644 index 0000000..30220df --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/LBBP3VzTDNqtmQGoBzn8TyGr_JYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Ud.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Ud.xml new file mode 100644 index 0000000..d28e2cf --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Ud.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Up.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Up.xml new file mode 100644 index 0000000..8a52762 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/bC9JguT7xdg6hTVY9GqmttWOU6Up.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660d.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660d.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660p.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660p.xml new file mode 100644 index 0000000..01cb34e --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/2C0ooPmXaSISA_J0x7PMu2uZ660p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml new file mode 100644 index 0000000..8e00d26 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sd.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml new file mode 100644 index 0000000..6e6097c --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml new file mode 100644 index 0000000..aa77220 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPId.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPId.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPId.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPIp.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPIp.xml new file mode 100644 index 0000000..a0bd1eb --- /dev/null +++ b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/aUjk9RtIbQ9S9PboEHDBe8PRzPIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkd.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml new file mode 100644 index 0000000..fd48245 --- /dev/null +++ b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yd.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yp.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yp.xml new file mode 100644 index 0000000..01cb34e --- /dev/null +++ b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/p3X7RLZlL9TzzpK7fJIwY38rB_Yp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml new file mode 100644 index 0000000..6d1c43c --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml new file mode 100644 index 0000000..e993c77 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml new file mode 100644 index 0000000..d47011f --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml new file mode 100644 index 0000000..91b0acc --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml new file mode 100644 index 0000000..6c16a34 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml new file mode 100644 index 0000000..76301e1 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml new file mode 100644 index 0000000..e228479 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml new file mode 100644 index 0000000..958c22f --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml new file mode 100644 index 0000000..b5689bd --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml new file mode 100644 index 0000000..ffb1fe8 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml new file mode 100644 index 0000000..646977e --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml new file mode 100644 index 0000000..2e052d9 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml new file mode 100644 index 0000000..c67e567 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml new file mode 100644 index 0000000..880a245 --- /dev/null +++ b/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/Project.xml b/resources/project/Project.xml new file mode 100644 index 0000000..62d05aa --- /dev/null +++ b/resources/project/Project.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml b/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml new file mode 100644 index 0000000..5de8c3e --- /dev/null +++ b/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml b/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml new file mode 100644 index 0000000..642c7d7 --- /dev/null +++ b/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUp.xml new file mode 100644 index 0000000..0ccb9dd --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/DnSrh-_-SnAVM_QmOB_8JskdVJUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUp.xml new file mode 100644 index 0000000..48d3403 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/IkPyncn3ZGRxjBV47QmicBzm2kUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUp.xml new file mode 100644 index 0000000..38ee02e --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/M3axfhPiVFfHfWnq8PF7Q8OtKAUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcp.xml new file mode 100644 index 0000000..664f3b3 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NRbCR7m2f1_2pHz6LyHrTz7eFpcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfId.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfId.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfId.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfIp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfIp.xml new file mode 100644 index 0000000..bd593f9 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/NSdjf1q7sJuLYHZ864kCIhygPfIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUp.xml new file mode 100644 index 0000000..4137335 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/QMJD9OLFzxcTTbPOoh-ahQ4zTRUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml new file mode 100644 index 0000000..77329db --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml new file mode 100644 index 0000000..603491d --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwp.xml new file mode 100644 index 0000000..08dc73d --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/raP7OV2lamoMNbKeDBUa13s5Imwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8d.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8d.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8p.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8p.xml new file mode 100644 index 0000000..e3931ee --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/u_8f8riMl9bapFIdVg6GQo796t8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQp.xml new file mode 100644 index 0000000..9ac5710 --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/wdgofbR4UWdlJ0HwKeczjlphIxQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml b/resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml new file mode 100644 index 0000000..fee2cd2 --- /dev/null +++ b/resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml b/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml new file mode 100644 index 0000000..10bfde4 --- /dev/null +++ b/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml b/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml new file mode 100644 index 0000000..2037c33 --- /dev/null +++ b/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml b/resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml new file mode 100644 index 0000000..a4de013 --- /dev/null +++ b/resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml b/resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml new file mode 100644 index 0000000..8b0d336 --- /dev/null +++ b/resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/rootp.xml b/resources/project/rootp.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/rootp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/startup.m b/startup.m index 12d0f9e..2a3c68e 100644 --- a/startup.m +++ b/startup.m @@ -1 +1 @@ -addpath("validators"); \ No newline at end of file +open("miSim.prj"); \ No newline at end of file From da3f73225030b0e09a233feaf56d20bc0f2796de Mon Sep 17 00:00:00 2001 From: Kevin D Date: Sat, 25 Oct 2025 18:22:06 -0700 Subject: [PATCH 02/14] refined domain and obstacle generation --- test_miSim.m | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test_miSim.m b/test_miSim.m index 9edb27d..7b69d1b 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -31,7 +31,8 @@ classdef test_miSim < matlab.unittest.TestCase % Generate a random domain function tc = setDomain(tc) % random integer-sized domain within [-10, 10] in all dimensions - tc.domain = tc.domain.initialize(ceil([rand * -10, rand * 10; rand * -10, rand * 10; rand * -10, rand * 10]), REGION_TYPE.DOMAIN, "Domain"); + L = ceil(5 + rand * 10 + rand * 10); + tc.domain = tc.domain.initialize(([0, L; 0, L; 0, L]), REGION_TYPE.DOMAIN, "Domain"); end % Generate a random sensing objective within that domain function tc = setSensingObjective(tc) @@ -74,8 +75,8 @@ classdef test_miSim < matlab.unittest.TestCase while any(candidateMinCorner(1:2, 1) < tc.domain.minCorner(1:2, 1)) candidateMinCorner = tc.domain.minCorner(1:3, 1) + [(tc.domain.maxCorner(1:2, 1) - tc.domain.minCorner(1:2, 1)) .* rand(2, 1); -Inf]; % random spots on the ground end - while any(candidateMaxCorner(1:2, 1) > tc.domain.maxCorner(1:2, 1)) - candidateMaxCorner = [candidateMinCorner(1:2, 1); 0] + [(tc.domain.maxCorner(1:2, 1) - tc.domain.minCorner(1:2, 1)) .* rand(2, 1) ./ 2; Inf]; % halved to keep from being excessively large + while any(candidateMaxCorner(1:3, 1) > tc.domain.maxCorner(1:3, 1)) + candidateMaxCorner = [candidateMinCorner(1:2, 1); 0] + ((tc.domain.maxCorner(1:3, 1) - tc.domain.minCorner(1:3, 1)) .* rand(3, 1) ./ 2); % halved to keep from being excessively large end % once a domain-valid obstacle has been found, make From c61d627f0d181615817648417565e932884b1db2 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Sat, 25 Oct 2025 23:41:12 -0700 Subject: [PATCH 03/14] stopped randomly placing agents too close to objective, fixed row/col preference --- geometries/rectangularPrismConstraint.m | 38 ++++++------- sensingObjective.m | 10 ++-- test_miSim.m | 73 ++++++++++++++++--------- 3 files changed, 70 insertions(+), 51 deletions(-) diff --git a/geometries/rectangularPrismConstraint.m b/geometries/rectangularPrismConstraint.m index ca00c26..d8f3bb4 100644 --- a/geometries/rectangularPrismConstraint.m +++ b/geometries/rectangularPrismConstraint.m @@ -4,23 +4,23 @@ classdef rectangularPrismConstraint tag = REGION_TYPE.INVALID; label = ""; - minCorner = NaN(3, 1); - maxCorner = NaN(3, 1); + minCorner = NaN(1, 3); + maxCorner = NaN(1, 3); - dimensions = NaN(3, 1); + dimensions = NaN(1, 3); center = NaN; vertices = NaN(8, 3); - footprint = NaN(2, 4); + footprint = NaN(4, 2); end methods (Access = public) function obj = initialize(obj, bounds, tag, label) arguments (Input) obj (1, 1) {mustBeA(obj, 'rectangularPrismConstraint')}; - bounds (3, 2) double; + bounds (2, 3) double; tag (1, 1) REGION_TYPE = REGION_TYPE.INVALID; label (1, 1) string = ""; end @@ -32,8 +32,8 @@ classdef rectangularPrismConstraint obj.label = label; %% Define geometry bounds by LL corner and UR corner - obj.minCorner = bounds(:, 1); - obj.maxCorner = bounds(:, 2); + obj.minCorner = bounds(1, 1:3); + obj.maxCorner = bounds(2, 1:3); % Compute L, W, H obj.dimensions = [obj.maxCorner(1) - obj.minCorner(1), obj.maxCorner(2) - obj.minCorner(2), obj.maxCorner(3) - obj.minCorner(3)]; @@ -42,20 +42,20 @@ classdef rectangularPrismConstraint obj.center = obj.minCorner + obj.dimensions ./ 2; % Compute vertices - obj.vertices = [obj.minCorner'; - obj.maxCorner(1), obj.minCorner(2:3)'; - obj.maxCorner(1:2)', obj.minCorner(3); + obj.vertices = [obj.minCorner; + obj.maxCorner(1), obj.minCorner(2:3); + obj.maxCorner(1:2), obj.minCorner(3); obj.minCorner(1), obj.maxCorner(2), obj.minCorner(3); - obj.minCorner(1:2)', obj.maxCorner(3); + obj.minCorner(1:2), obj.maxCorner(3); obj.maxCorner(1), obj.minCorner(2), obj.maxCorner(3); - obj.minCorner(1), obj.maxCorner(2:3)' - obj.maxCorner';]; + obj.minCorner(1), obj.maxCorner(2:3) + obj.maxCorner;]; % Compute footprint - obj.footprint = [obj.minCorner(1:2, 1), ... - [obj.minCorner(1, 1); obj.maxCorner(2, 1)], ... - [obj.maxCorner(1, 1); obj.minCorner(2, 1)], ... - obj.maxCorner(1:2, 1)]; + obj.footprint = [obj.minCorner(1:2); ... + [obj.minCorner(1), obj.maxCorner(2)]; ... + [obj.maxCorner(1), obj.minCorner(2)]; ... + obj.maxCorner(1:2)]; end function r = random(obj) arguments (Input) @@ -72,9 +72,9 @@ classdef rectangularPrismConstraint pos (:, 3) double; end arguments (Output) - c (1, 1) logical + c (:, 1) logical end - c = all(pos >= repmat(obj.minCorner', size(pos, 1), 1), 2) & all(pos <= repmat(obj.maxCorner', size(pos, 1), 1), 2); + c = all(pos >= repmat(obj.minCorner, size(pos, 2), 1), 2) & all(pos <= repmat(obj.maxCorner, size(pos, 2), 1), 2); end function f = plotWireframe(obj, f) arguments (Input) diff --git a/sensingObjective.m b/sensingObjective.m index a00e7d7..293f624 100644 --- a/sensingObjective.m +++ b/sensingObjective.m @@ -16,7 +16,7 @@ classdef sensingObjective arguments (Input) obj (1,1) {mustBeA(obj, 'sensingObjective')}; objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')}; - footprint (2, :) double; + footprint (:, 2) double; groundAlt (1, 1) double = 0; discretizationStep (1, 1) double = 1; end @@ -27,10 +27,10 @@ classdef sensingObjective obj.groundAlt = groundAlt; % Extract footprint limits - xMin = min(footprint(1, :)); - xMax = max(footprint(1, :)); - yMin = min(footprint(2, :)); - yMax = max(footprint(2, :)); + xMin = min(footprint(:, 1)); + xMax = max(footprint(:, 1)); + yMin = min(footprint(:, 2)); + yMax = max(footprint(:, 2)); xGrid = unique([xMin:discretizationStep:xMax, xMax]); yGrid = unique([yMin:discretizationStep:yMax, yMax]); diff --git a/test_miSim.m b/test_miSim.m index 7b69d1b..1a5872e 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -6,6 +6,7 @@ classdef test_miSim < matlab.unittest.TestCase % Obstacles constraintGeometries = cell(1, 0); + minObstacleDimension = 1; % Objective objective = sensingObjective; @@ -32,14 +33,14 @@ classdef test_miSim < matlab.unittest.TestCase function tc = setDomain(tc) % random integer-sized domain within [-10, 10] in all dimensions L = ceil(5 + rand * 10 + rand * 10); - tc.domain = tc.domain.initialize(([0, L; 0, L; 0, L]), REGION_TYPE.DOMAIN, "Domain"); + tc.domain = tc.domain.initialize([zeros(1, 3); L * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain"); end % Generate a random sensing objective within that domain function tc = setSensingObjective(tc) mu = tc.domain.random(); sig = [3, 1; 1, 4]; tc.objectiveFunction = @(x, y) mvnpdf([x(:), y(:)], mu(1, 1:2), sig); - tc.objective = tc.objective.initialize(tc.objectiveFunction, tc.domain.footprint, tc.domain.minCorner(3, 1), tc.objectiveDiscretizationStep); + tc.objective = tc.objective.initialize(tc.objectiveFunction, tc.domain.footprint, tc.domain.minCorner(3), tc.objectiveDiscretizationStep); end % Instantiate agents, they will be initialized under different % parameters in individual test cases @@ -64,29 +65,39 @@ classdef test_miSim < matlab.unittest.TestCase % Randomly come up with constraint geometries until they % fit within the domain - candidateMinCorner = -Inf(3, 1); - candidateMaxCorner = Inf(3, 1); + candidateMinCorner = [-Inf(1, 2), 0]; + candidateMaxCorner = Inf(1, 3); - % make sure the obstacles don't contain the sensing objective - obstructs = true; - while obstructs - - % Make sure the obstacle is in the domain - while any(candidateMinCorner(1:2, 1) < tc.domain.minCorner(1:2, 1)) - candidateMinCorner = tc.domain.minCorner(1:3, 1) + [(tc.domain.maxCorner(1:2, 1) - tc.domain.minCorner(1:2, 1)) .* rand(2, 1); -Inf]; % random spots on the ground + % make sure obstacles are not too small in any dimension + tooSmall = true; + while tooSmall + % make sure the obstacles don't contain the sensing objective + obstructs = true; + while obstructs + + % Make sure the obstacle is in the domain + while any(candidateMinCorner < tc.domain.minCorner) + candidateMinCorner = tc.domain.minCorner(1:3) + [(tc.domain.maxCorner(1:2) - tc.domain.minCorner(1:2)) .* rand(1, 2), 0]; % random spots on the ground + end + while any(candidateMaxCorner > tc.domain.maxCorner) + candidateMaxCorner = [candidateMinCorner(1:2), 0] + ((tc.domain.maxCorner(1:3) - tc.domain.minCorner(1:3)) .* rand(1, 3) ./ 2); % halved to keep from being excessively large + end + + % once a domain-valid obstacle has been found, make + % sure it doesn't obstruct the sensing target + if all(candidateMinCorner(1:2) <= tc.objective.groundPos) && all(candidateMaxCorner(1:2) >= tc.objective.groundPos) + % reset to try again + candidateMinCorner = [-Inf(1, 2), 0]; + candidateMaxCorner = Inf(1, 3); + else + obstructs = false; + end end - while any(candidateMaxCorner(1:3, 1) > tc.domain.maxCorner(1:3, 1)) - candidateMaxCorner = [candidateMinCorner(1:2, 1); 0] + ((tc.domain.maxCorner(1:3, 1) - tc.domain.minCorner(1:3, 1)) .* rand(3, 1) ./ 2); % halved to keep from being excessively large - end - - % once a domain-valid obstacle has been found, make - % sure it doesn't obstruct the sensing target - if all(candidateMinCorner(1:2, 1)' <= tc.objective.groundPos) && all(candidateMaxCorner(1:2, 1)' >= tc.objective.groundPos) - % reset to try again - candidateMinCorner = -Inf(3, 1); - candidateMaxCorner = Inf(3, 1); + if min(candidateMaxCorner - candidateMinCorner) >= tc.minObstacleDimension + tooSmall = false; else - obstructs = false; + candidateMinCorner = [-Inf(1, 2), 0]; + candidateMaxCorner = Inf(1, 3); end end @@ -95,7 +106,7 @@ classdef test_miSim < matlab.unittest.TestCase candidateMaxCorner(isinf(candidateMaxCorner)) = tc.domain.maxCorner(isinf(candidateMaxCorner)); % Initialize constraint geometry - tc.constraintGeometries{ii, 1} = tc.constraintGeometries{ii, 1}.initialize([candidateMinCorner, candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); + tc.constraintGeometries{ii} = tc.constraintGeometries{ii}.initialize([candidateMinCorner; candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); end % Repeat this until a connected set of agent initial conditions @@ -106,10 +117,18 @@ classdef test_miSim < matlab.unittest.TestCase for ii = 1:size(tc.agents, 1) posInvalid = true; while posInvalid - % Initialize the agent into a random spot in the domain - candidatePos = tc.domain.random(); + % Initialize the agent into a random spot in the + % domain (that is not too close to the sensing + % objective) + boringInit = true; + while boringInit + candidatePos = tc.domain.random(); + if norm(candidatePos(1:2) - tc.objective.groundPos) >= norm(tc.domain.footprint(4, :) - tc.domain.footprint(1, :))/2 + boringInit = false; + end + end candidateGeometry = rectangularPrismConstraint; - tc.agents{ii, 1} = tc.agents{ii, 1}.initialize(candidatePos, zeros(1, 3), eye(3), candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii, 1) * ones(1, 3); candidatePos + tc.collisionRanges(ii, 1) * ones(1, 3)]', REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), ii, sprintf("Agent %d", ii)); + tc.agents{ii} = tc.agents{ii}.initialize(candidatePos, zeros(1, 3), eye(3), candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), ii, sprintf("Agent %d", ii)); % Check obstacles to confirm that none are violated for jj = 1:size(tc.constraintGeometries, 1) @@ -128,7 +147,7 @@ classdef test_miSim < matlab.unittest.TestCase % Create a collision geometry for this agent candidateGeometry = rectangularPrismConstraint; - candidateGeometry = candidateGeometry.initialize([tc.agents{ii, 1}.pos - 0.1 * ones(1, 3); tc.agents{ii, 1}.pos + 0.1 * ones(1, 3)]', REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)); + candidateGeometry = candidateGeometry.initialize([tc.agents{ii}.pos - 0.1 * ones(1, 3); tc.agents{ii}.pos + 0.1 * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)); % Check previously placed agents for collisions for jj = 1:(ii - 1) From 5a9ac0c2d5ed099441b666e7004d83146ade0a1d Mon Sep 17 00:00:00 2001 From: Kevin D Date: Sun, 26 Oct 2025 13:30:09 -0700 Subject: [PATCH 04/14] protected objective from domain edges --- agent.m | 2 +- ...arPrismConstraint.m => rectangularPrism.m} | 54 ++++++++++++++--- miSim.m | 14 ++--- .../dcQXSYjif37BKJ8bynJny6jq5-sp.xml | 2 - ...d.xml => oA3NoVC5FBKXh-LtCKBuVxHDs28d.xml} | 0 .../oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml | 2 + ...d.xml => NmnqsjHeF9rAhG9A30BKV_vI7tId.xml} | 0 .../NmnqsjHeF9rAhG9A30BKV_vI7tIp.xml | 2 + .../ia5FvKngd_-0tJFYAO64kIgybSkp.xml | 2 - test_miSim.m | 60 +++++++++++-------- validators/mustBeConstraintGeometries.m | 10 ---- validators/mustBeGeometry.m | 10 ++++ 12 files changed, 102 insertions(+), 56 deletions(-) rename geometries/{rectangularPrismConstraint.m => rectangularPrism.m} (64%) delete mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml rename resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/{dcQXSYjif37BKJ8bynJny6jq5-sd.xml => oA3NoVC5FBKXh-LtCKBuVxHDs28d.xml} (100%) create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml rename resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/{ia5FvKngd_-0tJFYAO64kIgybSkd.xml => NmnqsjHeF9rAhG9A30BKV_vI7tId.xml} (100%) create mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/NmnqsjHeF9rAhG9A30BKV_vI7tIp.xml delete mode 100644 resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml delete mode 100644 validators/mustBeConstraintGeometries.m create mode 100644 validators/mustBeGeometry.m diff --git a/agent.m b/agent.m index 1cb27b7..1f338af 100644 --- a/agent.m +++ b/agent.m @@ -23,7 +23,7 @@ classdef agent pos (1, 3) double; vel (1, 3) double; cBfromC (3, 3) double {mustBeDcm}; - collisionGeometry (1, 1) {mustBeConstraintGeometries}; + collisionGeometry (1, 1) {mustBeGeometry}; index (1, 1) double = NaN; label (1, 1) string = ""; end diff --git a/geometries/rectangularPrismConstraint.m b/geometries/rectangularPrism.m similarity index 64% rename from geometries/rectangularPrismConstraint.m rename to geometries/rectangularPrism.m index d8f3bb4..c2b37a9 100644 --- a/geometries/rectangularPrismConstraint.m +++ b/geometries/rectangularPrism.m @@ -1,5 +1,5 @@ -classdef rectangularPrismConstraint - % Rectangular prism constraint geometry +classdef rectangularPrism + % Rectangular prism geometry properties (SetAccess = private, GetAccess = public) tag = REGION_TYPE.INVALID; label = ""; @@ -19,13 +19,13 @@ classdef rectangularPrismConstraint methods (Access = public) function obj = initialize(obj, bounds, tag, label) arguments (Input) - obj (1, 1) {mustBeA(obj, 'rectangularPrismConstraint')}; + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; bounds (2, 3) double; tag (1, 1) REGION_TYPE = REGION_TYPE.INVALID; label (1, 1) string = ""; end arguments (Output) - obj (1, 1) {mustBeA(obj, 'rectangularPrismConstraint')}; + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; end obj.tag = tag; @@ -59,26 +59,62 @@ classdef rectangularPrismConstraint end function r = random(obj) arguments (Input) - obj (1, 1) {mustBeA(obj, 'rectangularPrismConstraint')}; + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; end arguments (Output) r (1, 3) double end r = (obj.vertices(1, 1:3) + rand(1, 3) .* obj.vertices(8, 1:3) - obj.vertices(1, 1:3))'; end + function d = distance(obj, pos) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; + pos (:, 3) double; + end + arguments (Output) + d (:, 1) double + end + cPos = NaN(1, 3); + for ii = 1:3 + if pos(ii) < obj.minCorner(ii) + cPos(ii) = obj.minCorner(ii); + elseif pos(ii) > obj.maxCorner(ii) + cPos(ii) = obj.maxCorner(ii); + else + cPos(ii) = pos(ii); + end + end + d = norm(cPos - pos); + end + function d = interiorDistance(obj, pos) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; + pos (:, 3) double; + end + arguments (Output) + d (:, 1) double + end + % find minimum distance to any face + d = min([pos(1) - obj.minCorner(1), ... + pos(2) - obj.minCorner(2), ... + pos(3) - obj.minCorner(3), ... + obj.maxCorner(1) - pos(1), ... + obj.maxCorner(2) - pos(2), ... + obj.maxCorner(3) - pos(3)]); + end function c = contains(obj, pos) arguments (Input) - obj (1, 1) {mustBeA(obj, 'rectangularPrismConstraint')}; + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; pos (:, 3) double; end arguments (Output) c (:, 1) logical end - c = all(pos >= repmat(obj.minCorner, size(pos, 2), 1), 2) & all(pos <= repmat(obj.maxCorner, size(pos, 2), 1), 2); + c = all(pos >= repmat(obj.minCorner, size(pos, 1), 1), 2) & all(pos <= repmat(obj.maxCorner, size(pos, 1), 1), 2); end function f = plotWireframe(obj, f) arguments (Input) - obj (1, 1) {mustBeA(obj, 'rectangularPrismConstraint')}; + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; end arguments (Output) @@ -97,7 +133,7 @@ classdef rectangularPrismConstraint Y = [obj.vertices(edges(:,1),2), obj.vertices(edges(:,2),2)]'; Z = [obj.vertices(edges(:,1),3), obj.vertices(edges(:,2),3)]'; - % Plot the boundaries of the constraint geometry + % Plot the boundaries of the geometry hold(f.CurrentAxes, "on"); plot3(X, Y, Z, '-', 'Color', obj.tag.color, 'LineWidth', 2); hold(f.CurrentAxes, "off"); diff --git a/miSim.m b/miSim.m index 9edb5c5..908f33f 100644 --- a/miSim.m +++ b/miSim.m @@ -3,20 +3,20 @@ classdef miSim % Simulation parameters properties (SetAccess = private, GetAccess = public) - domain = rectangularPrismConstraint; + domain = rectangularPrism; objective = sensingObjective; - constraintGeometries = cell(0, 1); % geometries that define constraints within the domain + obstacles = cell(0, 1); % geometries that define obstacles within the domain agents = cell(0, 1); % agents that move within the domain end methods (Access = public) - function obj = initialize(obj, domain, objective, agents, constraintGeometries) + function obj = initialize(obj, domain, objective, agents, obstacles) arguments (Input) obj (1, 1) {mustBeA(obj, 'miSim')}; - domain (1, 1) {mustBeConstraintGeometries}; + domain (1, 1) {mustBeGeometry}; objective (1, 1) {mustBeA(objective, 'sensingObjective')}; agents (:, 1) cell {mustBeAgents}; - constraintGeometries (:, 1) cell {mustBeConstraintGeometries} = cell(0, 1); + obstacles (:, 1) cell {mustBeGeometry} = cell(0, 1); end arguments (Output) obj (1, 1) {mustBeA(obj, 'miSim')}; @@ -25,8 +25,8 @@ classdef miSim %% Define domain obj.domain = domain; - %% Add constraint geometries against the domain - obj.constraintGeometries = constraintGeometries; + %% Add geometries representing obstacles within the domain + obj.obstacles = obstacles; %% Define objective obj.objective = objective; diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml deleted file mode 100644 index 6e6097c..0000000 --- a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sp.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sd.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28d.xml similarity index 100% rename from resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/dcQXSYjif37BKJ8bynJny6jq5-sd.xml rename to resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28d.xml diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml new file mode 100644 index 0000000..60b28f2 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkd.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/NmnqsjHeF9rAhG9A30BKV_vI7tId.xml similarity index 100% rename from resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkd.xml rename to resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/NmnqsjHeF9rAhG9A30BKV_vI7tId.xml diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/NmnqsjHeF9rAhG9A30BKV_vI7tIp.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/NmnqsjHeF9rAhG9A30BKV_vI7tIp.xml new file mode 100644 index 0000000..75e44a0 --- /dev/null +++ b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/NmnqsjHeF9rAhG9A30BKV_vI7tIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml b/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml deleted file mode 100644 index fd48245..0000000 --- a/resources/project/NRbCR7m2f1_2pHz6LyHrTz7eFpc/ia5FvKngd_-0tJFYAO64kIgybSkp.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/test_miSim.m b/test_miSim.m index 1a5872e..7ca6362 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -2,16 +2,19 @@ classdef test_miSim < matlab.unittest.TestCase properties (Access = private) testClass = miSim; % Domain - domain = rectangularPrismConstraint; + domain = rectangularPrism; % Obstacles - constraintGeometries = cell(1, 0); + minNumObstacles = 1; + maxNumObstacles = 3; + obstacles = cell(1, 0); minObstacleDimension = 1; % Objective objective = sensingObjective; objectiveFunction = @(x, y) 0; objectiveDiscretizationStep = 0.01; + protectedRange = 1; % Agents minAgents = 3; @@ -31,15 +34,20 @@ classdef test_miSim < matlab.unittest.TestCase methods (TestMethodSetup) % Generate a random domain function tc = setDomain(tc) - % random integer-sized domain within [-10, 10] in all dimensions + % random integer-sized domain ranging from [0, 5] to [0, 25] in all dimensions L = ceil(5 + rand * 10 + rand * 10); tc.domain = tc.domain.initialize([zeros(1, 3); L * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain"); end % Generate a random sensing objective within that domain function tc = setSensingObjective(tc) - mu = tc.domain.random(); - sig = [3, 1; 1, 4]; - tc.objectiveFunction = @(x, y) mvnpdf([x(:), y(:)], mu(1, 1:2), sig); + mu = tc.domain.minCorner; + while tc.domain.interiorDistance(mu) < tc.protectedRange + mu = tc.domain.random(); + end + mu(3) = 0; + assert(tc.domain.contains(mu)); + sig = [2 + rand * 2, 1; 1, 2 + rand * 2]; + tc.objectiveFunction = @(x, y) mvnpdf([x(:), y(:)], mu(1:2), sig); tc.objective = tc.objective.initialize(tc.objectiveFunction, tc.domain.footprint, tc.domain.minCorner(3), tc.objectiveDiscretizationStep); end % Instantiate agents, they will be initialized under different @@ -55,15 +63,14 @@ classdef test_miSim < matlab.unittest.TestCase methods (Test) % Test methods function misim_initialization(tc) - % randomly create 2-3 constraint geometries - nGeom = 1 + randi(2); - tc.constraintGeometries = cell(nGeom, 1); - for ii = 1:size(tc.constraintGeometries, 1) - % Instantiate a rectangular prism constraint that spans the - % domain's height - tc.constraintGeometries{ii, 1} = rectangularPrismConstraint; + % randomly create 2-3 obstacles + nGeom = tc.minNumObstacles + randi(tc.maxNumObstacles - tc.minNumObstacles); + tc.obstacles = cell(nGeom, 1); + for ii = 1:size(tc.obstacles, 1) + % Instantiate a rectangular prism obstacle + tc.obstacles{ii, 1} = rectangularPrism; - % Randomly come up with constraint geometries until they + % Randomly come up with dimensions until they % fit within the domain candidateMinCorner = [-Inf(1, 2), 0]; candidateMaxCorner = Inf(1, 3); @@ -71,7 +78,8 @@ classdef test_miSim < matlab.unittest.TestCase % make sure obstacles are not too small in any dimension tooSmall = true; while tooSmall - % make sure the obstacles don't contain the sensing objective + % make sure the obstacles don't contain the sensing + % objective or encroach on it too much obstructs = true; while obstructs @@ -105,12 +113,13 @@ classdef test_miSim < matlab.unittest.TestCase candidateMinCorner(isinf(candidateMinCorner)) = tc.domain.minCorner(isinf(candidateMinCorner)); candidateMaxCorner(isinf(candidateMaxCorner)) = tc.domain.maxCorner(isinf(candidateMaxCorner)); - % Initialize constraint geometry - tc.constraintGeometries{ii} = tc.constraintGeometries{ii}.initialize([candidateMinCorner; candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); + % Initialize obstacle geometry + tc.obstacles{ii} = tc.obstacles{ii}.initialize([candidateMinCorner; candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); end % Repeat this until a connected set of agent initial conditions % is found by random chance + nIter = 0; connected = false; while ~connected % Randomly place agents in the domain @@ -127,13 +136,13 @@ classdef test_miSim < matlab.unittest.TestCase boringInit = false; end end - candidateGeometry = rectangularPrismConstraint; + candidateGeometry = rectangularPrism; tc.agents{ii} = tc.agents{ii}.initialize(candidatePos, zeros(1, 3), eye(3), candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), ii, sprintf("Agent %d", ii)); % Check obstacles to confirm that none are violated - for jj = 1:size(tc.constraintGeometries, 1) + for jj = 1:size(tc.obstacles, 1) inside = false; - if tc.constraintGeometries{jj, 1}.contains(tc.agents{ii, 1}.pos) + if tc.obstacles{jj, 1}.contains(tc.agents{ii, 1}.pos) % Found a violation, stop checking inside = true; break; @@ -146,7 +155,7 @@ classdef test_miSim < matlab.unittest.TestCase end % Create a collision geometry for this agent - candidateGeometry = rectangularPrismConstraint; + candidateGeometry = rectangularPrism; candidateGeometry = candidateGeometry.initialize([tc.agents{ii}.pos - 0.1 * ones(1, 3); tc.agents{ii}.pos + 0.1 * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)); % Check previously placed agents for collisions @@ -190,10 +199,11 @@ classdef test_miSim < matlab.unittest.TestCase % Check connectivity G = graph(adjacency); connected = all(conncomp(G) == 1); + nIter = nIter + 1; end % Initialize the simulation - tc.testClass = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.constraintGeometries); + tc.testClass = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.obstacles); % Plot domain f = tc.testClass.domain.plotWireframe; @@ -203,9 +213,9 @@ classdef test_miSim < matlab.unittest.TestCase ylim([tc.testClass.domain.minCorner(2) - 0.5, tc.testClass.domain.maxCorner(2) + 0.5]); zlim([tc.testClass.domain.minCorner(3) - 0.5, tc.testClass.domain.maxCorner(3) + 0.5]); - % Plot constraint geometries - for ii = 1:size(tc.testClass.constraintGeometries, 1) - tc.testClass.constraintGeometries{ii, 1}.plotWireframe(f); + % Plot obstacles + for ii = 1:size(tc.testClass.obstacles, 1) + tc.testClass.obstacles{ii, 1}.plotWireframe(f); end % Plot objective gradient diff --git a/validators/mustBeConstraintGeometries.m b/validators/mustBeConstraintGeometries.m deleted file mode 100644 index d16301a..0000000 --- a/validators/mustBeConstraintGeometries.m +++ /dev/null @@ -1,10 +0,0 @@ -function mustBeConstraintGeometries(constraintGeometry) - validGeometries = ["rectangularPrismConstraint";]; - if isa(constraintGeometry, 'cell') - for ii = 1:size(constraintGeometry, 1) - assert(isa(constraintGeometry{ii}, validGeometries), "Constraint geometry in index %d is not a valid constraint geometry class", ii); - end - else - assert(isa(constraintGeometry, validGeometries), "Constraint geometry is not a valid constraint geometry class"); - end -end \ No newline at end of file diff --git a/validators/mustBeGeometry.m b/validators/mustBeGeometry.m new file mode 100644 index 0000000..a8242c1 --- /dev/null +++ b/validators/mustBeGeometry.m @@ -0,0 +1,10 @@ +function mustBeGeometry(geometry) + validGeometries = ["rectangularPrism";]; + if isa(geometry, 'cell') + for ii = 1:size(geometry, 1) + assert(isa(geometry{ii}, validGeometries), "Geometry in index %d is not a valid geometry class", ii); + end + else + assert(isa(geometry, validGeometries), "Geometry is not a valid geometry class"); + end +end \ No newline at end of file From 2f0647caf3e58c2f9caf61f4ced4ba21226d8252 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Sun, 26 Oct 2025 19:14:50 -0700 Subject: [PATCH 05/14] fixed init generation being really slow --- geometries/rectangularPrism.m | 45 +++ .../jjRWXxv1fmTGw_ntc54vNxAyLDMd.xml | 2 + .../jjRWXxv1fmTGw_ntc54vNxAyLDMp.xml | 2 + .../3f4CTErydQ2TqIMJrHErKW1HTm8d.xml} | 0 .../3f4CTErydQ2TqIMJrHErKW1HTm8p.xml} | 0 .../bkRZvUTstiBe1YFWETJX1U9n5uQd.xml | 2 + .../bkRZvUTstiBe1YFWETJX1U9n5uQp.xml | 2 + .../eU5R_sxHD3gVw76yiaPpbMUKFIkd.xml} | 0 .../eU5R_sxHD3gVw76yiaPpbMUKFIkp.xml} | 0 .../xLI7SQj40yDbM71LQ8pVZ0dWmrgd.xml} | 0 .../xLI7SQj40yDbM71LQ8pVZ0dWmrgp.xml} | 0 .../6yzCMKkTsLiObJh9i87v9JChC2Yd.xml | 6 + .../6yzCMKkTsLiObJh9i87v9JChC2Yp.xml | 2 + .../G6lGXsTbuwZ-AEQ27UXCqCsFttEd.xml | 6 + .../G6lGXsTbuwZ-AEQ27UXCqCsFttEp.xml | 2 + .../IkDHDbHimostG0Ka3Qk97pof68kd.xml | 2 + .../IkDHDbHimostG0Ka3Qk97pof68kp.xml | 2 + .../gE3UtRAYb2Mvi_5_27MbNbrZKNcd.xml | 6 + .../gE3UtRAYb2Mvi_5_27MbNbrZKNcp.xml | 2 + .../mjV-hfj-qf8MzZBB6uhFVn0raaUd.xml | 6 + .../mjV-hfj-qf8MzZBB6uhFVn0raaUp.xml | 2 + test_miSim.m | 282 +++++++++--------- validators/agentsCrowdObjective.m | 11 + validators/{ => arguments}/mustBeAgents.m | 0 validators/{ => arguments}/mustBeDcm.m | 0 validators/{ => arguments}/mustBeGeometry.m | 0 validators/domainContainsObstacle.m | 21 ++ validators/obstacleCoversObjective.m | 13 + validators/obstacleCrowdsObjective.m | 11 + 29 files changed, 290 insertions(+), 137 deletions(-) create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMd.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMp.xml rename resources/project/{M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml => IkDHDbHimostG0Ka3Qk97pof68k/3f4CTErydQ2TqIMJrHErKW1HTm8d.xml} (100%) rename resources/project/{M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml => IkDHDbHimostG0Ka3Qk97pof68k/3f4CTErydQ2TqIMJrHErKW1HTm8p.xml} (100%) create mode 100644 resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQd.xml create mode 100644 resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQp.xml rename resources/project/{M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28d.xml => IkDHDbHimostG0Ka3Qk97pof68k/eU5R_sxHD3gVw76yiaPpbMUKFIkd.xml} (100%) rename resources/project/{M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml => IkDHDbHimostG0Ka3Qk97pof68k/eU5R_sxHD3gVw76yiaPpbMUKFIkp.xml} (100%) rename resources/project/{M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml => IkDHDbHimostG0Ka3Qk97pof68k/xLI7SQj40yDbM71LQ8pVZ0dWmrgd.xml} (100%) rename resources/project/{M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml => IkDHDbHimostG0Ka3Qk97pof68k/xLI7SQj40yDbM71LQ8pVZ0dWmrgp.xml} (100%) create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yd.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yp.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEd.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEp.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kd.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kp.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcd.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcp.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUd.xml create mode 100644 resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUp.xml create mode 100644 validators/agentsCrowdObjective.m rename validators/{ => arguments}/mustBeAgents.m (100%) rename validators/{ => arguments}/mustBeDcm.m (100%) rename validators/{ => arguments}/mustBeGeometry.m (100%) create mode 100644 validators/domainContainsObstacle.m create mode 100644 validators/obstacleCoversObjective.m create mode 100644 validators/obstacleCrowdsObjective.m diff --git a/geometries/rectangularPrism.m b/geometries/rectangularPrism.m index c2b37a9..a1b6001 100644 --- a/geometries/rectangularPrism.m +++ b/geometries/rectangularPrism.m @@ -74,6 +74,8 @@ classdef rectangularPrism arguments (Output) d (:, 1) double end + assert(~obj.contains(pos), "Cannot determine distance for a point inside of the geometry"); + cPos = NaN(1, 3); for ii = 1:3 if pos(ii) < obj.minCorner(ii) @@ -94,6 +96,8 @@ classdef rectangularPrism arguments (Output) d (:, 1) double end + assert(obj.contains(pos), "Cannot determine interior distance for a point outside of the geometry"); + % find minimum distance to any face d = min([pos(1) - obj.minCorner(1), ... pos(2) - obj.minCorner(2), ... @@ -112,6 +116,47 @@ classdef rectangularPrism end c = all(pos >= repmat(obj.minCorner, size(pos, 1), 1), 2) & all(pos <= repmat(obj.maxCorner, size(pos, 1), 1), 2); end + function c = containsLine(obj, pos1, pos2) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; + pos1 (1, 3) double; + pos2 (1, 3) double; + end + arguments (Output) + c (1, 1) logical + end + + d = pos2 - pos1; + + % edge case where the line is parallel to the geometry + if abs(d) < 1e-12 + % check if it happens to start or end inside or outside of + % the geometry + if obj.contains(pos1) || obj.contains(pos2) + c = true; + else + c = false; + end + return; + end + + tmin = -inf; + tmax = inf; + + % Standard case + for ii = 1:3 + t1 = (obj.minCorner(ii) - pos1(ii)) / d(ii); + t2 = (obj.maxCorner(ii) - pos2(ii)) / d(ii); + tmin = max(tmin, min(t1, t2)); + tmax = min(tmax, max(t1, t2)); + if tmin > tmax + c = false; + return; + end + end + + c = (tmax >= 0) && (tmin <= 1); + end function f = plotWireframe(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMd.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMd.xml new file mode 100644 index 0000000..2bd39f9 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMp.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMp.xml new file mode 100644 index 0000000..442ec92 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/jjRWXxv1fmTGw_ntc54vNxAyLDMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/3f4CTErydQ2TqIMJrHErKW1HTm8d.xml similarity index 100% rename from resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ed.xml rename to resources/project/IkDHDbHimostG0Ka3Qk97pof68k/3f4CTErydQ2TqIMJrHErKW1HTm8d.xml diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/3f4CTErydQ2TqIMJrHErKW1HTm8p.xml similarity index 100% rename from resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28p.xml rename to resources/project/IkDHDbHimostG0Ka3Qk97pof68k/3f4CTErydQ2TqIMJrHErKW1HTm8p.xml diff --git a/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQd.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQp.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQp.xml new file mode 100644 index 0000000..01cb34e --- /dev/null +++ b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/bkRZvUTstiBe1YFWETJX1U9n5uQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28d.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/eU5R_sxHD3gVw76yiaPpbMUKFIkd.xml similarity index 100% rename from resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oA3NoVC5FBKXh-LtCKBuVxHDs28d.xml rename to resources/project/IkDHDbHimostG0Ka3Qk97pof68k/eU5R_sxHD3gVw76yiaPpbMUKFIkd.xml diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/eU5R_sxHD3gVw76yiaPpbMUKFIkp.xml similarity index 100% rename from resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/ZHl_0ut8g6oljcuQL6lY7K4NP_Ep.xml rename to resources/project/IkDHDbHimostG0Ka3Qk97pof68k/eU5R_sxHD3gVw76yiaPpbMUKFIkp.xml diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/xLI7SQj40yDbM71LQ8pVZ0dWmrgd.xml similarity index 100% rename from resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUod.xml rename to resources/project/IkDHDbHimostG0Ka3Qk97pof68k/xLI7SQj40yDbM71LQ8pVZ0dWmrgd.xml diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml b/resources/project/IkDHDbHimostG0Ka3Qk97pof68k/xLI7SQj40yDbM71LQ8pVZ0dWmrgp.xml similarity index 100% rename from resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/oUK2iWSD0GT8w9SFN0zCkhZLgUop.xml rename to resources/project/IkDHDbHimostG0Ka3Qk97pof68k/xLI7SQj40yDbM71LQ8pVZ0dWmrgp.xml diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yd.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yp.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yp.xml new file mode 100644 index 0000000..82a6428 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/6yzCMKkTsLiObJh9i87v9JChC2Yp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEd.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEp.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEp.xml new file mode 100644 index 0000000..3f2bd30 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/G6lGXsTbuwZ-AEQ27UXCqCsFttEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kd.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kp.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kp.xml new file mode 100644 index 0000000..52177dc --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/IkDHDbHimostG0Ka3Qk97pof68kp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcd.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcp.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcp.xml new file mode 100644 index 0000000..7984fb9 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/gE3UtRAYb2Mvi_5_27MbNbrZKNcp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUd.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUd.xml new file mode 100644 index 0000000..99772b4 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUp.xml b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUp.xml new file mode 100644 index 0000000..8f14f17 --- /dev/null +++ b/resources/project/M3axfhPiVFfHfWnq8PF7Q8OtKAU/mjV-hfj-qf8MzZBB6uhFVn0raaUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/test_miSim.m b/test_miSim.m index 7ca6362..42ced91 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -1,61 +1,72 @@ classdef test_miSim < matlab.unittest.TestCase properties (Access = private) testClass = miSim; + % Domain - domain = rectangularPrism; + domain = rectangularPrism; % domain geometry % Obstacles - minNumObstacles = 1; - maxNumObstacles = 3; + minNumObstacles = 1; % Minimum number of obstacles to be randomly generated + maxNumObstacles = 3; % Maximum number of obstacles to be randomly generated + minObstacleSize = 1; % Minimum size of a randomly generated obstacle + maxObstacleSize = 6; % Maximum size of a randomly generated obstacle obstacles = cell(1, 0); - minObstacleDimension = 1; % Objective + objectiveDiscretizationStep = 0.01; % Step at which the objective function is solved in X and Y space + protectedRange = 1; % Minimum distance between the sensing objective and the edge of the domain objective = sensingObjective; - objectiveFunction = @(x, y) 0; - objectiveDiscretizationStep = 0.01; - protectedRange = 1; % Agents - minAgents = 3; - maxAgents = 9; - agents = cell(1, 0); + minAgents = 3; % Minimum number of agents to be randomly generated + maxAgents = 9; % Maximum number of agents to be randomly generated + agents = cell(0, 1); % Collision - minCollisionRange = 0.1; - maxCollisionRange = 0.5; + minCollisionRange = 0.1; % Minimum randomly generated collision geometry size + maxCollisionRange = 0.5; % Maximum randomly generated collision geometry size collisionRanges = NaN; % Communications - comRange = 5; + comRange = 5; % Maximum range between agents that forms a communications link end % Setup for each test methods (TestMethodSetup) % Generate a random domain function tc = setDomain(tc) - % random integer-sized domain ranging from [0, 5] to [0, 25] in all dimensions + % random integer-sized cube domain ranging from [0, 5 -> 25] + % in all dimensions L = ceil(5 + rand * 10 + rand * 10); tc.domain = tc.domain.initialize([zeros(1, 3); L * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain"); end % Generate a random sensing objective within that domain function tc = setSensingObjective(tc) + % Using a bivariate normal distribution + % Set peak position (mean) mu = tc.domain.minCorner; while tc.domain.interiorDistance(mu) < tc.protectedRange mu = tc.domain.random(); end mu(3) = 0; - assert(tc.domain.contains(mu)); + + % Set standard deviations of bivariate distribution sig = [2 + rand * 2, 1; 1, 2 + rand * 2]; - tc.objectiveFunction = @(x, y) mvnpdf([x(:), y(:)], mu(1:2), sig); - tc.objective = tc.objective.initialize(tc.objectiveFunction, tc.domain.footprint, tc.domain.minCorner(3), tc.objectiveDiscretizationStep); + + % Define objective + tc.objective = tc.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], mu(1:2), sig), tc.domain.footprint, tc.domain.minCorner(3), tc.objectiveDiscretizationStep); end - % Instantiate agents, they will be initialized under different - % parameters in individual test cases + % Instantiate agents function tc = setAgents(tc) + % Agents will be initialized under different parameters in + % individual test cases + + % Instantiate a random number of agents according to parameters for ii = 1:randi([tc.minAgents, tc.maxAgents]) tc.agents{ii, 1} = agent; end + + % Define random collision ranges for each agent tc.collisionRanges = tc.minCollisionRange + rand(size(tc.agents, 1), 1) * (tc.maxCollisionRange - tc.minCollisionRange); end end @@ -66,140 +77,137 @@ classdef test_miSim < matlab.unittest.TestCase % randomly create 2-3 obstacles nGeom = tc.minNumObstacles + randi(tc.maxNumObstacles - tc.minNumObstacles); tc.obstacles = cell(nGeom, 1); + + % Iterate over obstacles to initialize for ii = 1:size(tc.obstacles, 1) - % Instantiate a rectangular prism obstacle - tc.obstacles{ii, 1} = rectangularPrism; - - % Randomly come up with dimensions until they - % fit within the domain - candidateMinCorner = [-Inf(1, 2), 0]; - candidateMaxCorner = Inf(1, 3); - - % make sure obstacles are not too small in any dimension - tooSmall = true; - while tooSmall - % make sure the obstacles don't contain the sensing - % objective or encroach on it too much - obstructs = true; - while obstructs + badCandidate = true; + while badCandidate + % Instantiate a rectangular prism obstacle + tc.obstacles{ii} = rectangularPrism; - % Make sure the obstacle is in the domain - while any(candidateMinCorner < tc.domain.minCorner) - candidateMinCorner = tc.domain.minCorner(1:3) + [(tc.domain.maxCorner(1:2) - tc.domain.minCorner(1:2)) .* rand(1, 2), 0]; % random spots on the ground - end - while any(candidateMaxCorner > tc.domain.maxCorner) - candidateMaxCorner = [candidateMinCorner(1:2), 0] + ((tc.domain.maxCorner(1:3) - tc.domain.minCorner(1:3)) .* rand(1, 3) ./ 2); % halved to keep from being excessively large - end + % Randomly generate min corner for the obstacle + candidateMinCorner = tc.domain.random(); + candidateMinCorner = [candidateMinCorner(1:2), 0]; % bind obstacles to floor of domain - % once a domain-valid obstacle has been found, make - % sure it doesn't obstruct the sensing target - if all(candidateMinCorner(1:2) <= tc.objective.groundPos) && all(candidateMaxCorner(1:2) >= tc.objective.groundPos) - % reset to try again - candidateMinCorner = [-Inf(1, 2), 0]; - candidateMaxCorner = Inf(1, 3); - else - obstructs = false; - end + % Randomly select a corresponding maximum corner that + % satisfies min/max obstacle size specifications + candidateMaxCorner = candidateMinCorner + tc.minObstacleSize + rand(1, 3) * (tc.maxObstacleSize - tc.minObstacleSize); + + % Initialize obstacle + tc.obstacles{ii} = tc.obstacles{ii}.initialize([candidateMinCorner; candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); + + % Make sure that the obstacles are fully contained by + % the domain + if ~domainContainsObstacle(tc.domain, tc.obstacles{ii}) + continue; end - if min(candidateMaxCorner - candidateMinCorner) >= tc.minObstacleDimension - tooSmall = false; - else - candidateMinCorner = [-Inf(1, 2), 0]; - candidateMaxCorner = Inf(1, 3); + + % Make sure that the obstacles don't cover the sensing + % objective + if obstacleCoversObjective(tc.objective, tc.obstacles{ii}) + continue; end + + % Make sure that the obstacles aren't too close to the + % sensing objective + if obstacleCrowdsObjective(tc.objective, tc.obstacles{ii}, tc.protectedRange) + continue; + end + + badCandidate = false; end - - % Reduce infinite dimensions to the domain - candidateMinCorner(isinf(candidateMinCorner)) = tc.domain.minCorner(isinf(candidateMinCorner)); - candidateMaxCorner(isinf(candidateMaxCorner)) = tc.domain.maxCorner(isinf(candidateMaxCorner)); - - % Initialize obstacle geometry - tc.obstacles{ii} = tc.obstacles{ii}.initialize([candidateMinCorner; candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); end - - % Repeat this until a connected set of agent initial conditions - % is found by random chance - nIter = 0; - connected = false; - while ~connected - % Randomly place agents in the domain - for ii = 1:size(tc.agents, 1) - posInvalid = true; - while posInvalid - % Initialize the agent into a random spot in the - % domain (that is not too close to the sensing - % objective) - boringInit = true; - while boringInit + + % Add agents individually, ensuring that each addition does not + % invalidate the initialization setup + for ii = 1:size(tc.agents, 1) + initInvalid = true; + while initInvalid + candidatePos = [tc.objective.groundPos, 0]; + % Generate a random position for the agent based on + % existing agent positions + if ii == 1 + while agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2) candidatePos = tc.domain.random(); - if norm(candidatePos(1:2) - tc.objective.groundPos) >= norm(tc.domain.footprint(4, :) - tc.domain.footprint(1, :))/2 - boringInit = false; + end + else + candidatePos = tc.agents{randi(ii - 1)}.pos + sign(randn([1, 3])) .* (rand(1, 3) .* tc.comRange/sqrt(2)); + end + + % Make sure that the candidate position is within the + % domain + if ~tc.domain.contains(candidatePos) + continue; + end + + % Make sure that the candidate position does not crowd + % the sensing objective and create boring scenarios + if agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2) + continue; + end + + % Make sure that there exist unobstructed lines of sight at + % appropriate ranges to form a connected communications + % graph between the agents + connections = false(1, ii - 1); + for jj = 1:(ii - 1) + if norm(tc.agents{jj}.pos - candidatePos) <= tc.comRange + % Check new agent position against all existing + % agent positions for communications range + connections(jj) = true; + for kk = 1:size(tc.obstacles, 1) + if tc.obstacles{kk}.containsLine(tc.agents{jj}.pos, candidatePos) + connections(jj) = false; + end end end - candidateGeometry = rectangularPrism; - tc.agents{ii} = tc.agents{ii}.initialize(candidatePos, zeros(1, 3), eye(3), candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), ii, sprintf("Agent %d", ii)); - - % Check obstacles to confirm that none are violated - for jj = 1:size(tc.obstacles, 1) - inside = false; - if tc.obstacles{jj, 1}.contains(tc.agents{ii, 1}.pos) - % Found a violation, stop checking - inside = true; + end + + % New agent must be connected to an existing agent to + % be valid + if ii ~= 1 && ~any(connections) + continue; + end + + % Initialize candidate agent + candidateGeometry = rectangularPrism; + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), ii, sprintf("Agent %d", ii)); + + % Make sure candidate agent doesn't collide with + % domain, obstacles, or any existing agents + violation = false; + for jj = 1:size(newAgent.collisionGeometry.vertices, 1) + % Check if collision geometry exits domain + if ~tc.domain.contains(newAgent.collisionGeometry.vertices(jj, 1:3)) + violation = true; + break; + end + + % Check if collision geometry enters obstacle + for kk = 1:size(tc.obstacles, 1) + if tc.obstacles{kk}.contains(newAgent.collisionGeometry.vertices(jj, 1:3)) + violation = true; break; end end - - % Agent is inside obstacle, try again - if inside - continue; - end - - % Create a collision geometry for this agent - candidateGeometry = rectangularPrism; - candidateGeometry = candidateGeometry.initialize([tc.agents{ii}.pos - 0.1 * ones(1, 3); tc.agents{ii}.pos + 0.1 * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)); - - % Check previously placed agents for collisions - for jj = 1:(ii - 1) - % Check if previously defined agents collide with - % this one - colliding = false; - if candidateGeometry.contains(tc.agents{jj, 1}.pos) - % Found a violation, stop checking - colliding = true; + + % Check if collision geometry enters other + % collision geometry + for kk = 1:(ii - 1) + if tc.agents{kk}.collisionGeometry.contains(newAgent.collisionGeometry.vertices(jj, 1:3)) + violation = true; break; end end - - % Agent is colliding with another, try again - if ii ~= 1 && colliding - continue; - end - - % Allow to proceed since no obstacle/collision - % violations were found - posInvalid = false; end - end - - % Collect all agent positions - posArray = arrayfun(@(x) x{1}.pos, tc.agents, 'UniformOutput', false); - posArray = reshape([posArray{:}], size(tc.agents, 1), 3); - - % Communications checks - adjacency = false(size(tc.agents, 1), size(tc.agents, 1)); - for ii = 1:size(tc.agents, 1) - % Compute distance from each to all agents - for jj = 1:(size(tc.agents, 1)) - if norm(posArray(ii, 1:3) - posArray(jj, 1:3)) <= tc.comRange - adjacency(ii, jj) = true; - end + if violation + continue; end + + % Candidate agent is valid, store to pass in to sim + initInvalid = false; + tc.agents{ii} = newAgent; end - - % Check connectivity - G = graph(adjacency); - connected = all(conncomp(G) == 1); - nIter = nIter + 1; end % Initialize the simulation @@ -215,7 +223,7 @@ classdef test_miSim < matlab.unittest.TestCase % Plot obstacles for ii = 1:size(tc.testClass.obstacles, 1) - tc.testClass.obstacles{ii, 1}.plotWireframe(f); + tc.testClass.obstacles{ii}.plotWireframe(f); end % Plot objective gradient @@ -223,8 +231,8 @@ classdef test_miSim < matlab.unittest.TestCase % Plot agents and their collision geometries for ii = 1:size(tc.testClass.agents, 1) - f = tc.testClass.agents{ii, 1}.plot(f); - f = tc.testClass.agents{ii, 1}.collisionGeometry.plotWireframe(f); + f = tc.testClass.agents{ii}.plot(f); + f = tc.testClass.agents{ii}.collisionGeometry.plotWireframe(f); end end end diff --git a/validators/agentsCrowdObjective.m b/validators/agentsCrowdObjective.m new file mode 100644 index 0000000..be93221 --- /dev/null +++ b/validators/agentsCrowdObjective.m @@ -0,0 +1,11 @@ +function c = agentsCrowdObjective(objective, positions, protectedRange) + arguments (Input) + objective (1, 1) {mustBeA(objective, 'sensingObjective')}; + positions (:, 3) double; % this could be expanded to handle n obstacles in 1 call + protectedRange (1, 1) double; + end + arguments (Output) + c (:, 1) logical; + end + c = vecnorm(positions(:, 1:2) - objective.groundPos, 2, 2) <= protectedRange; +end \ No newline at end of file diff --git a/validators/mustBeAgents.m b/validators/arguments/mustBeAgents.m similarity index 100% rename from validators/mustBeAgents.m rename to validators/arguments/mustBeAgents.m diff --git a/validators/mustBeDcm.m b/validators/arguments/mustBeDcm.m similarity index 100% rename from validators/mustBeDcm.m rename to validators/arguments/mustBeDcm.m diff --git a/validators/mustBeGeometry.m b/validators/arguments/mustBeGeometry.m similarity index 100% rename from validators/mustBeGeometry.m rename to validators/arguments/mustBeGeometry.m diff --git a/validators/domainContainsObstacle.m b/validators/domainContainsObstacle.m new file mode 100644 index 0000000..a2d64ae --- /dev/null +++ b/validators/domainContainsObstacle.m @@ -0,0 +1,21 @@ +function c = domainContainsObstacle(domain, obstacle) + arguments (Input) + domain (1, 1) {mustBeGeometry}; + obstacle (1, 1) {mustBeGeometry}; % this could be expanded to handle n obstacles in 1 call + end + arguments (Output) + c (1, 1) logical; + end + + switch class(domain) + case 'rectangularPrism' + switch class(obstacle) + case 'rectangularPrism' + c = all(domain.minCorner <= obstacle.minCorner) && all(domain.maxCorner >= obstacle.maxCorner); + otherwise + error("%s not implemented for obstacles of class %s", coder.mfunctionname, class(domain)); + end + otherwise + error("%s not implemented for domains of class %s", coder.mfunctionname, class(domain)); + end +end \ No newline at end of file diff --git a/validators/obstacleCoversObjective.m b/validators/obstacleCoversObjective.m new file mode 100644 index 0000000..672a4d0 --- /dev/null +++ b/validators/obstacleCoversObjective.m @@ -0,0 +1,13 @@ +function c = obstacleCoversObjective(objective, obstacle) + arguments (Input) + objective (1, 1) {mustBeA(objective, 'sensingObjective')}; + obstacle (1, 1) {mustBeGeometry}; % this could be expanded to handle n obstacles in 1 call + end + arguments (Output) + c (1, 1) logical; + end + + % Check if the obstacle contains the objective's ground position if the + % ground position were raised to the obstacle's center's height + c = obstacle.contains([objective.groundPos, obstacle.center(3)]); +end \ No newline at end of file diff --git a/validators/obstacleCrowdsObjective.m b/validators/obstacleCrowdsObjective.m new file mode 100644 index 0000000..941aa69 --- /dev/null +++ b/validators/obstacleCrowdsObjective.m @@ -0,0 +1,11 @@ +function c = obstacleCrowdsObjective(objective, obstacle, protectedRange) + arguments (Input) + objective (1, 1) {mustBeA(objective, 'sensingObjective')}; + obstacle (1, 1) {mustBeGeometry}; % this could be expanded to handle n obstacles in 1 call + protectedRange (1, 1) double; + end + arguments (Output) + c (1, 1) logical; + end + c = norm(obstacle.distance([objective.groundPos, obstacle.center(3)])) <= protectedRange; +end \ No newline at end of file From d0a060f404af43f104af25485e885a7db2b51bb2 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Sun, 26 Oct 2025 19:45:32 -0700 Subject: [PATCH 06/14] fixed collision detection in initialization --- geometries/rectangularPrism.m | 14 ++++----- test_miSim.m | 51 +++++++++++++++++++++++---------- validators/geometryIntersects.m | 17 +++++++++++ 3 files changed, 60 insertions(+), 22 deletions(-) create mode 100644 validators/geometryIntersects.m diff --git a/geometries/rectangularPrism.m b/geometries/rectangularPrism.m index a1b6001..eba190b 100644 --- a/geometries/rectangularPrism.m +++ b/geometries/rectangularPrism.m @@ -13,6 +13,10 @@ classdef rectangularPrism vertices = NaN(8, 3); + edges = [1 2; 2 3; 3 4; 4 1; % bottom square + 5 6; 6 8; 8 7; 7 5; % top square + 1 5; 2 6; 3 8; 4 7]; % vertical edges + footprint = NaN(4, 2); end @@ -169,14 +173,10 @@ classdef rectangularPrism % Create axes if they don't already exist f = firstPlotSetup(f); - edges = [1 2; 2 3; 3 4; 4 1; % bottom square - 5 6; 6 8; 8 7; 7 5; % top square - 1 5; 2 6; 3 8; 4 7]; % vertical edges - % Create plotting inputs from vertices and edges - X = [obj.vertices(edges(:,1),1), obj.vertices(edges(:,2),1)]'; - Y = [obj.vertices(edges(:,1),2), obj.vertices(edges(:,2),2)]'; - Z = [obj.vertices(edges(:,1),3), obj.vertices(edges(:,2),3)]'; + X = [obj.vertices(obj.edges(:,1),1), obj.vertices(obj.edges(:,2),1)]'; + Y = [obj.vertices(obj.edges(:,1),2), obj.vertices(obj.edges(:,2),2)]'; + Z = [obj.vertices(obj.edges(:,1),3), obj.vertices(obj.edges(:,2),3)]'; % Plot the boundaries of the geometry hold(f.CurrentAxes, "on"); diff --git a/test_miSim.m b/test_miSim.m index 42ced91..3c8c6d8 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -96,6 +96,19 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize obstacle tc.obstacles{ii} = tc.obstacles{ii}.initialize([candidateMinCorner; candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); + % Check if the obstacle intersects with any existing + % obstacles + violation = false; + for kk = 1:(ii - 1) + if geometryIntersects(tc.obstacles{kk}, tc.obstacles{ii}) + violation = true; + break; + end + end + if violation + continue; + end + % Make sure that the obstacles are fully contained by % the domain if ~domainContainsObstacle(tc.domain, tc.obstacles{ii}) @@ -174,7 +187,7 @@ classdef test_miSim < matlab.unittest.TestCase newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), ii, sprintf("Agent %d", ii)); % Make sure candidate agent doesn't collide with - % domain, obstacles, or any existing agents + % domain violation = false; for jj = 1:size(newAgent.collisionGeometry.vertices, 1) % Check if collision geometry exits domain @@ -182,22 +195,30 @@ classdef test_miSim < matlab.unittest.TestCase violation = true; break; end + end + if violation + continue; + end - % Check if collision geometry enters obstacle - for kk = 1:size(tc.obstacles, 1) - if tc.obstacles{kk}.contains(newAgent.collisionGeometry.vertices(jj, 1:3)) - violation = true; - break; - end + % Make sure candidate doesn't collide with obstacles + violation = false; + for kk = 1:size(tc.obstacles, 1) + if geometryIntersects(tc.obstacles{kk}, newAgent.collisionGeometry) + violation = true; + break; end - - % Check if collision geometry enters other - % collision geometry - for kk = 1:(ii - 1) - if tc.agents{kk}.collisionGeometry.contains(newAgent.collisionGeometry.vertices(jj, 1:3)) - violation = true; - break; - end + end + if violation + continue; + end + + % Make sure candidate doesn't collide with existing + % agents + violation = false; + for kk = 1:(ii - 1) + if geometryIntersects(tc.agents{kk}.collisionGeometry, newAgent.collisionGeometry) + violation = true; + break; end end if violation diff --git a/validators/geometryIntersects.m b/validators/geometryIntersects.m new file mode 100644 index 0000000..278f4c5 --- /dev/null +++ b/validators/geometryIntersects.m @@ -0,0 +1,17 @@ +function c = geometryIntersects(g1, g2) + c = false; + % Check if g2 contains g1 + for jj = 1:size(g1.edges, 1) + if g2.containsLine(g1.vertices(g1.edges(jj, 1), 1:3), g1.vertices(g1.edges(jj, 2), 1:3)) + c = true; + return; + end + end + % Check if g1 contains g2 + for jj = 1:size(g2.edges, 1) + if g1.containsLine(g2.vertices(g2.edges(jj, 1), 1:3), g2.vertices(g2.edges(jj, 2), 1:3)) + c = true; + return; + end + end +end \ No newline at end of file From 8af5e87272e136349a995b749df69182e1829951 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 09:22:20 -0700 Subject: [PATCH 07/14] added multiple visualization perspectives --- agent.m | 10 +++++++- firstPlotSetup.m | 44 +++++++++++++++++++++++++++++++---- geometries/rectangularPrism.m | 10 +++++++- sensingObjective.m | 25 +++++++++++++++----- test_miSim.m | 6 ++--- 5 files changed, 80 insertions(+), 15 deletions(-) diff --git a/agent.m b/agent.m index 1f338af..2340933 100644 --- a/agent.m +++ b/agent.m @@ -52,8 +52,16 @@ classdef agent % Plot points representing the agent position hold(f.CurrentAxes, "on"); - scatter3(obj.pos(1), obj.pos(2), obj.pos(3), 'filled', 'ko', 'SizeData', 50); + o = scatter3(obj.pos(1), obj.pos(2), obj.pos(3), 'filled', 'ko', 'SizeData', 25); hold(f.CurrentAxes, "off"); + + % Check if this is a tiled layout figure + if strcmp(f.Children(1).Type, 'tiledlayout') + % Add to other perspectives + copyobj(o, f.Children(1).Children(2)); + copyobj(o, f.Children(1).Children(3)); + copyobj(o, f.Children(1).Children(5)); + end end end end \ No newline at end of file diff --git a/firstPlotSetup.m b/firstPlotSetup.m index d97b1f2..96182a4 100644 --- a/firstPlotSetup.m +++ b/firstPlotSetup.m @@ -1,8 +1,44 @@ function f = firstPlotSetup(f) if isempty(f.CurrentAxes) - axes(f); - axis(f.CurrentAxes, "equal"); - grid(f.CurrentAxes, "on"); - view(f.CurrentAxes, 3); + tiledlayout(f, 4, 3, "TileSpacing", "tight", "Padding", "compact"); + + % Top-down view + nexttile(1, [1, 2]); + axes(f.Children(1).Children(1)); + axis(f.Children(1).Children(1), "image"); + grid(f.Children(1).Children(1), "on"); + view(f.Children(1).Children(1), 0, 90); + xlabel(f.Children(1).Children(1), "X"); ylabel(f.Children(1).Children(1), "Y"); + + % Communications graph + nexttile(3, [1, 1]); + axes(f.Children(1).Children(1)); + axis(f.Children(1).Children(1), "image"); + grid(f.Children(1).Children(1), "off"); + view(f.Children(1).Children(1), 0, 0); + + % 3D view + nexttile(4, [2, 2]); + axes(f.Children(1).Children(1)); + axis(f.Children(1).Children(1), "image"); + grid(f.Children(1).Children(1), "on"); + view(f.Children(1).Children(1), 3); + xlabel(f.Children(1).Children(1), "X"); ylabel(f.Children(1).Children(1), "Y"); zlabel(f.Children(1).Children(1), "Z"); + + % Side-on view + nexttile(6, [2, 1]); + axes(f.Children(1).Children(1)); + axis(f.Children(1).Children(1), "image"); + grid(f.Children(1).Children(1), "on"); + view(f.Children(1).Children(1), 90, 0); + ylabel(f.Children(1).Children(1), "Y"); zlabel(f.Children(1).Children(1), "Z"); + + % Front-on view + nexttile(10, [1, 2]); + axes(f.Children(1).Children(1)); + axis(f.Children(1).Children(1), "image"); + grid(f.Children(1).Children(1), "on"); + view(f.Children(1).Children(1), 0, 0); + xlabel(f.Children(1).Children(1), "X"); zlabel(f.Children(1).Children(1), "Z"); end end \ No newline at end of file diff --git a/geometries/rectangularPrism.m b/geometries/rectangularPrism.m index eba190b..8af3d31 100644 --- a/geometries/rectangularPrism.m +++ b/geometries/rectangularPrism.m @@ -180,8 +180,16 @@ classdef rectangularPrism % Plot the boundaries of the geometry hold(f.CurrentAxes, "on"); - plot3(X, Y, Z, '-', 'Color', obj.tag.color, 'LineWidth', 2); + o = plot3(X, Y, Z, '-', 'Color', obj.tag.color, 'LineWidth', 2); hold(f.CurrentAxes, "off"); + + % Check if this is a tiled layout figure + if strcmp(f.Children(1).Type, 'tiledlayout') + % Add to other perspectives + copyobj(o, f.Children(1).Children(2)); + copyobj(o, f.Children(1).Children(3)); + copyobj(o, f.Children(1).Children(5)); + end end end end \ No newline at end of file diff --git a/sensingObjective.m b/sensingObjective.m index 293f624..b468018 100644 --- a/sensingObjective.m +++ b/sensingObjective.m @@ -58,12 +58,25 @@ classdef sensingObjective % Create axes if they don't already exist f = firstPlotSetup(f); - % Plot gradient on the "floor" of the domain - hold(f.CurrentAxes, "on"); - s = surf(obj.X, obj.Y, repmat(obj.groundAlt, size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none'); - s.HitTest = 'off'; - s.PickableParts = 'none'; - hold(f.CurrentAxes, "off"); + % Check if this is a tiled layout figure + if strcmp(f.Children(1).Type, 'tiledlayout') + % Plot gradient on the "floor" of the domain + hold(f.Children(1).Children(3), "on"); + o = surf(f.Children(1).Children(3), obj.X, obj.Y, repmat(obj.groundAlt, size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none'); + o.HitTest = 'off'; + o.PickableParts = 'none'; + hold(f.Children(1).Children(3), "off"); + + % Add to other perspectives + copyobj(o, f.Children(1).Children(5)); + else + % Plot gradient on the "floor" of the domain + hold(f.CurrentAxes, "on"); + o = surf(obj.X, obj.Y, repmat(obj.groundAlt, size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none'); + o.HitTest = 'off'; + o.PickableParts = 'none'; + hold(f.CurrentAxes, "off"); + end end end end \ No newline at end of file diff --git a/test_miSim.m b/test_miSim.m index 3c8c6d8..8586776 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -238,9 +238,9 @@ classdef test_miSim < matlab.unittest.TestCase f = tc.testClass.domain.plotWireframe; % Set plotting limits to focus on the domain - xlim([tc.testClass.domain.minCorner(1) - 0.5, tc.testClass.domain.maxCorner(1) + 0.5]); - ylim([tc.testClass.domain.minCorner(2) - 0.5, tc.testClass.domain.maxCorner(2) + 0.5]); - zlim([tc.testClass.domain.minCorner(3) - 0.5, tc.testClass.domain.maxCorner(3) + 0.5]); + xlim([tc.testClass.domain.minCorner(1), tc.testClass.domain.maxCorner(1)]); + ylim([tc.testClass.domain.minCorner(2), tc.testClass.domain.maxCorner(2)]); + zlim([tc.testClass.domain.minCorner(3), tc.testClass.domain.maxCorner(3)]); % Plot obstacles for ii = 1:size(tc.testClass.obstacles, 1) From b2787e1e53a45e8a932f6a38e69501545efdf2dc Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 19:42:59 -0700 Subject: [PATCH 08/14] Added connections to plots --- agent.m | 7 +++++- miSim.m | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test_miSim.m | 5 ++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/agent.m b/agent.m index 2340933..eb8a4d4 100644 --- a/agent.m +++ b/agent.m @@ -14,16 +14,20 @@ classdef agent % Collision collisionGeometry; + + % Communication + comRange = NaN; end methods (Access = public) - function obj = initialize(obj, pos, vel, cBfromC, collisionGeometry, index, label) + function obj = initialize(obj, pos, vel, cBfromC, collisionGeometry, comRange, index, label) arguments (Input) obj (1, 1) {mustBeA(obj, 'agent')}; pos (1, 3) double; vel (1, 3) double; cBfromC (3, 3) double {mustBeDcm}; collisionGeometry (1, 1) {mustBeGeometry}; + comRange (1, 1) double = NaN; index (1, 1) double = NaN; label (1, 1) string = ""; end @@ -35,6 +39,7 @@ classdef agent obj.vel = vel; obj.cBfromC = cBfromC; obj.collisionGeometry = collisionGeometry; + obj.comRange = comRange; obj.index = index; obj.label = label; end diff --git a/miSim.m b/miSim.m index 908f33f..dd52399 100644 --- a/miSim.m +++ b/miSim.m @@ -7,6 +7,7 @@ classdef miSim objective = sensingObjective; obstacles = cell(0, 1); % geometries that define obstacles within the domain agents = cell(0, 1); % agents that move within the domain + adjacency = NaN; % Adjacency matrix representing communications network graph end methods (Access = public) @@ -34,6 +35,67 @@ classdef miSim %% Define agents obj.agents = agents; + %% Compute adjacency matrix + obj = obj.updateAdjacency(); + + end + function obj = updateAdjacency(obj) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'miSim')}; + end + arguments (Output) + obj (1, 1) {mustBeA(obj, 'miSim')}; + end + + % Initialize assuming only self-connections + A = logical(eye(size(obj.agents, 1))); + + % Check lower triangle off-diagonal connections + for ii = 2:size(A, 1) + for jj = 1:(ii - 1) + if norm(obj.agents{ii}.pos - obj.agents{jj}.pos) <= min([obj.agents{ii}.comRange, obj.agents{jj}.comRange]) + A(ii, jj) = true; + end + end + end + + obj.adjacency = A; + end + function f = plotNetwork(obj, f) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'miSim')}; + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; + end + arguments (Output) + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; + end + + % Iterate over lower triangle off-diagonal region of the + % adjacency matrix to plot communications links between agents + X = []; Y = []; Z = []; + for ii = 2:size(obj.adjacency, 1) + for jj = 1:(ii - 1) + if obj.adjacency(ii, jj) + X = [X; obj.agents{ii}.pos(1), obj.agents{jj}.pos(1)]; + Y = [Y; obj.agents{ii}.pos(2), obj.agents{jj}.pos(2)]; + Z = [Z; obj.agents{ii}.pos(3), obj.agents{jj}.pos(3)]; + end + end + end + X = X'; Y = Y'; Z = Z'; + + % Plot the connections + hold(f.CurrentAxes, "on"); + o = plot3(X, Y, Z, 'Color', 'g', 'LineWidth', 1, 'LineStyle', '--'); + hold(f.CurrentAxes, "off"); + + % Check if this is a tiled layout figure + if strcmp(f.Children(1).Type, 'tiledlayout') + % Add to other plots + copyobj(o, f.Children(1).Children(2)); + copyobj(o, f.Children(1).Children(3)); + copyobj(o, f.Children(1).Children(5)); + end end end diff --git a/test_miSim.m b/test_miSim.m index 8586776..4033729 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -184,7 +184,7 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize candidate agent candidateGeometry = rectangularPrism; - newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), ii, sprintf("Agent %d", ii)); + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), tc.comRange, ii, sprintf("Agent %d", ii)); % Make sure candidate agent doesn't collide with % domain @@ -255,6 +255,9 @@ classdef test_miSim < matlab.unittest.TestCase f = tc.testClass.agents{ii}.plot(f); f = tc.testClass.agents{ii}.collisionGeometry.plotWireframe(f); end + + % Plot communication links + f = tc.testClass.plotNetwork(f); end end end \ No newline at end of file From f953cd38829ca0992f133ab5349ae7ae37ad9214 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 19:52:10 -0700 Subject: [PATCH 09/14] added abstract network graph plot --- firstPlotSetup.m | 5 +++++ miSim.m | 22 +++++++++++++++++++++- test_miSim.m | 3 +++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/firstPlotSetup.m b/firstPlotSetup.m index 96182a4..3b29be0 100644 --- a/firstPlotSetup.m +++ b/firstPlotSetup.m @@ -9,6 +9,7 @@ function f = firstPlotSetup(f) grid(f.Children(1).Children(1), "on"); view(f.Children(1).Children(1), 0, 90); xlabel(f.Children(1).Children(1), "X"); ylabel(f.Children(1).Children(1), "Y"); + title("Top-down Perspective"); % Communications graph nexttile(3, [1, 1]); @@ -16,8 +17,10 @@ function f = firstPlotSetup(f) axis(f.Children(1).Children(1), "image"); grid(f.Children(1).Children(1), "off"); view(f.Children(1).Children(1), 0, 0); + title("Network Graph"); % 3D view + title("3D Perspective"); nexttile(4, [2, 2]); axes(f.Children(1).Children(1)); axis(f.Children(1).Children(1), "image"); @@ -26,6 +29,7 @@ function f = firstPlotSetup(f) xlabel(f.Children(1).Children(1), "X"); ylabel(f.Children(1).Children(1), "Y"); zlabel(f.Children(1).Children(1), "Z"); % Side-on view + title("Side-on Perspective"); nexttile(6, [2, 1]); axes(f.Children(1).Children(1)); axis(f.Children(1).Children(1), "image"); @@ -34,6 +38,7 @@ function f = firstPlotSetup(f) ylabel(f.Children(1).Children(1), "Y"); zlabel(f.Children(1).Children(1), "Z"); % Front-on view + title("Front-on Perspective"); nexttile(10, [1, 2]); axes(f.Children(1).Children(1)); axis(f.Children(1).Children(1), "image"); diff --git a/miSim.m b/miSim.m index dd52399..c154bcf 100644 --- a/miSim.m +++ b/miSim.m @@ -59,7 +59,7 @@ classdef miSim end end - obj.adjacency = A; + obj.adjacency = A | A'; end function f = plotNetwork(obj, f) arguments (Input) @@ -97,6 +97,26 @@ classdef miSim copyobj(o, f.Children(1).Children(5)); end end + function f = plotGraph(obj, f) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'miSim')}; + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; + end + arguments (Output) + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; + end + + % Form graph from adjacency matrix + G = graph(obj.adjacency, 'omitselfloops'); + + % Check if this is a tiled layout figure + if strcmp(f.Children(1).Type, 'tiledlayout') + o = plot(f.Children(1).Children(4), G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k'); + else + o = plot(f.CurrentAxes, G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k'); + end + + end end methods (Access = private) diff --git a/test_miSim.m b/test_miSim.m index 4033729..71842d9 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -258,6 +258,9 @@ classdef test_miSim < matlab.unittest.TestCase % Plot communication links f = tc.testClass.plotNetwork(f); + + % Plot abstract network graph + f = tc.testClass.plotGraph(f); end end end \ No newline at end of file From 8955d4d29bf182e7e6d398c44e0eb8492faef347 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 20:45:37 -0700 Subject: [PATCH 10/14] fixed bug allowing obstructed coms connections --- agent.m | 3 +- miSim.m | 54 +++++++++++--- test_miSim.m | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 243 insertions(+), 15 deletions(-) diff --git a/agent.m b/agent.m index eb8a4d4..b75af2b 100644 --- a/agent.m +++ b/agent.m @@ -20,13 +20,14 @@ classdef agent end methods (Access = public) - function obj = initialize(obj, pos, vel, cBfromC, collisionGeometry, comRange, index, label) + function obj = initialize(obj, pos, vel, cBfromC, collisionGeometry, sensingFunction, comRange, index, label) arguments (Input) obj (1, 1) {mustBeA(obj, 'agent')}; pos (1, 3) double; vel (1, 3) double; cBfromC (3, 3) double {mustBeDcm}; collisionGeometry (1, 1) {mustBeGeometry}; + sensingFunction (1, 1) {mustBeA(sensingFunction, 'function_handle')} comRange (1, 1) double = NaN; index (1, 1) double = NaN; label (1, 1) string = ""; diff --git a/miSim.m b/miSim.m index c154bcf..e60cdff 100644 --- a/miSim.m +++ b/miSim.m @@ -3,6 +3,8 @@ classdef miSim % Simulation parameters properties (SetAccess = private, GetAccess = public) + timestep = NaN; % delta time interval for simulation iterations + maxIter = NaN; % maximum number of simulation iterations domain = rectangularPrism; objective = sensingObjective; obstacles = cell(0, 1); % geometries that define obstacles within the domain @@ -11,33 +13,58 @@ classdef miSim end methods (Access = public) - function obj = initialize(obj, domain, objective, agents, obstacles) + function obj = initialize(obj, domain, objective, agents, timestep, maxIter, obstacles) arguments (Input) obj (1, 1) {mustBeA(obj, 'miSim')}; domain (1, 1) {mustBeGeometry}; objective (1, 1) {mustBeA(objective, 'sensingObjective')}; agents (:, 1) cell {mustBeAgents}; + timestep (:, 1) double = 0.05; + maxIter (:, 1) double = 1000; obstacles (:, 1) cell {mustBeGeometry} = cell(0, 1); end arguments (Output) obj (1, 1) {mustBeA(obj, 'miSim')}; end - %% Define domain + % Define simulation time parameters + obj.timestep = timestep; + obj.maxIter = maxIter; + + % Define domain obj.domain = domain; - %% Add geometries representing obstacles within the domain + % Add geometries representing obstacles within the domain obj.obstacles = obstacles; - %% Define objective + % Define objective obj.objective = objective; - %% Define agents + % Define agents obj.agents = agents; - %% Compute adjacency matrix + % Compute adjacency matrix obj = obj.updateAdjacency(); + end + function obj = run(obj) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'miSim')}; + end + arguments (Output) + obj (1, 1) {mustBeA(obj, 'miSim')}; + end + keyboard + % Iterate over agents to simulate their motion + for ii = 1:size(obj.agents, 1) + obj.agents{ii} + end + + % Update adjacency matrix + obj = obj.updateAdjacency; + + % Update plots + end function obj = updateAdjacency(obj) arguments (Input) @@ -54,7 +81,13 @@ classdef miSim for ii = 2:size(A, 1) for jj = 1:(ii - 1) if norm(obj.agents{ii}.pos - obj.agents{jj}.pos) <= min([obj.agents{ii}.comRange, obj.agents{jj}.comRange]) - A(ii, jj) = true; + % Make sure that obstacles don't obstruct the line + % of sight, breaking the connection + for kk = 1:size(obj.obstacles, 1) + if ~obj.obstacles{kk}.containsLine(obj.agents{ii}.pos, obj.agents{jj}.pos) + A(ii, jj) = true; + end + end end end end @@ -86,7 +119,7 @@ classdef miSim % Plot the connections hold(f.CurrentAxes, "on"); - o = plot3(X, Y, Z, 'Color', 'g', 'LineWidth', 1, 'LineStyle', '--'); + o = plot3(X, Y, Z, 'Color', 'g', 'LineWidth', 2, 'LineStyle', '--'); hold(f.CurrentAxes, "off"); % Check if this is a tiled layout figure @@ -111,11 +144,10 @@ classdef miSim % Check if this is a tiled layout figure if strcmp(f.Children(1).Type, 'tiledlayout') - o = plot(f.Children(1).Children(4), G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k'); + o = plot(f.Children(1).Children(4), G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2); else - o = plot(f.CurrentAxes, G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k'); + o = plot(f.CurrentAxes, G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2); end - end end diff --git a/test_miSim.m b/test_miSim.m index 71842d9..f949ac8 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -4,6 +4,8 @@ classdef test_miSim < matlab.unittest.TestCase % Domain domain = rectangularPrism; % domain geometry + maxIter = 1000; + timestep = 0.05 % Obstacles minNumObstacles = 1; % Minimum number of obstacles to be randomly generated @@ -74,7 +76,7 @@ classdef test_miSim < matlab.unittest.TestCase methods (Test) % Test methods function misim_initialization(tc) - % randomly create 2-3 obstacles + % randomly create obstacles nGeom = tc.minNumObstacles + randi(tc.maxNumObstacles - tc.minNumObstacles); tc.obstacles = cell(nGeom, 1); @@ -184,7 +186,7 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize candidate agent candidateGeometry = rectangularPrism; - newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), tc.comRange, ii, sprintf("Agent %d", ii)); + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), @(r) 0.5, tc.comRange, ii, sprintf("Agent %d", ii)); % Make sure candidate agent doesn't collide with % domain @@ -232,7 +234,7 @@ classdef test_miSim < matlab.unittest.TestCase end % Initialize the simulation - tc.testClass = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.obstacles); + tc.testClass = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles); % Plot domain f = tc.testClass.domain.plotWireframe; @@ -262,5 +264,198 @@ classdef test_miSim < matlab.unittest.TestCase % Plot abstract network graph f = tc.testClass.plotGraph(f); end + function misim_run(tc) + % randomly create obstacles + nGeom = tc.minNumObstacles + randi(tc.maxNumObstacles - tc.minNumObstacles); + tc.obstacles = cell(nGeom, 1); + + % Iterate over obstacles to initialize + for ii = 1:size(tc.obstacles, 1) + badCandidate = true; + while badCandidate + % Instantiate a rectangular prism obstacle + tc.obstacles{ii} = rectangularPrism; + + % Randomly generate min corner for the obstacle + candidateMinCorner = tc.domain.random(); + candidateMinCorner = [candidateMinCorner(1:2), 0]; % bind obstacles to floor of domain + + % Randomly select a corresponding maximum corner that + % satisfies min/max obstacle size specifications + candidateMaxCorner = candidateMinCorner + tc.minObstacleSize + rand(1, 3) * (tc.maxObstacleSize - tc.minObstacleSize); + + % Initialize obstacle + tc.obstacles{ii} = tc.obstacles{ii}.initialize([candidateMinCorner; candidateMaxCorner], REGION_TYPE.OBSTACLE, sprintf("Column obstacle %d", ii)); + + % Check if the obstacle intersects with any existing + % obstacles + violation = false; + for kk = 1:(ii - 1) + if geometryIntersects(tc.obstacles{kk}, tc.obstacles{ii}) + violation = true; + break; + end + end + if violation + continue; + end + + % Make sure that the obstacles are fully contained by + % the domain + if ~domainContainsObstacle(tc.domain, tc.obstacles{ii}) + continue; + end + + % Make sure that the obstacles don't cover the sensing + % objective + if obstacleCoversObjective(tc.objective, tc.obstacles{ii}) + continue; + end + + % Make sure that the obstacles aren't too close to the + % sensing objective + if obstacleCrowdsObjective(tc.objective, tc.obstacles{ii}, tc.protectedRange) + continue; + end + + badCandidate = false; + end + end + + % Add agents individually, ensuring that each addition does not + % invalidate the initialization setup + for ii = 1:size(tc.agents, 1) + initInvalid = true; + while initInvalid + candidatePos = [tc.objective.groundPos, 0]; + % Generate a random position for the agent based on + % existing agent positions + if ii == 1 + while agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2) + candidatePos = tc.domain.random(); + end + else + candidatePos = tc.agents{randi(ii - 1)}.pos + sign(randn([1, 3])) .* (rand(1, 3) .* tc.comRange/sqrt(2)); + end + + % Make sure that the candidate position is within the + % domain + if ~tc.domain.contains(candidatePos) + continue; + end + + % Make sure that the candidate position does not crowd + % the sensing objective and create boring scenarios + if agentsCrowdObjective(tc.objective, candidatePos, mean(tc.domain.dimensions) / 2) + continue; + end + + % Make sure that there exist unobstructed lines of sight at + % appropriate ranges to form a connected communications + % graph between the agents + connections = false(1, ii - 1); + for jj = 1:(ii - 1) + if norm(tc.agents{jj}.pos - candidatePos) <= tc.comRange + % Check new agent position against all existing + % agent positions for communications range + connections(jj) = true; + for kk = 1:size(tc.obstacles, 1) + if tc.obstacles{kk}.containsLine(tc.agents{jj}.pos, candidatePos) + connections(jj) = false; + end + end + end + end + + % New agent must be connected to an existing agent to + % be valid + if ii ~= 1 && ~any(connections) + continue; + end + + % Initialize candidate agent + candidateGeometry = rectangularPrism; + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), @(r) 0.5, tc.comRange, ii, sprintf("Agent %d", ii)); + + % Make sure candidate agent doesn't collide with + % domain + violation = false; + for jj = 1:size(newAgent.collisionGeometry.vertices, 1) + % Check if collision geometry exits domain + if ~tc.domain.contains(newAgent.collisionGeometry.vertices(jj, 1:3)) + violation = true; + break; + end + end + if violation + continue; + end + + % Make sure candidate doesn't collide with obstacles + violation = false; + for kk = 1:size(tc.obstacles, 1) + if geometryIntersects(tc.obstacles{kk}, newAgent.collisionGeometry) + violation = true; + break; + end + end + if violation + continue; + end + + % Make sure candidate doesn't collide with existing + % agents + violation = false; + for kk = 1:(ii - 1) + if geometryIntersects(tc.agents{kk}.collisionGeometry, newAgent.collisionGeometry) + violation = true; + break; + end + end + if violation + continue; + end + + % Candidate agent is valid, store to pass in to sim + initInvalid = false; + tc.agents{ii} = newAgent; + end + end + + % Initialize the simulation + tc.testClass = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles); + + % Plot domain + f = tc.testClass.domain.plotWireframe; + + % Set plotting limits to focus on the domain + xlim([tc.testClass.domain.minCorner(1), tc.testClass.domain.maxCorner(1)]); + ylim([tc.testClass.domain.minCorner(2), tc.testClass.domain.maxCorner(2)]); + zlim([tc.testClass.domain.minCorner(3), tc.testClass.domain.maxCorner(3)]); + + % Plot obstacles + for ii = 1:size(tc.testClass.obstacles, 1) + tc.testClass.obstacles{ii}.plotWireframe(f); + end + + % Plot objective gradient + f = tc.testClass.objective.plot(f); + + % Plot agents and their collision geometries + for ii = 1:size(tc.testClass.agents, 1) + f = tc.testClass.agents{ii}.plot(f); + f = tc.testClass.agents{ii}.collisionGeometry.plotWireframe(f); + end + + % Plot communication links + f = tc.testClass.plotNetwork(f); + + % Plot abstract network graph + f = tc.testClass.plotGraph(f); + + % Run simulation loop + tc.testClass.run(); + + end end end \ No newline at end of file From faa8bad596fbfd87971e19820e44b6feb7616929 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 21:29:54 -0700 Subject: [PATCH 11/14] implemented basic gradient ascent --- agent.m | 25 ++++++++++- miSim.m | 28 +++++++----- .../Lzv9PNrakrESxUF7UZmIf8m-ri4d.xml | 2 + .../Lzv9PNrakrESxUF7UZmIf8m-ri4p.xml | 2 + sensingFunctions/basicGradientAscent.m | 43 +++++++++++++++++++ test_miSim.m | 5 ++- 6 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4d.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4p.xml create mode 100644 sensingFunctions/basicGradientAscent.m diff --git a/agent.m b/agent.m index b75af2b..3787afe 100644 --- a/agent.m +++ b/agent.m @@ -6,6 +6,7 @@ classdef agent % Sensor sensingFunction = @(r) 0.5; % probability of detection as a function of range + sensingLength = 0.05; % length parameter used by sensing function % State pos = NaN(1, 3); @@ -20,14 +21,15 @@ classdef agent end methods (Access = public) - function obj = initialize(obj, pos, vel, cBfromC, collisionGeometry, sensingFunction, comRange, index, label) + function obj = initialize(obj, pos, vel, cBfromC, collisionGeometry, sensingFunction, sensingLength, comRange, index, label) arguments (Input) obj (1, 1) {mustBeA(obj, 'agent')}; pos (1, 3) double; vel (1, 3) double; cBfromC (3, 3) double {mustBeDcm}; collisionGeometry (1, 1) {mustBeGeometry}; - sensingFunction (1, 1) {mustBeA(sensingFunction, 'function_handle')} + sensingFunction (1, 1) {mustBeA(sensingFunction, 'function_handle')} = @(r) 0.5; + sensingLength (1, 1) double = NaN; comRange (1, 1) double = NaN; index (1, 1) double = NaN; label (1, 1) string = ""; @@ -40,10 +42,29 @@ classdef agent obj.vel = vel; obj.cBfromC = cBfromC; obj.collisionGeometry = collisionGeometry; + obj.sensingFunction = sensingFunction; + obj.sensingLength = sensingLength; obj.comRange = comRange; obj.index = index; obj.label = label; end + function obj = run(obj, objectiveFunction) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'agent')}; + objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')}; + end + arguments (Output) + obj (1, 1) {mustBeA(obj, 'agent')}; + end + + % Do sensing to determine target position + nextPos = obj.sensingFunction(objectiveFunction, obj.pos, obj.sensingLength); + + % Move to next position + % (dynamics not modeled at this time) + obj.pos = nextPos; + + end function f = plot(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'agent')}; diff --git a/miSim.m b/miSim.m index e60cdff..37cdcea 100644 --- a/miSim.m +++ b/miSim.m @@ -54,17 +54,25 @@ classdef miSim arguments (Output) obj (1, 1) {mustBeA(obj, 'miSim')}; end - keyboard - % Iterate over agents to simulate their motion - for ii = 1:size(obj.agents, 1) - obj.agents{ii} + + % Set up times to iterate over + times = linspace(0, obj.timestep * obj.maxIter, obj.maxIter+1)'; + + for ii = 1:size(times, 1) + % Get current sim time + t = times(ii); + + % Iterate over agents to simulate their motion + for jj = 1:size(obj.agents, 1) + obj.agents{jj} = obj.agents{jj}.run(obj.objective.objectiveFunction); + end + + % Update adjacency matrix + obj = obj.updateAdjacency; + + % Update plots + end - - % Update adjacency matrix - obj = obj.updateAdjacency; - - % Update plots - end function obj = updateAdjacency(obj) arguments (Input) diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4d.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4d.xml new file mode 100644 index 0000000..34af544 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4p.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4p.xml new file mode 100644 index 0000000..0f57430 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Lzv9PNrakrESxUF7UZmIf8m-ri4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/sensingFunctions/basicGradientAscent.m b/sensingFunctions/basicGradientAscent.m new file mode 100644 index 0000000..9889f28 --- /dev/null +++ b/sensingFunctions/basicGradientAscent.m @@ -0,0 +1,43 @@ +function nextPos = basicGradientAscent(objectiveFunction, pos, r) + arguments (Input) + objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')}; + pos (1, 3) double; + r (1, 1) double; + end + arguments (Output) + nextPos(1, 3) double; + end + + % Evaluate objective at position offsets +/-[r, 0, 0] and +/-[0, r, 0] + currentPos = pos(1:2); + neighborPos = [currentPos(1) + r, currentPos(2); ... % (+x) + currentPos(1), currentPos(2) + r; ... % (+y) + currentPos(1) - r, currentPos(2); ... % (-x) + currentPos(1), currentPos(2) - r; ... % (-y) + ]; + + % Check for neighbor positions that fall outside of the domain + outOfBounds = false(size(neighborPos, 1), 1); + for ii = 1:size(neighborPos, 1) + if ~domain.contains([neighborPos(ii, :), 0]) + outOfBounds(ii) = true; + end + end + + % Replace out of bounds positions with inoffensive in-bounds positions + neighborPos(outOfBounds, 1:3) = repmat(pos, sum(outOfBounds), 1); + + % Sense values at selected positions + neighborValues = [objectiveFunction(neighborPos(1, 1), neighborPos(1, 2)), ... % (+x) + objectiveFunction(neighborPos(2, 1), neighborPos(2, 2)), ... % (+y) + objectiveFunction(neighborPos(3, 1), neighborPos(3, 2)), ... % (-x) + objectiveFunction(neighborPos(4, 1), neighborPos(4, 2)), ... % (-y) + ]; + + % Prevent out of bounds locations from ever possibly being selected + neighborValues(outOfBounds) = 0; + + % Select next position by maximum sensed value + nextPos = neighborPos(neighborValues == max(neighborValues), :); + nextPos = nextPos(1, 1:3); % just in case two get selected, simply pick one +end \ No newline at end of file diff --git a/test_miSim.m b/test_miSim.m index f949ac8..3211893 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -22,6 +22,7 @@ classdef test_miSim < matlab.unittest.TestCase % Agents minAgents = 3; % Minimum number of agents to be randomly generated maxAgents = 9; % Maximum number of agents to be randomly generated + sensingLength = 0.05; % length parameter used by sensing function agents = cell(0, 1); % Collision @@ -186,7 +187,7 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize candidate agent candidateGeometry = rectangularPrism; - newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), @(r) 0.5, tc.comRange, ii, sprintf("Agent %d", ii)); + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), @(r) 0.5, tc.sensingLength, tc.comRange, ii, sprintf("Agent %d", ii)); % Make sure candidate agent doesn't collide with % domain @@ -375,7 +376,7 @@ classdef test_miSim < matlab.unittest.TestCase % Initialize candidate agent candidateGeometry = rectangularPrism; - newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), @(r) 0.5, tc.comRange, ii, sprintf("Agent %d", ii)); + newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), eye(3),candidateGeometry.initialize([candidatePos - tc.collisionRanges(ii) * ones(1, 3); candidatePos + tc.collisionRanges(ii) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", ii)), @basicGradientAscent, tc.sensingLength, tc.comRange, ii, sprintf("Agent %d", ii)); % Make sure candidate agent doesn't collide with % domain From 7fb9d13781993f0893535c15cad49a12104f1231 Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 22:38:39 -0700 Subject: [PATCH 12/14] geometries move in plots as sim runs --- agent.m | 64 +++++++++++++++++++++---- firstPlotSetup.m | 10 ++-- geometries/rectangularPrism.m | 21 +++++---- miSim.m | 65 ++++++++++++++++++++++++-- sensingFunctions/basicGradientAscent.m | 5 +- test_miSim.m | 63 ++----------------------- 6 files changed, 139 insertions(+), 89 deletions(-) diff --git a/agent.m b/agent.m index 3787afe..0b1ef5d 100644 --- a/agent.m +++ b/agent.m @@ -9,15 +9,19 @@ classdef agent sensingLength = 0.05; % length parameter used by sensing function % State - pos = NaN(1, 3); - vel = NaN(1, 3); - cBfromC = NaN(3); % DCM body from sim cartesian (assume fixed for now) + lastPos = NaN(1, 3); % position from previous timestep + pos = NaN(1, 3); % current position + vel = NaN(1, 3); % current velocity + cBfromC = NaN(3); % current DCM body from sim cartesian (assume fixed for now) % Collision collisionGeometry; % Communication comRange = NaN; + + % Plotting + scatterPoints; end methods (Access = public) @@ -48,29 +52,66 @@ classdef agent obj.index = index; obj.label = label; end - function obj = run(obj, objectiveFunction) + function obj = run(obj, objectiveFunction, domain) arguments (Input) obj (1, 1) {mustBeA(obj, 'agent')}; objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')}; + domain (1, 1) {mustBeGeometry}; end arguments (Output) obj (1, 1) {mustBeA(obj, 'agent')}; end % Do sensing to determine target position - nextPos = obj.sensingFunction(objectiveFunction, obj.pos, obj.sensingLength); + nextPos = obj.sensingFunction(objectiveFunction, domain, obj.pos, obj.sensingLength); % Move to next position % (dynamics not modeled at this time) + obj.lastPos = obj.pos; obj.pos = nextPos; + % Calculate movement + d = obj.pos - obj.collisionGeometry.center; + + % Reinitialize collision geometry in the new position + obj.collisionGeometry = obj.collisionGeometry.initialize([obj.collisionGeometry.minCorner; obj.collisionGeometry.maxCorner] + d, obj.collisionGeometry.tag, obj.collisionGeometry.label); end - function f = plot(obj, f) + function updatePlots(obj) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'agent')}; + end + arguments (Output) + end + + % Scatterplot point positions + for ii = 1:size(obj.scatterPoints, 1) + obj.scatterPoints(ii).XData = obj.pos(1); + obj.scatterPoints(ii).YData = obj.pos(2); + obj.scatterPoints(ii).ZData = obj.pos(3); + end + + % Find change in agent position since last timestep + deltaPos = obj.pos - obj.lastPos; + + % Collision geometry edges + for jj = 1:size(obj.collisionGeometry.lines, 2) + % Update plotting + for ii = 1:size(obj.collisionGeometry.lines(:, jj), 1) + obj.collisionGeometry.lines(ii, jj).XData = obj.collisionGeometry.lines(ii, jj).XData + deltaPos(1); + obj.collisionGeometry.lines(ii, jj).YData = obj.collisionGeometry.lines(ii, jj).YData + deltaPos(2); + obj.collisionGeometry.lines(ii, jj).ZData = obj.collisionGeometry.lines(ii, jj).ZData + deltaPos(3); + end + end + + % Network connections + end + function [obj, f] = plot(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'agent')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; end arguments (Output) + obj (1, 1) {mustBeA(obj, 'agent')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; end @@ -85,10 +126,15 @@ classdef agent % Check if this is a tiled layout figure if strcmp(f.Children(1).Type, 'tiledlayout') % Add to other perspectives - copyobj(o, f.Children(1).Children(2)); - copyobj(o, f.Children(1).Children(3)); - copyobj(o, f.Children(1).Children(5)); + o = [o; copyobj(o(1), f.Children(1).Children(2))]; + o = [o; copyobj(o(1), f.Children(1).Children(3))]; + o = [o; copyobj(o(1), f.Children(1).Children(5))]; end + + obj.scatterPoints = o; + + % Plot collision geometry + [obj.collisionGeometry, f] = obj.collisionGeometry.plotWireframe(f); end end end \ No newline at end of file diff --git a/firstPlotSetup.m b/firstPlotSetup.m index 3b29be0..422780e 100644 --- a/firstPlotSetup.m +++ b/firstPlotSetup.m @@ -9,7 +9,7 @@ function f = firstPlotSetup(f) grid(f.Children(1).Children(1), "on"); view(f.Children(1).Children(1), 0, 90); xlabel(f.Children(1).Children(1), "X"); ylabel(f.Children(1).Children(1), "Y"); - title("Top-down Perspective"); + title(f.Children(1).Children(1), "Top-down Perspective"); % Communications graph nexttile(3, [1, 1]); @@ -17,33 +17,33 @@ function f = firstPlotSetup(f) axis(f.Children(1).Children(1), "image"); grid(f.Children(1).Children(1), "off"); view(f.Children(1).Children(1), 0, 0); - title("Network Graph"); + title(f.Children(1).Children(1), "Network Graph"); % 3D view - title("3D Perspective"); nexttile(4, [2, 2]); axes(f.Children(1).Children(1)); axis(f.Children(1).Children(1), "image"); grid(f.Children(1).Children(1), "on"); view(f.Children(1).Children(1), 3); xlabel(f.Children(1).Children(1), "X"); ylabel(f.Children(1).Children(1), "Y"); zlabel(f.Children(1).Children(1), "Z"); + title(f.Children(1).Children(1), "3D Perspective"); % Side-on view - title("Side-on Perspective"); nexttile(6, [2, 1]); axes(f.Children(1).Children(1)); axis(f.Children(1).Children(1), "image"); grid(f.Children(1).Children(1), "on"); view(f.Children(1).Children(1), 90, 0); ylabel(f.Children(1).Children(1), "Y"); zlabel(f.Children(1).Children(1), "Z"); + title(f.Children(1).Children(1), "Side-on Perspective"); % Front-on view - title("Front-on Perspective"); nexttile(10, [1, 2]); axes(f.Children(1).Children(1)); axis(f.Children(1).Children(1), "image"); grid(f.Children(1).Children(1), "on"); view(f.Children(1).Children(1), 0, 0); xlabel(f.Children(1).Children(1), "X"); zlabel(f.Children(1).Children(1), "Z"); + title(f.Children(1).Children(1), "Front-on Perspective"); end end \ No newline at end of file diff --git a/geometries/rectangularPrism.m b/geometries/rectangularPrism.m index 8af3d31..c2ebcb2 100644 --- a/geometries/rectangularPrism.m +++ b/geometries/rectangularPrism.m @@ -1,23 +1,25 @@ classdef rectangularPrism % Rectangular prism geometry properties (SetAccess = private, GetAccess = public) + % Meta tag = REGION_TYPE.INVALID; label = ""; + % Spatial minCorner = NaN(1, 3); maxCorner = NaN(1, 3); - dimensions = NaN(1, 3); - center = NaN; + footprint = NaN(4, 2); + % Graph vertices = NaN(8, 3); - edges = [1 2; 2 3; 3 4; 4 1; % bottom square 5 6; 6 8; 8 7; 7 5; % top square 1 5; 2 6; 3 8; 4 7]; % vertical edges - footprint = NaN(4, 2); + % Plotting + lines; end methods (Access = public) @@ -161,12 +163,13 @@ classdef rectangularPrism c = (tmax >= 0) && (tmin <= 1); end - function f = plotWireframe(obj, f) + function [obj, f] = plotWireframe(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; end arguments (Output) + obj (1, 1) {mustBeA(obj, 'rectangularPrism')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; end @@ -186,10 +189,12 @@ classdef rectangularPrism % Check if this is a tiled layout figure if strcmp(f.Children(1).Type, 'tiledlayout') % Add to other perspectives - copyobj(o, f.Children(1).Children(2)); - copyobj(o, f.Children(1).Children(3)); - copyobj(o, f.Children(1).Children(5)); + o = [o, copyobj(o(:, 1), f.Children(1).Children(2))]; + o = [o, copyobj(o(:, 1), f.Children(1).Children(3))]; + o = [o, copyobj(o(:, 1), f.Children(1).Children(5))]; end + + obj.lines = o; end end end \ No newline at end of file diff --git a/miSim.m b/miSim.m index 37cdcea..e28e8e5 100644 --- a/miSim.m +++ b/miSim.m @@ -13,7 +13,7 @@ classdef miSim end methods (Access = public) - function obj = initialize(obj, domain, objective, agents, timestep, maxIter, obstacles) + function [obj, f] = initialize(obj, domain, objective, agents, timestep, maxIter, obstacles) arguments (Input) obj (1, 1) {mustBeA(obj, 'miSim')}; domain (1, 1) {mustBeGeometry}; @@ -25,6 +25,7 @@ classdef miSim end arguments (Output) obj (1, 1) {mustBeA(obj, 'miSim')}; + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; end % Define simulation time parameters @@ -46,33 +47,87 @@ classdef miSim % Compute adjacency matrix obj = obj.updateAdjacency(); + % Set up initial plot + % Set up axes arrangement + % Plot domain + [obj.domain, f] = obj.domain.plotWireframe(); + + % Set plotting limits to focus on the domain + xlim([obj.domain.minCorner(1), obj.domain.maxCorner(1)]); + ylim([obj.domain.minCorner(2), obj.domain.maxCorner(2)]); + zlim([obj.domain.minCorner(3), obj.domain.maxCorner(3)]); + + % Plot obstacles + for ii = 1:size(obj.obstacles, 1) + [obj.obstacles{ii}, f] = obj.obstacles{ii}.plotWireframe(f); + end + + % Plot objective gradient + f = obj.objective.plot(f); + + % Plot agents and their collision geometries + for ii = 1:size(obj.agents, 1) + [obj.agents{ii}, f] = obj.agents{ii}.plot(f); + end + + % Plot communication links + f = obj.plotNetwork(f); + + % Plot abstract network graph + f = obj.plotGraph(f); end - function obj = run(obj) + function [obj, f] = run(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'miSim')}; + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; end arguments (Output) obj (1, 1) {mustBeA(obj, 'miSim')}; + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; end + % Create axes if they don't already exist + f = firstPlotSetup(f); + % Set up times to iterate over times = linspace(0, obj.timestep * obj.maxIter, obj.maxIter+1)'; for ii = 1:size(times, 1) - % Get current sim time + % Display current sim time t = times(ii); + fprintf("Sim Time: %4.2f (%d/%d)\n", t, ii, obj.maxIter) % Iterate over agents to simulate their motion for jj = 1:size(obj.agents, 1) - obj.agents{jj} = obj.agents{jj}.run(obj.objective.objectiveFunction); + obj.agents{jj} = obj.agents{jj}.run(obj.objective.objectiveFunction, obj.domain); end % Update adjacency matrix obj = obj.updateAdjacency; % Update plots - + f = obj.updatePlots(f); end + + end + function f = updatePlots(obj, f) + arguments (Input) + obj (1, 1) {mustBeA(obj, 'miSim')}; + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; + end + arguments (Output) + f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; + end + + % Update agent positions, collision geometries, connections + for ii = 1:size(obj.agents, 1) + obj.agents{ii}.updatePlots(); + end + + % Update network graph plot + + drawnow; + end function obj = updateAdjacency(obj) arguments (Input) diff --git a/sensingFunctions/basicGradientAscent.m b/sensingFunctions/basicGradientAscent.m index 9889f28..003f674 100644 --- a/sensingFunctions/basicGradientAscent.m +++ b/sensingFunctions/basicGradientAscent.m @@ -1,6 +1,7 @@ -function nextPos = basicGradientAscent(objectiveFunction, pos, r) +function nextPos = basicGradientAscent(objectiveFunction, domain, pos, r) arguments (Input) objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')}; + domain (1, 1) {mustBeGeometry}; pos (1, 3) double; r (1, 1) double; end @@ -39,5 +40,5 @@ function nextPos = basicGradientAscent(objectiveFunction, pos, r) % Select next position by maximum sensed value nextPos = neighborPos(neighborValues == max(neighborValues), :); - nextPos = nextPos(1, 1:3); % just in case two get selected, simply pick one + nextPos = [nextPos(1, 1:2), pos(3)]; % just in case two get selected, simply pick one end \ No newline at end of file diff --git a/test_miSim.m b/test_miSim.m index 3211893..b8a3a44 100644 --- a/test_miSim.m +++ b/test_miSim.m @@ -235,35 +235,7 @@ classdef test_miSim < matlab.unittest.TestCase end % Initialize the simulation - tc.testClass = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles); - - % Plot domain - f = tc.testClass.domain.plotWireframe; - - % Set plotting limits to focus on the domain - xlim([tc.testClass.domain.minCorner(1), tc.testClass.domain.maxCorner(1)]); - ylim([tc.testClass.domain.minCorner(2), tc.testClass.domain.maxCorner(2)]); - zlim([tc.testClass.domain.minCorner(3), tc.testClass.domain.maxCorner(3)]); - - % Plot obstacles - for ii = 1:size(tc.testClass.obstacles, 1) - tc.testClass.obstacles{ii}.plotWireframe(f); - end - - % Plot objective gradient - f = tc.testClass.objective.plot(f); - - % Plot agents and their collision geometries - for ii = 1:size(tc.testClass.agents, 1) - f = tc.testClass.agents{ii}.plot(f); - f = tc.testClass.agents{ii}.collisionGeometry.plotWireframe(f); - end - - % Plot communication links - f = tc.testClass.plotNetwork(f); - - % Plot abstract network graph - f = tc.testClass.plotGraph(f); + [tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles); end function misim_run(tc) % randomly create obstacles @@ -424,39 +396,10 @@ classdef test_miSim < matlab.unittest.TestCase end % Initialize the simulation - tc.testClass = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles); - - % Plot domain - f = tc.testClass.domain.plotWireframe; - - % Set plotting limits to focus on the domain - xlim([tc.testClass.domain.minCorner(1), tc.testClass.domain.maxCorner(1)]); - ylim([tc.testClass.domain.minCorner(2), tc.testClass.domain.maxCorner(2)]); - zlim([tc.testClass.domain.minCorner(3), tc.testClass.domain.maxCorner(3)]); - - % Plot obstacles - for ii = 1:size(tc.testClass.obstacles, 1) - tc.testClass.obstacles{ii}.plotWireframe(f); - end - - % Plot objective gradient - f = tc.testClass.objective.plot(f); - - % Plot agents and their collision geometries - for ii = 1:size(tc.testClass.agents, 1) - f = tc.testClass.agents{ii}.plot(f); - f = tc.testClass.agents{ii}.collisionGeometry.plotWireframe(f); - end - - % Plot communication links - f = tc.testClass.plotNetwork(f); - - % Plot abstract network graph - f = tc.testClass.plotGraph(f); + [tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles); % Run simulation loop - tc.testClass.run(); - + [tc.testClass, f] = tc.testClass.run(f); end end end \ No newline at end of file From 0621e0a07a9bdaab5e69f3437d872921f9aea15b Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 23:13:33 -0700 Subject: [PATCH 13/14] added video writing feature --- .gitignore | 3 + miSim.m | 61 +++++++++++++------ .../Zft-eetWhSiBfHeQkgT2iI9nSuId.xml | 2 + .../Zft-eetWhSiBfHeQkgT2iI9nSuIp.xml | 2 + .../ulE9PYd_TlaqYfhxJlcxk9uZKPwd.xml | 2 + .../ulE9PYd_TlaqYfhxJlcxk9uZKPwp.xml | 2 + .../q138eJA8Ym4eSfM3RFMVvg63QtUd.xml | 2 + .../q138eJA8Ym4eSfM3RFMVvg63QtUp.xml | 2 + 8 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuId.xml create mode 100644 resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuIp.xml create mode 100644 resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwd.xml create mode 100644 resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwp.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUd.xml create mode 100644 resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUp.xml diff --git a/.gitignore b/.gitignore index aac549e..7beb566 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ codegen/ # SimBiology backup files *.sbproj.backup *.sbproj.bak + +# Sandbox contents +sandbox/* \ No newline at end of file diff --git a/miSim.m b/miSim.m index e28e8e5..7ba7ab1 100644 --- a/miSim.m +++ b/miSim.m @@ -12,6 +12,12 @@ classdef miSim adjacency = NaN; % Adjacency matrix representing communications network graph end + properties (Access = private) + v = VideoWriter(fullfile('sandbox', strcat(string(datetime('now'), 'yyyy_MM_dd_HH_mm_ss'), '_miSimHist.mp4'))); + connectionsPlot; % objects for lines connecting agents in spatial plots + graphPlot; % objects for abstract network graph plot + end + methods (Access = public) function [obj, f] = initialize(obj, domain, objective, agents, timestep, maxIter, obstacles) arguments (Input) @@ -71,10 +77,10 @@ classdef miSim end % Plot communication links - f = obj.plotNetwork(f); + [obj, f] = obj.plotConnections(f); % Plot abstract network graph - f = obj.plotGraph(f); + [obj, f] = obj.plotGraph(f); end function [obj, f] = run(obj, f) arguments (Input) @@ -92,6 +98,11 @@ classdef miSim % Set up times to iterate over times = linspace(0, obj.timestep * obj.maxIter, obj.maxIter+1)'; + % Start video writer + obj.v.FrameRate = 1/obj.timestep; + obj.v.Quality = 90; + obj.v.open(); + for ii = 1:size(times, 1) % Display current sim time t = times(ii); @@ -106,28 +117,44 @@ classdef miSim obj = obj.updateAdjacency; % Update plots - f = obj.updatePlots(f); + [obj, f] = obj.updatePlots(f); + + % Write frame in to video + I = getframe(f); + obj.v.writeVideo(I); end + % Close video file + obj.v.close(); end - function f = updatePlots(obj, f) + function [obj, f] = updatePlots(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'miSim')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; end arguments (Output) + obj (1, 1) {mustBeA(obj, 'miSim')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; end - % Update agent positions, collision geometries, connections + % Update agent positions, collision geometries for ii = 1:size(obj.agents, 1) obj.agents{ii}.updatePlots(); end + % The remaining updates might be possible to do in a clever way + % that moves existing lines instead of clearing and + % re-plotting, which is much better for performance boost + + % Update agent connections plot + delete(obj.connectionsPlot); + [obj, f] = obj.plotConnections(f); + % Update network graph plot + delete(obj.graphPlot); + [obj, f] = obj.plotGraph(f); drawnow; - end function obj = updateAdjacency(obj) arguments (Input) @@ -157,12 +184,13 @@ classdef miSim obj.adjacency = A | A'; end - function f = plotNetwork(obj, f) + function [obj, f] = plotConnections(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'miSim')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; end arguments (Output) + obj (1, 1) {mustBeA(obj, 'miSim')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; end @@ -188,29 +216,28 @@ classdef miSim % Check if this is a tiled layout figure if strcmp(f.Children(1).Type, 'tiledlayout') % Add to other plots - copyobj(o, f.Children(1).Children(2)); - copyobj(o, f.Children(1).Children(3)); - copyobj(o, f.Children(1).Children(5)); + o = [o, copyobj(o(:, 1), f.Children(1).Children(2))]; + o = [o, copyobj(o(:, 1), f.Children(1).Children(3))]; + o = [o, copyobj(o(:, 1), f.Children(1).Children(5))]; end + + obj.connectionsPlot = o; end - function f = plotGraph(obj, f) + function [obj, f] = plotGraph(obj, f) arguments (Input) obj (1, 1) {mustBeA(obj, 'miSim')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure; end arguments (Output) + obj (1, 1) {mustBeA(obj, 'miSim')}; f (1, 1) {mustBeA(f, 'matlab.ui.Figure')}; end % Form graph from adjacency matrix G = graph(obj.adjacency, 'omitselfloops'); - % Check if this is a tiled layout figure - if strcmp(f.Children(1).Type, 'tiledlayout') - o = plot(f.Children(1).Children(4), G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2); - else - o = plot(f.CurrentAxes, G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2); - end + % Plot graph object + obj.graphPlot = plot(f.Children(1).Children(4), G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2); end end diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuId.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuId.xml new file mode 100644 index 0000000..4f38380 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuIp.xml b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuIp.xml new file mode 100644 index 0000000..63aea22 --- /dev/null +++ b/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/Zft-eetWhSiBfHeQkgT2iI9nSuIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwd.xml b/resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwp.xml b/resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwp.xml new file mode 100644 index 0000000..01cb34e --- /dev/null +++ b/resources/project/q138eJA8Ym4eSfM3RFMVvg63QtU/ulE9PYd_TlaqYfhxJlcxk9uZKPwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUd.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUd.xml new file mode 100644 index 0000000..4356a6a --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUp.xml b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUp.xml new file mode 100644 index 0000000..baaf30c --- /dev/null +++ b/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/q138eJA8Ym4eSfM3RFMVvg63QtUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 2b58646acae241537e508ee250b1a71fab3162fa Mon Sep 17 00:00:00 2001 From: Kevin D Date: Mon, 27 Oct 2025 23:16:25 -0700 Subject: [PATCH 14/14] fixed filename --- miSim.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miSim.m b/miSim.m index 7ba7ab1..3317ecf 100644 --- a/miSim.m +++ b/miSim.m @@ -13,7 +13,7 @@ classdef miSim end properties (Access = private) - v = VideoWriter(fullfile('sandbox', strcat(string(datetime('now'), 'yyyy_MM_dd_HH_mm_ss'), '_miSimHist.mp4'))); + v = VideoWriter(fullfile('sandbox', strcat(string(datetime('now'), 'yyyy_MM_dd_HH_mm_ss'), '_miSimHist'))); connectionsPlot; % objects for lines connecting agents in spatial plots graphPlot; % objects for abstract network graph plot end