diff --git a/EastCampusLiteV4.gml b/EastCampusLiteV4.gml deleted file mode 100644 index 87be4bcd..00000000 --- a/EastCampusLiteV4.gml +++ /dev/null @@ -1,3200 +0,0 @@ -graph [ - directed 1 - node [ - id 0 - label "R_Node:172" - active 0 - pos 36.85892184575399 - pos 17.077014287312828 - ] - node [ - id 1 - label "R_Node:175" - active 0 - pos 41.85546429951986 - pos 20.636311848958336 - ] - node [ - id 2 - label "R_Node:129" - active 0 - pos 212.161376953125 - pos 141.32177734375 - ] - node [ - id 3 - label "R_Node:174" - active 0 - pos 40.18995014826457 - pos 19.449879328409832 - ] - node [ - id 4 - label "R_Node:258" - active 0 - pos 27.437116622924805 - pos 13.336549758911133 - ] - node [ - id 5 - label "R_Node:177" - active 0 - pos 45.18649260203044 - pos 23.00917689005534 - ] - node [ - id 6 - label "R_Node:246" - active 0 - pos 46.160543714250835 - pos 31.095536913190568 - ] - node [ - id 7 - label "R_Node:250" - active 0 - pos 42.37858581542969 - pos 22.35539182027181 - ] - node [ - id 8 - label "R_Node:251" - active 0 - pos 40.4602165222168 - pos 20.564404169718426 - ] - node [ - id 9 - label "R_Node:252" - active 0 - pos 38.541847229003906 - pos 18.77341651916504 - ] - node [ - id 10 - label "R_Node:176" - active 0 - pos 43.52097845077515 - pos 21.822744369506836 - ] - node [ - id 11 - label "R_Node:254" - active 0 - pos 35.1614803314209 - pos 17.148366165161132 - ] - node [ - id 12 - label "R_Node:255" - active 0 - pos 33.23038940429687 - pos 16.19541206359863 - ] - node [ - id 13 - label "R_Node:256" - active 0 - pos 31.29929847717285 - pos 15.242457962036132 - ] - node [ - id 14 - label "R_Node:257" - active 0 - pos 29.36820755004883 - pos 14.289503860473634 - ] - node [ - id 15 - label "R_Node:153" - active 0 - pos 74.57064819335938 - pos 135.58511352539062 - ] - node [ - id 16 - label "R_Node:152" - active 0 - pos 87.55392456054688 - pos 131.78089904785156 - ] - node [ - id 17 - label "R_Node:151" - active 0 - pos 127.93462371826172 - pos 116.86445617675781 - ] - node [ - id 18 - label "R_Node:150" - active 0 - pos 127.51367950439453 - pos 127.16743469238281 - ] - node [ - id 19 - label "R_Node:157" - active 0 - pos 62.76912307739258 - pos 124.16730499267578 - ] - node [ - id 20 - label "R_Node:156" - active 0 - pos 62.997310638427734 - pos 130.343505859375 - ] - node [ - id 21 - label "R_Node:155" - active 0 - pos 62.744781494140625 - pos 136.39981079101562 - ] - node [ - id 22 - label "R_Node:154" - active 0 - pos 66.09662628173828 - pos 140.23387145996094 - ] - node [ - id 23 - label "R_Node:159" - active 0 - pos 62.36149597167969 - pos 112.84590148925781 - ] - node [ - id 24 - label "R_Node:158" - active 0 - pos 62.53026580810547 - pos 118.29088592529297 - ] - node [ - id 25 - label "R_Node:242" - active 0 - pos 46.904314858572825 - pos 39.40179170880999 - ] - node [ - id 26 - label "R_Node:236" - active 0 - pos 48.019971575055806 - pos 51.861173902239116 - ] - node [ - id 27 - label "R_Node:240" - active 0 - pos 47.276200430733816 - pos 43.5549191066197 - ] - node [ - id 28 - label "R_Node:126" - active 0 - pos 205.57742309570312 - pos 139.0648193359375 - ] - node [ - id 29 - label "R_Node:127" - active 0 - pos 207.92601013183594 - pos 139.86581420898438 - ] - node [ - id 30 - label "R_Node:124" - active 0 - pos 201.7657928466797 - pos 137.75791931152344 - ] - node [ - id 31 - label "R_Node:237" - active 0 - pos 47.83402878897531 - pos 49.78461020333426 - ] - node [ - id 32 - label "R_Node:125" - active 0 - pos 203.6590576171875 - pos 138.41526794433594 - ] - node [ - id 33 - label "R_Node:249" - active 0 - pos 44.29695510864258 - pos 24.146379470825195 - ] - node [ - id 34 - label "R_Node:248" - active 0 - pos 45.788658142089844 - pos 26.94240951538086 - ] - node [ - id 35 - label "R_Node:247" - active 0 - pos 45.97460092817034 - pos 29.01897321428571 - ] - node [ - id 36 - label "R_Node:122" - active 0 - pos 197.14239501953125 - pos 136.17918395996094 - ] - node [ - id 37 - label "R_Node:245" - active 0 - pos 46.34648650033133 - pos 33.17210061209542 - ] - node [ - id 38 - label "R_Node:169" - active 0 - pos 31.862379391988117 - pos 13.517716725667318 - ] - node [ - id 39 - label "R_Node:243" - active 0 - pos 46.71837207249233 - pos 37.32522800990513 - ] - node [ - id 40 - label "R_Node:216" - active 0 - pos 56.86594990321568 - pos 95.38580213274274 - ] - node [ - id 41 - label "R_Node:241" - active 0 - pos 47.09025764465332 - pos 41.478355407714844 - ] - node [ - id 42 - label "R_Node:123" - active 0 - pos 199.4720001220703 - pos 136.99835205078125 - ] - node [ - id 43 - label "R_Node:97" - active 0 - pos 144.37139892578125 - pos 117.93341064453125 - ] - node [ - id 44 - label "R_Node:96" - active 0 - pos 142.03541564941406 - pos 117.09336853027344 - ] - node [ - id 45 - label "R_Node:95" - active 0 - pos 139.6620330810547 - pos 116.3309326171875 - ] - node [ - id 46 - label "R_Node:94" - active 0 - pos 137.30259704589844 - pos 115.70829010009766 - ] - node [ - id 47 - label "R_Node:93" - active 0 - pos 134.86337280273438 - pos 115.23493957519531 - ] - node [ - id 48 - label "R_Node:92" - active 0 - pos 132.88206481933594 - pos 114.9500503540039 - ] - node [ - id 49 - label "R_Node:91" - active 0 - pos 130.88577270507812 - pos 114.79431915283203 - ] - node [ - id 50 - label "R_Node:90" - active 0 - pos 128.88699340820312 - pos 114.71823120117188 - ] - node [ - id 51 - label "R_Node:121" - active 0 - pos 195.22164916992188 - pos 135.53895568847656 - ] - node [ - id 52 - label "R_Node:99" - active 0 - pos 148.95623779296875 - pos 119.71843719482422 - ] - node [ - id 53 - label "R_Node:98" - active 0 - pos 146.67117309570312 - pos 118.83965301513672 - ] - node [ - id 54 - label "R_Node:209" - active 0 - pos 57.692172459193635 - pos 90.76302773611886 - ] - node [ - id 55 - label "R_Node:11" - active 0 - pos 24.81735610961914 - pos 10.96833324432373 - ] - node [ - id 56 - label "R_Node:10" - active 0 - pos 22.611421585083008 - pos 10.346707344055176 - ] - node [ - id 57 - label "R_Node:208" - active 0 - pos 56.97021320887974 - pos 88.80300685337612 - ] - node [ - id 58 - label "R_Node:167" - active 0 - pos 28.53135108947754 - pos 11.144851684570312 - ] - node [ - id 59 - label "R_Node:88" - active 0 - pos 124.84341430664062 - pos 114.89605712890625 - ] - node [ - id 60 - label "R_Node:89" - active 0 - pos 126.86002349853516 - pos 114.72852325439453 - ] - node [ - id 61 - label "R_Node:244" - active 0 - pos 46.53242928641183 - pos 35.248664311000276 - ] - node [ - id 62 - label "R_Node:128" - active 0 - pos 209.8089141845703 - pos 140.5406494140625 - ] - node [ - id 63 - label "R_Node:80" - active 0 - pos 107.35012817382812 - pos 118.9886703491211 - ] - node [ - id 64 - label "R_Node:81" - active 0 - pos 109.29534912109375 - pos 118.47537994384766 - ] - node [ - id 65 - label "R_Node:82" - active 0 - pos 111.63228607177734 - pos 117.79683685302734 - ] - node [ - id 66 - label "R_Node:83" - active 0 - pos 114.03765106201172 - pos 117.1289291381836 - ] - node [ - id 67 - label "R_Node:84" - active 0 - pos 116.42974090576172 - pos 116.4520034790039 - ] - node [ - id 68 - label "R_Node:85" - active 0 - pos 118.7590103149414 - pos 115.83805084228516 - ] - node [ - id 69 - label "R_Node:86" - active 0 - pos 120.77393341064453 - pos 115.4172134399414 - ] - node [ - id 70 - label "R_Node:87" - active 0 - pos 122.83879089355469 - pos 115.08295440673828 - ] - node [ - id 71 - label "R_Node:135" - active 0 - pos 225.37648010253906 - pos 145.98486328125 - ] - node [ - id 72 - label "R_Node:134" - active 0 - pos 223.47389221191406 - pos 145.31536865234375 - ] - node [ - id 73 - label "R_Node:137" - active 0 - pos 229.45050048828125 - pos 147.4447784423828 - ] - node [ - id 74 - label "R_Node:136" - active 0 - pos 227.44236755371094 - pos 146.7117919921875 - ] - node [ - id 75 - label "R_Node:131" - active 0 - pos 216.79237365722656 - pos 142.98812866210938 - ] - node [ - id 76 - label "R_Node:130" - active 0 - pos 214.5050811767578 - pos 142.1568603515625 - ] - node [ - id 77 - label "R_Node:133" - active 0 - pos 221.36578369140625 - pos 144.59803771972656 - ] - node [ - id 78 - label "R_Node:132" - active 0 - pos 219.1042022705078 - pos 143.80979919433594 - ] - node [ - id 79 - label "R_Node:232" - active 0 - pos 48.92604217529297 - pos 60.30195007324219 - ] - node [ - id 80 - label "R_Node:233" - active 0 - pos 48.668678283691406 - pos 58.30877685546875 - ] - node [ - id 81 - label "R_Node:230" - active 0 - pos 49.44076995849609 - pos 64.28829650878906 - ] - node [ - id 82 - label "R_Node:231" - active 0 - pos 49.183406066894534 - pos 62.29512329101563 - ] - node [ - id 83 - label "R_Node:139" - active 0 - pos 233.42654418945312 - pos 148.9989776611328 - ] - node [ - id 84 - label "R_Node:138" - active 0 - pos 231.49647521972656 - pos 148.26290893554688 - ] - node [ - id 85 - label "R_Node:234" - active 0 - pos 48.3918571472168 - pos 56.01430130004883 - ] - node [ - id 86 - label "R_Node:235" - active 0 - pos 48.2059143611363 - pos 53.93773760114397 - ] - node [ - id 87 - label "R_Node:173" - active 0 - pos 38.52443599700928 - pos 18.263446807861328 - ] - node [ - id 88 - label "R_Node:180" - active 0 - pos 48.754188537597656 - pos 28.451602935791016 - ] - node [ - id 89 - label "R_Node:181" - active 0 - pos 48.873538970947266 - pos 30.452623639787948 - ] - node [ - id 90 - label "R_Node:182" - active 0 - pos 48.992889404296875 - pos 32.45364434378488 - ] - node [ - id 91 - label "R_Node:183" - active 0 - pos 49.112239837646484 - pos 34.45466504778181 - ] - node [ - id 92 - label "R_Node:184" - active 0 - pos 49.231590270996094 - pos 36.45568575177874 - ] - node [ - id 93 - label "R_Node:185" - active 0 - pos 49.3509407043457 - pos 38.456706455775674 - ] - node [ - id 94 - label "R_Node:186" - active 0 - pos 49.47029113769531 - pos 40.4577271597726 - ] - node [ - id 95 - label "R_Node:187" - active 0 - pos 49.58964157104492 - pos 42.45874786376953 - ] - node [ - id 96 - label "R_Node:188" - active 0 - pos 49.70899200439453 - pos 44.45976856776646 - ] - node [ - id 97 - label "R_Node:189" - active 0 - pos 49.82834243774414 - pos 46.460789271763396 - ] - node [ - id 98 - label "R_Node:108" - active 0 - pos 167.94996643066406 - pos 126.34739685058594 - ] - node [ - id 99 - label "R_Node:109" - active 0 - pos 169.85992431640625 - pos 126.98471069335938 - ] - node [ - id 100 - label "R_Node:100" - active 0 - pos 150.85183715820312 - pos 120.40372467041016 - ] - node [ - id 101 - label "R_Node:101" - active 0 - pos 153.23667907714844 - pos 121.21746826171875 - ] - node [ - id 102 - label "R_Node:102" - active 0 - pos 155.14755249023438 - pos 121.89105224609375 - ] - node [ - id 103 - label "R_Node:103" - active 0 - pos 157.07484436035156 - pos 122.57482147216797 - ] - node [ - id 104 - label "R_Node:104" - active 0 - pos 158.97669982910156 - pos 123.2376937866211 - ] - node [ - id 105 - label "R_Node:105" - active 0 - pos 161.34388732910156 - pos 124.05858612060547 - ] - node [ - id 106 - label "R_Node:106" - active 0 - pos 163.71536254882812 - pos 124.89189147949219 - ] - node [ - id 107 - label "R_Node:107" - active 0 - pos 165.61778259277344 - pos 125.5633773803711 - ] - node [ - id 108 - label "R_Node:229" - active 0 - pos 49.698133850097655 - pos 66.2814697265625 - ] - node [ - id 109 - label "R_Node:228" - active 0 - pos 49.95549774169922 - pos 68.27464294433594 - ] - node [ - id 110 - label "R_Node:221" - active 0 - pos 53.337608337402344 - pos 85.12073516845703 - ] - node [ - id 111 - label "R_Node:220" - active 0 - pos 54.04327665056501 - pos 87.17374856131417 - ] - node [ - id 112 - label "R_Node:223" - active 0 - pos 52.32830581665039 - pos 80.42354125976563 - ] - node [ - id 113 - label "R_Node:222" - active 0 - pos 52.85615921020508 - pos 82.7434310913086 - ] - node [ - id 114 - label "R_Node:225" - active 0 - pos 51.27259902954101 - pos 75.78376159667968 - ] - node [ - id 115 - label "R_Node:224" - active 0 - pos 51.800452423095706 - pos 78.10365142822266 - ] - node [ - id 116 - label "R_Node:227" - active 0 - pos 50.21689224243164 - pos 71.14398193359375 - ] - node [ - id 117 - label "R_Node:226" - active 0 - pos 50.74474563598633 - pos 73.46387176513672 - ] - node [ - id 118 - label "R_Node:75" - active 0 - pos 95.37141418457031 - pos 120.68218994140625 - ] - node [ - id 119 - label "R_Node:74" - active 0 - pos 92.95496368408203 - pos 120.5523910522461 - ] - node [ - id 120 - label "R_Node:77" - active 0 - pos 100.25975799560547 - pos 120.49601745605469 - ] - node [ - id 121 - label "R_Node:76" - active 0 - pos 97.84554290771484 - pos 120.74671936035156 - ] - node [ - id 122 - label "R_Node:71" - active 0 - pos 86.01351928710938 - pos 119.37199401855469 - ] - node [ - id 123 - label "R_Node:70" - active 0 - pos 83.77678680419922 - pos 118.71979522705078 - ] - node [ - id 124 - label "R_Node:73" - active 0 - pos 90.56732177734375 - pos 120.32624053955078 - ] - node [ - id 125 - label "R_Node:72" - active 0 - pos 88.24047088623047 - pos 119.89970397949219 - ] - node [ - id 126 - label "R_Node:79" - active 0 - pos 105.03081512451172 - pos 119.5119857788086 - ] - node [ - id 127 - label "R_Node:78" - active 0 - pos 102.64038848876953 - pos 120.06380462646484 - ] - node [ - id 128 - label "R_Node:197" - active 0 - pos 51.500187683105466 - pos 64.12092590332031 - ] - node [ - id 129 - label "R_Node:196" - active 0 - pos 51.11942329406738 - pos 61.985361099243164 - ] - node [ - id 130 - label "R_Node:195" - active 0 - pos 50.7386589050293 - pos 59.849796295166016 - ] - node [ - id 131 - label "R_Node:194" - active 0 - pos 50.42509460449219 - pos 56.46589279174805 - ] - node [ - id 132 - label "R_Node:193" - active 0 - pos 50.30574417114258 - pos 54.46487208775112 - ] - node [ - id 133 - label "R_Node:192" - active 0 - pos 50.18639373779297 - pos 52.46385138375419 - ] - node [ - id 134 - label "R_Node:191" - active 0 - pos 50.06704330444336 - pos 50.46283067975726 - ] - node [ - id 135 - label "R_Node:190" - active 0 - pos 49.94769287109375 - pos 48.461809975760325 - ] - node [ - id 136 - label "R_Node:199" - active 0 - pos 52.26171646118164 - pos 68.39205551147461 - ] - node [ - id 137 - label "R_Node:198" - active 0 - pos 51.88095207214356 - pos 66.25649070739746 - ] - node [ - id 138 - label "R_Node:119" - active 0 - pos 190.9514923095703 - pos 134.0975799560547 - ] - node [ - id 139 - label "R_Node:118" - active 0 - pos 188.60523986816406 - pos 133.28880310058594 - ] - node [ - id 140 - label "R_Node:117" - active 0 - pos 186.25982666015625 - pos 132.5243682861328 - ] - node [ - id 141 - label "R_Node:116" - active 0 - pos 183.90382385253906 - pos 131.72488403320312 - ] - node [ - id 142 - label "R_Node:115" - active 0 - pos 181.5365447998047 - pos 130.93260192871094 - ] - node [ - id 143 - label "R_Node:114" - active 0 - pos 179.6199951171875 - pos 130.27706909179688 - ] - node [ - id 144 - label "R_Node:113" - active 0 - pos 177.69375610351562 - pos 129.64181518554688 - ] - node [ - id 145 - label "R_Node:112" - active 0 - pos 175.70069885253906 - pos 128.9686737060547 - ] - node [ - id 146 - label "R_Node:111" - active 0 - pos 173.7199249267578 - pos 128.29908752441406 - ] - node [ - id 147 - label "R_Node:110" - active 0 - pos 171.75375366210938 - pos 127.64253997802734 - ] - node [ - id 148 - label "R_Node:218" - active 0 - pos 55.45461327689035 - pos 91.27977534702846 - ] - node [ - id 149 - label "R_Node:219" - active 0 - pos 54.74894496372768 - pos 89.22676195417132 - ] - node [ - id 150 - label "R_Node:214" - active 0 - pos 58.277286529541016 - pos 99.49182891845703 - ] - node [ - id 151 - label "R_Node:215" - active 0 - pos 57.57161821637835 - pos 97.43881552559989 - ] - node [ - id 152 - label "R_Node:120" - active 0 - pos 192.8698272705078 - pos 134.75054931640625 - ] - node [ - id 153 - label "R_Node:217" - active 0 - pos 56.16028159005301 - pos 93.3327887398856 - ] - node [ - id 154 - label "R_Node:210" - active 0 - pos 58.41413170950754 - pos 92.72304861886161 - ] - node [ - id 155 - label "R_Node:211" - active 0 - pos 59.13609095982143 - pos 94.68306950160435 - ] - node [ - id 156 - label "R_Node:212" - active 0 - pos 59.858050210135325 - pos 96.64309038434709 - ] - node [ - id 157 - label "R_Node:213" - active 0 - pos 60.58000946044922 - pos 98.60311126708984 - ] - node [ - id 158 - label "R_Node:66" - active 0 - pos 75.40181732177734 - pos 114.78266906738281 - ] - node [ - id 159 - label "R_Node:67" - active 0 - pos 77.40827178955078 - pos 115.93681335449219 - ] - node [ - id 160 - label "R_Node:64" - active 0 - pos 71.57231140136719 - pos 112.16053771972656 - ] - node [ - id 161 - label "R_Node:65" - active 0 - pos 73.42894744873047 - pos 113.50651550292969 - ] - node [ - id 162 - label "R_Node:62" - active 0 - pos 67.9829330444336 - pos 109.18582153320312 - ] - node [ - id 163 - label "R_Node:63" - active 0 - pos 69.7397689819336 - pos 110.71794891357422 - ] - node [ - id 164 - label "R_Node:60" - active 0 - pos 64.87171936035156 - pos 105.78549194335938 - ] - node [ - id 165 - label "R_Node:61" - active 0 - pos 66.38858032226562 - pos 107.52010345458984 - ] - node [ - id 166 - label "R_Node:68" - active 0 - pos 79.46025848388672 - pos 116.9792709350586 - ] - node [ - id 167 - label "R_Node:69" - active 0 - pos 81.573974609375 - pos 117.91546630859375 - ] - node [ - id 168 - label "R_Node:9" - active 0 - pos 20.688304901123047 - pos 9.7810697555542 - ] - node [ - id 169 - label "R_Node:8" - active 0 - pos 18.5693359375 - pos 9.118142127990723 - ] - node [ - id 170 - label "R_Node:253" - active 0 - pos 37.09257125854492 - pos 18.101320266723633 - ] - node [ - id 171 - label "R_Node:3" - active 0 - pos 8.485836029052734 - pos 3.9599599838256836 - ] - node [ - id 172 - label "R_Node:2" - active 0 - pos 6.710972785949707 - pos 2.7150332927703857 - ] - node [ - id 173 - label "R_Node:1" - active 0 - pos 4.935946464538574 - pos 1.4794938564300537 - ] - node [ - id 174 - label "R_Node:0" - active 0 - pos 3.1503920555114746 - pos 0.5402687191963196 - ] - node [ - id 175 - label "R_Node:7" - active 0 - pos 16.40631866455078 - pos 8.319733619689941 - ] - node [ - id 176 - label "R_Node:6" - active 0 - pos 14.303437232971191 - pos 7.350276470184326 - ] - node [ - id 177 - label "R_Node:5" - active 0 - pos 12.293851852416992 - pos 6.330555438995361 - ] - node [ - id 178 - label "R_Node:4" - active 0 - pos 10.407621383666992 - pos 5.224569797515869 - ] - node [ - id 179 - label "R_Node:171" - active 0 - pos 35.193407694498696 - pos 15.890581766764324 - ] - node [ - id 180 - label "R_Node:203" - active 0 - pos 53.78477401733399 - pos 76.9343147277832 - ] - node [ - id 181 - label "R_Node:202" - active 0 - pos 53.404009628295896 - pos 74.79874992370605 - ] - node [ - id 182 - label "R_Node:59" - active 0 - pos 63.43403244018555 - pos 104.0111083984375 - ] - node [ - id 183 - label "R_Node:58" - active 0 - pos 62.10154724121094 - pos 102.12691497802734 - ] - node [ - id 184 - label "R_Node:207" - active 0 - pos 56.24825395856585 - pos 86.84298597063336 - ] - node [ - id 185 - label "R_Node:206" - active 0 - pos 55.52629470825195 - pos 84.88296508789062 - ] - node [ - id 186 - label "R_Node:205" - active 0 - pos 54.546302795410156 - pos 81.2054443359375 - ] - node [ - id 187 - label "R_Node:204" - active 0 - pos 54.16553840637207 - pos 79.06987953186035 - ] - node [ - id 188 - label "R_Node:163" - active 0 - pos 9.328222274780273 - pos 0.08156789094209671 - ] - node [ - id 189 - label "R_Node:160" - active 0 - pos 62.51338195800781 - pos 109.39071655273438 - ] - node [ - id 190 - label "R_Node:161" - active 0 - pos 22.66044044494629 - pos 4.209108829498291 - ] - node [ - id 191 - label "R_Node:166" - active 0 - pos 22.56236457824707 - pos 0.592990517616272 - ] - node [ - id 192 - label "R_Node:164" - active 0 - pos 13.247344970703125 - pos -3.6120378971099854 - ] - node [ - id 193 - label "R_Node:168" - active 0 - pos 30.19686524073283 - pos 12.331284205118815 - ] - node [ - id 194 - label "R_Node:179" - active 0 - pos 48.517520904541016 - pos 25.382041931152344 - ] - node [ - id 195 - label "R_Node:178" - active 0 - pos 46.85200675328573 - pos 24.195609410603844 - ] - node [ - id 196 - label "R_Node:201" - active 0 - pos 53.02324523925781 - pos 72.6631851196289 - ] - node [ - id 197 - label "R_Node:165" - active 0 - pos 19.836017608642578 - pos -2.8733162879943848 - ] - node [ - id 198 - label "R_Node:238" - active 0 - pos 47.64808600289481 - pos 47.708046504429404 - ] - node [ - id 199 - label "R_Node:239" - active 0 - pos 47.46214321681431 - pos 45.631482805524556 - ] - node [ - id 200 - label "R_Node:200" - active 0 - pos 52.64248085021973 - pos 70.52762031555176 - ] - node [ - id 201 - label "R_Node:148" - active 0 - pos 126.97246551513672 - pos 139.7107391357422 - ] - node [ - id 202 - label "R_Node:149" - active 0 - pos 127.31443786621094 - pos 133.76632690429688 - ] - node [ - id 203 - label "R_Node:144" - active 0 - pos 109.34207153320312 - pos 135.46420288085938 - ] - node [ - id 204 - label "R_Node:145" - active 0 - pos 115.02513122558594 - pos 138.55552673339844 - ] - node [ - id 205 - label "R_Node:146" - active 0 - pos 122.10986328125 - pos 143.45484924316406 - ] - node [ - id 206 - label "R_Node:147" - active 0 - pos 126.17327880859375 - pos 144.59207153320312 - ] - node [ - id 207 - label "R_Node:141" - active 0 - pos 94.5787353515625 - pos 125.63873291015625 - ] - node [ - id 208 - label "R_Node:142" - active 0 - pos 94.33634185791016 - pos 130.40090942382812 - ] - node [ - id 209 - label "R_Node:143" - active 0 - pos 102.3397216796875 - pos 132.2660369873047 - ] - node [ - id 210 - label "R_Node:170" - active 0 - pos 33.52789354324341 - pos 14.70414924621582 - ] - edge [ - source 0 - target 87 - weight 2.0448861860374254 - ] - edge [ - source 1 - target 10 - weight 2.0448861860374254 - ] - edge [ - source 2 - target 76 - weight 2.4880339864663137 - ] - edge [ - source 2 - target 62 - weight 2.4787581406772756 - ] - edge [ - source 3 - target 1 - weight 2.0448861860374272 - ] - edge [ - source 4 - target 55 - weight 3.531514491976503 - ] - edge [ - source 5 - target 195 - weight 2.0448861860374272 - ] - edge [ - source 6 - target 35 - weight 2.084872062095129 - ] - edge [ - source 7 - target 8 - weight 2.624457564826845 - ] - edge [ - source 8 - target 9 - weight 2.624457564826847 - ] - edge [ - source 9 - target 170 - weight 1.597533790282889 - ] - edge [ - source 10 - target 5 - weight 2.044886186037433 - ] - edge [ - source 11 - target 12 - weight 2.153423713184546 - ] - edge [ - source 12 - target 13 - weight 2.153423713184542 - ] - edge [ - source 13 - target 14 - weight 2.153423713184542 - ] - edge [ - source 14 - target 4 - weight 2.153423713184546 - ] - edge [ - source 15 - target 16 - weight 13.529135708458513 - ] - edge [ - source 15 - target 22 - weight 9.66540209680202 - ] - edge [ - source 16 - target 15 - weight 13.529135708458513 - ] - edge [ - source 16 - target 208 - weight 6.921383948169974 - ] - edge [ - source 17 - target 60 - weight 2.391019673919837 - ] - edge [ - source 17 - target 18 - weight 10.311574095385176 - ] - edge [ - source 17 - target 49 - weight 3.604822830627851 - ] - edge [ - source 18 - target 17 - weight 10.311574095385176 - ] - edge [ - source 18 - target 202 - weight 6.6018993975102465 - ] - edge [ - source 19 - target 24 - weight 5.881271448470269 - ] - edge [ - source 19 - target 20 - weight 6.180414768349075 - ] - edge [ - source 20 - target 19 - weight 6.180414768349075 - ] - edge [ - source 20 - target 21 - weight 6.061567486527633 - ] - edge [ - source 21 - target 20 - weight 6.061567486527633 - ] - edge [ - source 21 - target 22 - weight 5.092630429679632 - ] - edge [ - source 22 - target 15 - weight 9.66540209680202 - ] - edge [ - source 22 - target 21 - weight 5.092630429679632 - ] - edge [ - source 23 - target 189 - weight 3.458521692634201 - ] - edge [ - source 23 - target 24 - weight 5.447599358098232 - ] - edge [ - source 24 - target 23 - weight 5.447599358098232 - ] - edge [ - source 24 - target 19 - weight 5.881271448470269 - ] - edge [ - source 25 - target 39 - weight 2.084872062095129 - ] - edge [ - source 26 - target 31 - weight 2.084872062095129 - ] - edge [ - source 27 - target 41 - weight 2.084872062095129 - ] - edge [ - source 28 - target 29 - weight 2.4814217402405596 - ] - edge [ - source 28 - target 32 - weight 2.0253501226928665 - ] - edge [ - source 29 - target 28 - weight 2.4814217402405596 - ] - edge [ - source 29 - target 62 - weight 2.000182548123138 - ] - edge [ - source 30 - target 32 - weight 2.0041354036857046 - ] - edge [ - source 30 - target 42 - weight 2.416283817572408 - ] - edge [ - source 31 - target 198 - weight 2.0848720620951293 - ] - edge [ - source 32 - target 28 - weight 2.0253501226928665 - ] - edge [ - source 32 - target 30 - weight 2.0041354036857046 - ] - edge [ - source 33 - target 7 - weight 2.624457564826847 - ] - edge [ - source 34 - target 33 - weight 3.169063260658222 - ] - edge [ - source 35 - target 34 - weight 2.084872062095125 - ] - edge [ - source 36 - target 42 - weight 2.4694323831184835 - ] - edge [ - source 36 - target 51 - weight 2.0246374634485824 - ] - edge [ - source 37 - target 6 - weight 2.084872062095125 - ] - edge [ - source 38 - target 210 - weight 2.0448861860374294 - ] - edge [ - source 39 - target 61 - weight 2.084872062095129 - ] - edge [ - source 40 - target 153 - weight 2.170905746330924 - ] - edge [ - source 41 - target 25 - weight 2.084872062095129 - ] - edge [ - source 42 - target 30 - weight 2.416283817572408 - ] - edge [ - source 42 - target 36 - weight 2.4694323831184835 - ] - edge [ - source 43 - target 44 - weight 2.4824360255994344 - ] - edge [ - source 43 - target 53 - weight 2.4718892505370196 - ] - edge [ - source 44 - target 43 - weight 2.4824360255994344 - ] - edge [ - source 44 - target 45 - weight 2.492840415541141 - ] - edge [ - source 45 - target 44 - weight 2.492840415541141 - ] - edge [ - source 45 - target 46 - weight 2.440209439388722 - ] - edge [ - source 46 - target 45 - weight 2.440209439388722 - ] - edge [ - source 46 - target 47 - weight 2.484728481718801 - ] - edge [ - source 47 - target 46 - weight 2.484728481718801 - ] - edge [ - source 47 - target 48 - weight 2.001685088476564 - ] - edge [ - source 48 - target 47 - weight 2.001685088476564 - ] - edge [ - source 48 - target 49 - weight 2.0023572140021275 - ] - edge [ - source 49 - target 17 - weight 3.604822830627851 - ] - edge [ - source 49 - target 48 - weight 2.0023572140021275 - ] - edge [ - source 49 - target 50 - weight 2.0002270006186693 - ] - edge [ - source 50 - target 60 - weight 2.026996038737844 - ] - edge [ - source 50 - target 49 - weight 2.0002270006186693 - ] - edge [ - source 51 - target 36 - weight 2.0246374634485824 - ] - edge [ - source 51 - target 152 - weight 2.480453759715073 - ] - edge [ - source 52 - target 100 - weight 2.0156676009878 - ] - edge [ - source 52 - target 53 - weight 2.4482202321602267 - ] - edge [ - source 53 - target 43 - weight 2.4718892505370196 - ] - edge [ - source 53 - target 52 - weight 2.4482202321602267 - ] - edge [ - source 54 - target 154 - weight 2.0887572908075014 - ] - edge [ - source 55 - target 190 - weight 7.095026418166703 - ] - edge [ - source 55 - target 58 - weight 3.7181873904041565 - ] - edge [ - source 55 - target 56 - weight 2.2918477014027667 - ] - edge [ - source 56 - target 168 - weight 2.004575681197983 - ] - edge [ - source 56 - target 55 - weight 2.2918477014027667 - ] - edge [ - source 57 - target 54 - weight 2.088757290807486 - ] - edge [ - source 58 - target 193 - weight 2.0448861860374294 - ] - edge [ - source 59 - target 60 - weight 2.023556332782071 - ] - edge [ - source 59 - target 70 - weight 2.013317069105941 - ] - edge [ - source 60 - target 59 - weight 2.023556332782071 - ] - edge [ - source 60 - target 17 - weight 2.391019673919837 - ] - edge [ - source 60 - target 50 - weight 2.026996038737844 - ] - edge [ - source 61 - target 37 - weight 2.0848720620951293 - ] - edge [ - source 62 - target 29 - weight 2.000182548123138 - ] - edge [ - source 62 - target 2 - weight 2.4787581406772756 - ] - edge [ - source 63 - target 64 - weight 2.011803065368662 - ] - edge [ - source 63 - target 126 - weight 2.3776189895940814 - ] - edge [ - source 64 - target 63 - weight 2.011803065368662 - ] - edge [ - source 64 - target 65 - weight 2.433453315264198 - ] - edge [ - source 65 - target 64 - weight 2.433453315264198 - ] - edge [ - source 65 - target 66 - weight 2.4963736602906654 - ] - edge [ - source 66 - target 65 - weight 2.4963736602906654 - ] - edge [ - source 66 - target 67 - weight 2.4860253757006894 - ] - edge [ - source 67 - target 66 - weight 2.4860253757006894 - ] - edge [ - source 67 - target 68 - weight 2.408824157275536 - ] - edge [ - source 68 - target 67 - weight 2.408824157275536 - ] - edge [ - source 68 - target 69 - weight 2.058402098912965 - ] - edge [ - source 69 - target 68 - weight 2.058402098912965 - ] - edge [ - source 69 - target 70 - weight 2.0917374419386277 - ] - edge [ - source 70 - target 59 - weight 2.013317069105941 - ] - edge [ - source 70 - target 69 - weight 2.0917374419386277 - ] - edge [ - source 71 - target 72 - weight 2.0169441587925045 - ] - edge [ - source 71 - target 74 - weight 2.1900493856748255 - ] - edge [ - source 72 - target 71 - weight 2.0169441587925045 - ] - edge [ - source 72 - target 77 - weight 2.2268105445068924 - ] - edge [ - source 73 - target 74 - weight 2.1377247294906563 - ] - edge [ - source 73 - target 84 - weight 2.203485898651859 - ] - edge [ - source 74 - target 71 - weight 2.1900493856748255 - ] - edge [ - source 74 - target 73 - weight 2.1377247294906563 - ] - edge [ - source 75 - target 76 - weight 2.4336626502718786 - ] - edge [ - source 75 - target 78 - weight 2.453506470485739 - ] - edge [ - source 76 - target 75 - weight 2.4336626502718786 - ] - edge [ - source 76 - target 2 - weight 2.4880339864663137 - ] - edge [ - source 77 - target 72 - weight 2.2268105445068924 - ] - edge [ - source 77 - target 78 - weight 2.395009498157154 - ] - edge [ - source 78 - target 75 - weight 2.453506470485739 - ] - edge [ - source 78 - target 77 - weight 2.395009498157154 - ] - edge [ - source 79 - target 80 - weight 2.0097202911722882 - ] - edge [ - source 80 - target 85 - weight 2.31111402055776 - ] - edge [ - source 81 - target 82 - weight 2.0097202911722802 - ] - edge [ - source 82 - target 79 - weight 2.0097202911722882 - ] - edge [ - source 83 - target 84 - weight 2.065662943630219 - ] - edge [ - source 84 - target 73 - weight 2.203485898651859 - ] - edge [ - source 84 - target 83 - weight 2.065662943630219 - ] - edge [ - source 85 - target 86 - weight 2.084872062095129 - ] - edge [ - source 86 - target 26 - weight 2.084872062095129 - ] - edge [ - source 87 - target 3 - weight 2.044886186037433 - ] - edge [ - source 88 - target 89 - weight 2.0045768590316304 - ] - edge [ - source 89 - target 90 - weight 2.0045768590316304 - ] - edge [ - source 90 - target 91 - weight 2.004576859031627 - ] - edge [ - source 91 - target 92 - weight 2.004576859031627 - ] - edge [ - source 92 - target 93 - weight 2.004576859031634 - ] - edge [ - source 93 - target 94 - weight 2.004576859031627 - ] - edge [ - source 94 - target 95 - weight 2.004576859031627 - ] - edge [ - source 95 - target 96 - weight 2.004576859031627 - ] - edge [ - source 96 - target 97 - weight 2.004576859031634 - ] - edge [ - source 97 - target 135 - weight 2.004576859031627 - ] - edge [ - source 98 - target 99 - weight 2.0134815766476266 - ] - edge [ - source 98 - target 107 - weight 2.460440607573003 - ] - edge [ - source 99 - target 98 - weight 2.0134815766476266 - ] - edge [ - source 99 - target 147 - weight 2.00482641603035 - ] - edge [ - source 100 - target 101 - weight 2.519851108846427 - ] - edge [ - source 100 - target 52 - weight 2.0156676009878 - ] - edge [ - source 101 - target 100 - weight 2.519851108846427 - ] - edge [ - source 101 - target 102 - weight 2.0261176137739882 - ] - edge [ - source 102 - target 101 - weight 2.0261176137739882 - ] - edge [ - source 102 - target 103 - weight 2.0449924956209355 - ] - edge [ - source 103 - target 102 - weight 2.0449924956209355 - ] - edge [ - source 103 - target 104 - weight 2.0140640330641735 - ] - edge [ - source 104 - target 103 - weight 2.0140640330641735 - ] - edge [ - source 104 - target 105 - weight 2.5054821660012996 - ] - edge [ - source 105 - target 104 - weight 2.5054821660012996 - ] - edge [ - source 105 - target 106 - weight 2.5136213992816163 - ] - edge [ - source 106 - target 105 - weight 2.5136213992816163 - ] - edge [ - source 106 - target 107 - weight 2.0174477288604136 - ] - edge [ - source 107 - target 98 - weight 2.460440607573003 - ] - edge [ - source 107 - target 106 - weight 2.0174477288604136 - ] - edge [ - source 108 - target 81 - weight 2.009720291172295 - ] - edge [ - source 109 - target 108 - weight 2.009720291172281 - ] - edge [ - source 110 - target 113 - weight 2.425565488150257 - ] - edge [ - source 111 - target 110 - weight 2.170905746330924 - ] - edge [ - source 112 - target 115 - weight 2.3791843214815556 - ] - edge [ - source 113 - target 112 - weight 2.3791843214815556 - ] - edge [ - source 114 - target 117 - weight 2.3791843214815556 - ] - edge [ - source 115 - target 114 - weight 2.3791843214815707 - ] - edge [ - source 116 - target 109 - weight 2.881220803806643 - ] - edge [ - source 117 - target 116 - weight 2.3791843214815556 - ] - edge [ - source 118 - target 119 - weight 2.4199340430964797 - ] - edge [ - source 118 - target 121 - weight 2.4749700977179923 - ] - edge [ - source 119 - target 118 - weight 2.4199340430964797 - ] - edge [ - source 119 - target 124 - weight 2.3983281529442895 - ] - edge [ - source 120 - target 121 - weight 2.427197135672506 - ] - edge [ - source 120 - target 127 - weight 2.419547369869957 - ] - edge [ - source 121 - target 118 - weight 2.4749700977179923 - ] - edge [ - source 121 - target 120 - weight 2.427197135672506 - ] - edge [ - source 122 - target 123 - weight 2.3298788517312627 - ] - edge [ - source 122 - target 207 - weight 10.612961064956258 - ] - edge [ - source 122 - target 125 - weight 2.2886221242705522 - ] - edge [ - source 123 - target 122 - weight 2.3298788517312627 - ] - edge [ - source 123 - target 167 - weight 2.345064300767156 - ] - edge [ - source 124 - target 119 - weight 2.3983281529442895 - ] - edge [ - source 124 - target 125 - weight 2.36562222397011 - ] - edge [ - source 125 - target 122 - weight 2.2886221242705522 - ] - edge [ - source 125 - target 124 - weight 2.36562222397011 - ] - edge [ - source 126 - target 63 - weight 2.3776189895940814 - ] - edge [ - source 126 - target 207 - weight 12.115403500980515 - ] - edge [ - source 126 - target 127 - weight 2.4532923880969393 - ] - edge [ - source 127 - target 120 - weight 2.419547369869957 - ] - edge [ - source 127 - target 126 - weight 2.4532923880969393 - ] - edge [ - source 128 - target 137 - weight 2.1692437743076782 - ] - edge [ - source 129 - target 128 - weight 2.169243774307677 - ] - edge [ - source 130 - target 129 - weight 2.169243774307677 - ] - edge [ - source 131 - target 130 - weight 3.3984004312346316 - ] - edge [ - source 132 - target 131 - weight 2.004576859031627 - ] - edge [ - source 133 - target 132 - weight 2.004576859031627 - ] - edge [ - source 134 - target 133 - weight 2.004576859031627 - ] - edge [ - source 135 - target 134 - weight 2.004576859031634 - ] - edge [ - source 136 - target 200 - weight 2.169243774307677 - ] - edge [ - source 137 - target 136 - weight 2.169243774307677 - ] - edge [ - source 138 - target 152 - weight 2.026419997905915 - ] - edge [ - source 138 - target 139 - weight 2.481737399634923 - ] - edge [ - source 139 - target 140 - weight 2.4668448880798084 - ] - edge [ - source 139 - target 138 - weight 2.481737399634923 - ] - edge [ - source 140 - target 141 - weight 2.4879558477156727 - ] - edge [ - source 140 - target 139 - weight 2.4668448880798084 - ] - edge [ - source 141 - target 140 - weight 2.4879558477156727 - ] - edge [ - source 141 - target 142 - weight 2.4963415324457365 - ] - edge [ - source 142 - target 141 - weight 2.4963415324457365 - ] - edge [ - source 142 - target 143 - weight 2.025558191267938 - ] - edge [ - source 143 - target 142 - weight 2.025558191267938 - ] - edge [ - source 143 - target 144 - weight 2.0282860407737076 - ] - edge [ - source 144 - target 143 - weight 2.0282860407737076 - ] - edge [ - source 144 - target 145 - weight 2.103662676638815 - ] - edge [ - source 145 - target 144 - weight 2.103662676638815 - ] - edge [ - source 145 - target 146 - weight 2.090887610489607 - ] - edge [ - source 146 - target 145 - weight 2.090887610489607 - ] - edge [ - source 146 - target 147 - weight 2.072892694423823 - ] - edge [ - source 147 - target 99 - weight 2.00482641603035 - ] - edge [ - source 147 - target 146 - weight 2.072892694423823 - ] - edge [ - source 148 - target 149 - weight 2.170905746330924 - ] - edge [ - source 149 - target 111 - weight 2.170905746330938 - ] - edge [ - source 150 - target 151 - weight 2.170905746330924 - ] - edge [ - source 151 - target 40 - weight 2.170905746330938 - ] - edge [ - source 152 - target 138 - weight 2.026419997905915 - ] - edge [ - source 152 - target 51 - weight 2.480453759715073 - ] - edge [ - source 153 - target 148 - weight 2.170905746330922 - ] - edge [ - source 154 - target 155 - weight 2.088757290807486 - ] - edge [ - source 155 - target 156 - weight 2.088757290807486 - ] - edge [ - source 156 - target 157 - weight 2.088757290807499 - ] - edge [ - source 157 - target 183 - weight 3.8382639059218158 - ] - edge [ - source 158 - target 159 - weight 2.314715655694063 - ] - edge [ - source 158 - target 161 - weight 2.3496347494966976 - ] - edge [ - source 159 - target 158 - weight 2.314715655694063 - ] - edge [ - source 159 - target 166 - weight 2.301601008214085 - ] - edge [ - source 160 - target 161 - weight 2.293197245167791 - ] - edge [ - source 160 - target 163 - weight 2.332225156939092 - ] - edge [ - source 161 - target 158 - weight 2.3496347494966976 - ] - edge [ - source 161 - target 160 - weight 2.293197245167791 - ] - edge [ - source 162 - target 163 - weight 2.331069887621196 - ] - edge [ - source 162 - target 165 - weight 2.3057704395935716 - ] - edge [ - source 163 - target 189 - weight 7.347259023555887 - ] - edge [ - source 163 - target 162 - weight 2.331069887621196 - ] - edge [ - source 163 - target 160 - weight 2.332225156939092 - ] - edge [ - source 164 - target 182 - weight 2.2837207896119796 - ] - edge [ - source 164 - target 165 - weight 2.304288235588618 - ] - edge [ - source 165 - target 162 - weight 2.3057704395935716 - ] - edge [ - source 165 - target 164 - weight 2.304288235588618 - ] - edge [ - source 166 - target 159 - weight 2.301601008214085 - ] - edge [ - source 166 - target 167 - weight 2.311765047875286 - ] - edge [ - source 167 - target 123 - weight 2.345064300767156 - ] - edge [ - source 167 - target 166 - weight 2.311765047875286 - ] - edge [ - source 168 - target 169 - weight 2.2202482987685563 - ] - edge [ - source 168 - target 56 - weight 2.004575681197983 - ] - edge [ - source 169 - target 168 - weight 2.2202482987685563 - ] - edge [ - source 169 - target 175 - weight 2.305666903350038 - ] - edge [ - source 170 - target 11 - weight 2.153423713184546 - ] - edge [ - source 171 - target 172 - weight 2.167944186970709 - ] - edge [ - source 171 - target 178 - weight 2.300542746851572 - ] - edge [ - source 172 - target 171 - weight 2.167944186970709 - ] - edge [ - source 172 - target 188 - weight 3.7128338111758374 - ] - edge [ - source 172 - target 173 - weight 2.1627011213883724 - ] - edge [ - source 173 - target 172 - weight 2.1627011213883724 - ] - edge [ - source 173 - target 174 - weight 2.0175104475585353 - ] - edge [ - source 174 - target 173 - weight 2.0175104475585353 - ] - edge [ - source 175 - target 169 - weight 2.305666903350038 - ] - edge [ - source 175 - target 190 - weight 7.484068105633168 - ] - edge [ - source 175 - target 176 - weight 2.315590093261279 - ] - edge [ - source 176 - target 175 - weight 2.315590093261279 - ] - edge [ - source 176 - target 177 - weight 2.253500473305087 - ] - edge [ - source 177 - target 176 - weight 2.253500473305087 - ] - edge [ - source 177 - target 178 - weight 2.1865657137162944 - ] - edge [ - source 178 - target 171 - weight 2.300542746851572 - ] - edge [ - source 178 - target 188 - weight 5.255051954765709 - ] - edge [ - source 178 - target 177 - weight 2.1865657137162944 - ] - edge [ - source 179 - target 0 - weight 2.044886186037433 - ] - edge [ - source 180 - target 187 - weight 2.169243774307677 - ] - edge [ - source 181 - target 180 - weight 2.1692437743076782 - ] - edge [ - source 182 - target 183 - weight 2.307748177553896 - ] - edge [ - source 182 - target 164 - weight 2.2837207896119796 - ] - edge [ - source 183 - target 150 - weight 4.644205909750766 - ] - edge [ - source 183 - target 189 - weight 7.275467074399795 - ] - edge [ - source 183 - target 182 - weight 2.307748177553896 - ] - edge [ - source 184 - target 57 - weight 2.088757290807499 - ] - edge [ - source 185 - target 184 - weight 2.088757290807486 - ] - edge [ - source 186 - target 185 - weight 3.805856412199651 - ] - edge [ - source 187 - target 186 - weight 2.169243774307677 - ] - edge [ - source 188 - target 172 - weight 3.7128338111758374 - ] - edge [ - source 188 - target 192 - weight 5.385373378256093 - ] - edge [ - source 188 - target 178 - weight 5.255051954765709 - ] - edge [ - source 189 - target 23 - weight 3.458521692634201 - ] - edge [ - source 189 - target 183 - weight 7.275467074399795 - ] - edge [ - source 189 - target 163 - weight 7.347259023555887 - ] - edge [ - source 190 - target 191 - weight 3.617448067513515 - ] - edge [ - source 190 - target 175 - weight 7.484068105633168 - ] - edge [ - source 190 - target 55 - weight 7.095026418166703 - ] - edge [ - source 191 - target 190 - weight 3.617448067513515 - ] - edge [ - source 191 - target 197 - weight 4.410017082653349 - ] - edge [ - source 192 - target 188 - weight 5.385373378256093 - ] - edge [ - source 192 - target 197 - weight 6.629956013859094 - ] - edge [ - source 193 - target 38 - weight 2.0448861860374272 - ] - edge [ - source 194 - target 88 - weight 3.0786711954567356 - ] - edge [ - source 195 - target 194 - weight 2.0448861860374254 - ] - edge [ - source 196 - target 181 - weight 2.169243774307677 - ] - edge [ - source 197 - target 191 - weight 4.410017082653349 - ] - edge [ - source 197 - target 192 - weight 6.629956013859094 - ] - edge [ - source 198 - target 199 - weight 2.0848720620951218 - ] - edge [ - source 199 - target 27 - weight 2.084872062095129 - ] - edge [ - source 200 - target 196 - weight 2.169243774307677 - ] - edge [ - source 201 - target 206 - weight 4.946322408256132 - ] - edge [ - source 201 - target 202 - weight 5.954240662440163 - ] - edge [ - source 202 - target 18 - weight 6.6018993975102465 - ] - edge [ - source 202 - target 201 - weight 5.954240662440163 - ] - edge [ - source 203 - target 204 - weight 6.469424288795965 - ] - edge [ - source 203 - target 209 - weight 7.6981276005095385 - ] - edge [ - source 204 - target 203 - weight 6.469424288795965 - ] - edge [ - source 204 - target 205 - weight 8.613755821663979 - ] - edge [ - source 205 - target 204 - weight 8.613755821663979 - ] - edge [ - source 205 - target 206 - weight 4.219552142682915 - ] - edge [ - source 206 - target 205 - weight 4.219552142682915 - ] - edge [ - source 206 - target 201 - weight 4.946322408256132 - ] - edge [ - source 207 - target 122 - weight 10.612961064956258 - ] - edge [ - source 207 - target 126 - weight 12.115403500980515 - ] - edge [ - source 207 - target 208 - weight 4.768341404842254 - ] - edge [ - source 208 - target 16 - weight 6.921383948169974 - ] - edge [ - source 208 - target 207 - weight 4.768341404842254 - ] - edge [ - source 208 - target 209 - weight 8.21783361961489 - ] - edge [ - source 209 - target 203 - weight 7.6981276005095385 - ] - edge [ - source 209 - target 208 - weight 8.21783361961489 - ] - edge [ - source 210 - target 179 - weight 2.0448861860374272 - ] -] diff --git a/EastCampusLiteV5.gml b/EastCampusLiteV5.gml new file mode 100644 index 00000000..f38d4386 --- /dev/null +++ b/EastCampusLiteV5.gml @@ -0,0 +1,4652 @@ +graph [ + directed 1 + node [ + id 0 + label "R_Node:405" + active 0 + pos 126.32887129350142 + pos 130.09720542214134 + ] + node [ + id 1 + label "R_Node:404" + active 0 + pos 126.16242564808239 + pos 132.17148382013494 + ] + node [ + id 2 + label "R_Node:407" + active 0 + pos 126.66176258433948 + pos 125.94864862615412 + ] + node [ + id 3 + label "R_Node:406" + active 0 + pos 126.49531693892045 + pos 128.02292702414772 + ] + node [ + id 4 + label "R_Node:401" + active 0 + pos 125.66308871182528 + pos 138.39431901411578 + ] + node [ + id 5 + label "R_Node:400" + active 0 + pos 125.49664306640625 + pos 140.46859741210938 + ] + node [ + id 6 + label "R_Node:403" + active 0 + pos 125.99598000266336 + pos 134.24576221812856 + ] + node [ + id 7 + label "R_Node:402" + active 0 + pos 125.82953435724431 + pos 136.32004061612216 + ] + node [ + id 8 + label "R_Node:409" + active 0 + pos 126.99465387517756 + pos 121.8000918301669 + ] + node [ + id 9 + label "R_Node:408" + active 0 + pos 126.82820822975852 + pos 123.87437022816052 + ] + node [ + id 10 + label "R_Node:470" + active 0 + pos 70.37710507710774 + pos 110.46276982625325 + ] + node [ + id 11 + label "R_Node:471" + active 0 + pos 71.95603942871094 + pos 111.93141174316406 + ] + node [ + id 12 + label "R_Node:499" + active 0 + pos 108.2052230834961 + pos 119.25115203857422 + ] + node [ + id 13 + label "R_Node:496" + active 0 + pos 103.8828353881836 + pos 120.0474624633789 + ] + node [ + id 14 + label "R_Node:497" + active 0 + pos 106.19354629516602 + pos 119.65007400512695 + ] + node [ + id 15 + label "R_Node:494" + active 0 + pos 99.26141357421875 + pos 120.84223937988281 + ] + node [ + id 16 + label "R_Node:495" + active 0 + pos 101.57212448120117 + pos 120.44485092163086 + ] + node [ + id 17 + label "R_Node:539" + active 0 + pos 86.37067413330078 + pos 130.93798828125 + ] + node [ + id 18 + label "R_Node:538" + active 0 + pos 84.3013687133789 + pos 131.54974060058595 + ] + node [ + id 19 + label "R_Node:249" + active 0 + pos 44.29695510864258 + pos 24.146379470825195 + ] + node [ + id 20 + label "R_Node:248" + active 0 + pos 45.788658142089844 + pos 26.94240951538086 + ] + node [ + id 21 + label "R_Node:247" + active 0 + pos 45.97460092817034 + pos 29.01897321428571 + ] + node [ + id 22 + label "R_Node:246" + active 0 + pos 46.160543714250835 + pos 31.095536913190568 + ] + node [ + id 23 + label "R_Node:245" + active 0 + pos 46.34648650033133 + pos 33.17210061209542 + ] + node [ + id 24 + label "R_Node:532" + active 0 + pos 71.98013114929199 + pos 135.6436424255371 + ] + node [ + id 25 + label "R_Node:243" + active 0 + pos 46.71837207249233 + pos 37.32522800990513 + ] + node [ + id 26 + label "R_Node:242" + active 0 + pos 46.904314858572825 + pos 39.40179170880999 + ] + node [ + id 27 + label "R_Node:537" + active 0 + pos 82.23206329345703 + pos 132.16149291992187 + ] + node [ + id 28 + label "R_Node:240" + active 0 + pos 47.276200430733816 + pos 43.5549191066197 + ] + node [ + id 29 + label "R_Node:294" + active 0 + pos 167.9210685567653 + pos 124.57857529660488 + ] + node [ + id 30 + label "R_Node:333" + active 0 + pos 208.70319707342918 + pos 142.62738718885058 + ] + node [ + id 31 + label "R_Node:332" + active 0 + pos 210.60300266996342 + pos 143.33299661189952 + ] + node [ + id 32 + label "R_Node:331" + active 0 + pos 212.50280826649768 + pos 144.03860603494846 + ] + node [ + id 33 + label "R_Node:330" + active 0 + pos 214.40261386303192 + pos 144.74421545799743 + ] + node [ + id 34 + label "R_Node:337" + active 0 + pos 201.10397468729224 + pos 139.80494949665476 + ] + node [ + id 35 + label "R_Node:336" + active 0 + pos 203.00378028382647 + pos 140.5105589197037 + ] + node [ + id 36 + label "R_Node:335" + active 0 + pos 204.9035858803607 + pos 141.21616834275267 + ] + node [ + id 37 + label "R_Node:334" + active 0 + pos 206.80339147689494 + pos 141.9217777658016 + ] + node [ + id 38 + label "R_Node:232" + active 0 + pos 48.92604217529297 + pos 60.30195007324219 + ] + node [ + id 39 + label "R_Node:233" + active 0 + pos 48.668678283691406 + pos 58.30877685546875 + ] + node [ + id 40 + label "R_Node:230" + active 0 + pos 49.44076995849609 + pos 64.28829650878906 + ] + node [ + id 41 + label "R_Node:231" + active 0 + pos 49.183406066894534 + pos 62.29512329101563 + ] + node [ + id 42 + label "R_Node:236" + active 0 + pos 48.019971575055806 + pos 51.861173902239116 + ] + node [ + id 43 + label "R_Node:237" + active 0 + pos 47.83402878897531 + pos 49.78461020333426 + ] + node [ + id 44 + label "R_Node:234" + active 0 + pos 48.3918571472168 + pos 56.01430130004883 + ] + node [ + id 45 + label "R_Node:235" + active 0 + pos 48.2059143611363 + pos 53.93773760114397 + ] + node [ + id 46 + label "R_Node:197" + active 0 + pos 51.500187683105466 + pos 64.12092590332031 + ] + node [ + id 47 + label "R_Node:196" + active 0 + pos 51.11942329406738 + pos 61.985361099243164 + ] + node [ + id 48 + label "R_Node:195" + active 0 + pos 50.7386589050293 + pos 59.849796295166016 + ] + node [ + id 49 + label "R_Node:194" + active 0 + pos 50.42509460449219 + pos 56.46589279174805 + ] + node [ + id 50 + label "R_Node:193" + active 0 + pos 50.30574417114258 + pos 54.46487208775112 + ] + node [ + id 51 + label "R_Node:192" + active 0 + pos 50.18639373779297 + pos 52.46385138375419 + ] + node [ + id 52 + label "R_Node:191" + active 0 + pos 50.06704330444336 + pos 50.46283067975726 + ] + node [ + id 53 + label "R_Node:190" + active 0 + pos 49.94769287109375 + pos 48.461809975760325 + ] + node [ + id 54 + label "R_Node:199" + active 0 + pos 52.26171646118164 + pos 68.39205551147461 + ] + node [ + id 55 + label "R_Node:198" + active 0 + pos 51.88095207214356 + pos 66.25649070739746 + ] + node [ + id 56 + label "R_Node:291" + active 0 + pos 162.21566869857463 + pos 122.53487185214428 + ] + node [ + id 57 + label "R_Node:229" + active 0 + pos 49.698133850097655 + pos 66.2814697265625 + ] + node [ + id 58 + label "R_Node:289" + active 0 + pos 158.4120687931142 + pos 121.17240288917054 + ] + node [ + id 59 + label "R_Node:288" + active 0 + pos 156.510268840384 + pos 120.49116840768367 + ] + node [ + id 60 + label "R_Node:228" + active 0 + pos 49.95549774169922 + pos 68.27464294433594 + ] + node [ + id 61 + label "R_Node:283" + active 0 + pos 147.00126907673288 + pos 117.08499600024933 + ] + node [ + id 62 + label "R_Node:282" + active 0 + pos 145.09946912400267 + pos 116.40376151876247 + ] + node [ + id 63 + label "R_Node:281" + active 0 + pos 143.19766917127245 + pos 115.7225270372756 + ] + node [ + id 64 + label "R_Node:280" + active 0 + pos 141.2958692185422 + pos 115.04129255578873 + ] + node [ + id 65 + label "R_Node:287" + active 0 + pos 154.60846888765377 + pos 119.8099339261968 + ] + node [ + id 66 + label "R_Node:286" + active 0 + pos 152.70666893492353 + pos 119.12869944470994 + ] + node [ + id 67 + label "R_Node:285" + active 0 + pos 150.8048689821933 + pos 118.44746496322307 + ] + node [ + id 68 + label "R_Node:284" + active 0 + pos 148.9030690294631 + pos 117.7662304817362 + ] + node [ + id 69 + label "R_Node:575" + active 0 + pos 84.9034194946289 + pos 120.62381235758464 + ] + node [ + id 70 + label "R_Node:574" + active 0 + pos 86.80859375 + pos 121.26056416829427 + ] + node [ + id 71 + label "R_Node:577" + active 0 + pos 81.45442199707031 + pos 119.49200439453125 + ] + node [ + id 72 + label "R_Node:576" + active 0 + pos 82.99824523925781 + pos 119.987060546875 + ] + node [ + id 73 + label "R_Node:478" + active 0 + pos 86.04608154296875 + pos 119.16532135009766 + ] + node [ + id 74 + label "R_Node:479" + active 0 + pos 88.33107452392578 + pos 119.53241577148438 + ] + node [ + id 75 + label "R_Node:573" + active 0 + pos 88.7137680053711 + pos 121.8973159790039 + ] + node [ + id 76 + label "R_Node:572" + active 0 + pos 91.72807312011719 + pos 121.99597930908203 + ] + node [ + id 77 + label "R_Node:474" + active 0 + pos 78.19667510986328 + pos 115.64808349609375 + ] + node [ + id 78 + label "R_Node:475" + active 0 + pos 80.25677795410157 + pos 116.68274993896485 + ] + node [ + id 79 + label "R_Node:476" + active 0 + pos 82.31688079833984 + pos 117.71741638183593 + ] + node [ + id 80 + label "R_Node:477" + active 0 + pos 84.37698364257812 + pos 118.75208282470703 + ] + node [ + id 81 + label "R_Node:579" + active 0 + pos 76.93404388427734 + pos 117.4376449584961 + ] + node [ + id 82 + label "R_Node:578" + active 0 + pos 79.19423294067383 + pos 118.46482467651367 + ] + node [ + id 83 + label "R_Node:472" + active 0 + pos 74.07646942138672 + pos 113.57875061035156 + ] + node [ + id 84 + label "R_Node:473" + active 0 + pos 76.136572265625 + pos 114.61341705322266 + ] + node [ + id 85 + label "R_Node:227" + active 0 + pos 50.21689224243164 + pos 71.14398193359375 + ] + node [ + id 86 + label "R_Node:226" + active 0 + pos 50.74474563598633 + pos 73.46387176513672 + ] + node [ + id 87 + label "R_Node:372" + active 0 + pos 134.61077880859375 + pos 115.1086196899414 + ] + node [ + id 88 + label "R_Node:371" + active 0 + pos 136.510584405128 + pos 115.81422911299036 + ] + node [ + id 89 + label "R_Node:370" + active 0 + pos 138.41039000166222 + pos 116.51983853603932 + ] + node [ + id 90 + label "R_Node:179" + active 0 + pos 48.517520904541016 + pos 25.382041931152344 + ] + node [ + id 91 + label "R_Node:178" + active 0 + pos 46.85200675328573 + pos 24.195609410603844 + ] + node [ + id 92 + label "R_Node:275" + active 0 + pos 60.94453048706055 + pos 106.27528381347656 + ] + node [ + id 93 + label "R_Node:272" + active 0 + pos 9.681283950805664 + pos -0.7005032896995544 + ] + node [ + id 94 + label "R_Node:273" + active 0 + pos 5.183620452880859 + pos 0.7034059762954712 + ] + node [ + id 95 + label "R_Node:270" + active 0 + pos 13.53003215789795 + pos 5.624235153198242 + ] + node [ + id 96 + label "R_Node:271" + active 0 + pos 23.766420364379883 + pos 9.130175590515137 + ] + node [ + id 97 + label "R_Node:171" + active 0 + pos 35.193407694498696 + pos 15.890581766764324 + ] + node [ + id 98 + label "R_Node:170" + active 0 + pos 33.52789354324341 + pos 14.70414924621582 + ] + node [ + id 99 + label "R_Node:173" + active 0 + pos 38.52443599700928 + pos 18.263446807861328 + ] + node [ + id 100 + label "R_Node:172" + active 0 + pos 36.85892184575399 + pos 17.077014287312828 + ] + node [ + id 101 + label "R_Node:175" + active 0 + pos 41.85546429951986 + pos 20.636311848958336 + ] + node [ + id 102 + label "R_Node:174" + active 0 + pos 40.18995014826457 + pos 19.449879328409832 + ] + node [ + id 103 + label "R_Node:177" + active 0 + pos 45.18649260203044 + pos 23.00917689005534 + ] + node [ + id 104 + label "R_Node:176" + active 0 + pos 43.52097845077515 + pos 21.822744369506836 + ] + node [ + id 105 + label "R_Node:277" + active 0 + pos 135.59046936035156 + pos 112.99758911132812 + ] + node [ + id 106 + label "R_Node:308" + active 0 + pos 194.54626789498838 + pos 134.11585803742105 + ] + node [ + id 107 + label "R_Node:309" + active 0 + pos 196.4480678477186 + pos 134.7970925189079 + ] + node [ + id 108 + label "R_Node:302" + active 0 + pos 183.13546817860706 + pos 130.02845114849984 + ] + node [ + id 109 + label "R_Node:303" + active 0 + pos 185.03726813133727 + pos 130.7096856299867 + ] + node [ + id 110 + label "R_Node:300" + active 0 + pos 179.3318682731466 + pos 128.6659821855261 + ] + node [ + id 111 + label "R_Node:301" + active 0 + pos 181.23366822587684 + pos 129.34721666701296 + ] + node [ + id 112 + label "R_Node:306" + active 0 + pos 190.74266798952792 + pos 132.7533890744473 + ] + node [ + id 113 + label "R_Node:307" + active 0 + pos 192.64446794225813 + pos 133.43462355593417 + ] + node [ + id 114 + label "R_Node:304" + active 0 + pos 186.9390680840675 + pos 131.39092011147358 + ] + node [ + id 115 + label "R_Node:305" + active 0 + pos 188.8408680367977 + pos 132.07215459296043 + ] + node [ + id 116 + label "R_Node:531" + active 0 + pos 69.90438461303711 + pos 136.51065826416016 + ] + node [ + id 117 + label "R_Node:278" + active 0 + pos 137.49226931308178 + pos 113.678823592815 + ] + node [ + id 118 + label "R_Node:530" + active 0 + pos 67.82863807678223 + pos 137.3776741027832 + ] + node [ + id 119 + label "R_Node:279" + active 0 + pos 139.394069265812 + pos 114.36005807430186 + ] + node [ + id 120 + label "R_Node:533" + active 0 + pos 74.05587768554688 + pos 134.77662658691406 + ] + node [ + id 121 + label "R_Node:244" + active 0 + pos 46.53242928641183 + pos 35.248664311000276 + ] + node [ + id 122 + label "R_Node:535" + active 0 + pos 78.09345245361328 + pos 133.38499755859374 + ] + node [ + id 123 + label "R_Node:534" + active 0 + pos 76.0241470336914 + pos 133.9967498779297 + ] + node [ + id 124 + label "R_Node:241" + active 0 + pos 47.09025764465332 + pos 41.478355407714844 + ] + node [ + id 125 + label "R_Node:536" + active 0 + pos 80.16275787353516 + pos 132.77324523925782 + ] + node [ + id 126 + label "R_Node:438" + active 0 + pos 95.3791446685791 + pos 132.47478485107422 + ] + node [ + id 127 + label "R_Node:439" + active 0 + pos 93.32544326782227 + pos 132.47314453125 + ] + node [ + id 128 + label "R_Node:437" + active 0 + pos 97.43284606933594 + pos 132.47642517089844 + ] + node [ + id 129 + label "R_Node:566" + active 0 + pos 108.26012929280598 + pos 120.94359588623047 + ] + node [ + id 130 + label "R_Node:295" + active 0 + pos 169.82286850949552 + pos 125.25980977809175 + ] + node [ + id 131 + label "R_Node:564" + active 0 + pos 113.3269271850586 + pos 119.3891372680664 + ] + node [ + id 132 + label "R_Node:565" + active 0 + pos 110.52056121826172 + pos 120.5362548828125 + ] + node [ + id 133 + label "R_Node:290" + active 0 + pos 160.31386874584442 + pos 121.85363737065741 + ] + node [ + id 134 + label "R_Node:481" + active 0 + pos 92.90106048583985 + pos 120.26660461425782 + ] + node [ + id 135 + label "R_Node:480" + active 0 + pos 90.6160675048828 + pos 119.89951019287109 + ] + node [ + id 136 + label "R_Node:482" + active 0 + pos 95.18605346679688 + pos 120.63369903564453 + ] + node [ + id 137 + label "R_Node:292" + active 0 + pos 164.11746865130485 + pos 123.21610633363115 + ] + node [ + id 138 + label "R_Node:293" + active 0 + pos 166.01926860403506 + pos 123.89734081511801 + ] + node [ + id 139 + label "R_Node:508" + active 0 + pos 126.55646006266277 + pos 112.36990865071614 + ] + node [ + id 140 + label "R_Node:509" + active 0 + pos 128.9799041748047 + pos 112.00094604492188 + ] + node [ + id 141 + label "R_Node:504" + active 0 + pos 117.57784525553386 + pos 115.09004211425781 + ] + node [ + id 142 + label "R_Node:505" + active 0 + pos 119.4523696899414 + pos 114.25782012939453 + ] + node [ + id 143 + label "R_Node:506" + active 0 + pos 121.7095718383789 + pos 113.10783386230469 + ] + node [ + id 144 + label "R_Node:507" + active 0 + pos 124.13301595052083 + pos 112.73887125651042 + ] + node [ + id 145 + label "R_Node:500" + active 0 + pos 110.07974751790364 + pos 118.41893005371094 + ] + node [ + id 146 + label "R_Node:501" + active 0 + pos 111.9542719523112 + pos 117.58670806884766 + ] + node [ + id 147 + label "R_Node:502" + active 0 + pos 113.82879638671875 + pos 116.75448608398438 + ] + node [ + id 148 + label "R_Node:503" + active 0 + pos 115.7033208211263 + pos 115.9222640991211 + ] + node [ + id 149 + label "R_Node:445" + active 0 + pos 78.92100715637207 + pos 134.70959091186523 + ] + node [ + id 150 + label "R_Node:444" + active 0 + pos 81.2151985168457 + pos 134.0921401977539 + ] + node [ + id 151 + label "R_Node:447" + active 0 + pos 73.31144714355469 + pos 137.0347442626953 + ] + node [ + id 152 + label "R_Node:446" + active 0 + pos 76.62681579589844 + pos 135.32704162597656 + ] + node [ + id 153 + label "R_Node:346" + active 0 + pos 184.00572431848406 + pos 133.45446468921418 + ] + node [ + id 154 + label "R_Node:347" + active 0 + pos 182.1059187219498 + pos 132.74885526616524 + ] + node [ + id 155 + label "R_Node:344" + active 0 + pos 187.80533551155253 + pos 134.8656835353121 + ] + node [ + id 156 + label "R_Node:345" + active 0 + pos 185.9055299150183 + pos 134.16007411226315 + ] + node [ + id 157 + label "R_Node:342" + active 0 + pos 191.604946704621 + pos 136.27690238141 + ] + node [ + id 158 + label "R_Node:343" + active 0 + pos 189.70514110808676 + pos 135.57129295836103 + ] + node [ + id 159 + label "R_Node:340" + active 0 + pos 195.4045578976895 + pos 137.6881212275079 + ] + node [ + id 160 + label "R_Node:341" + active 0 + pos 193.50475230115526 + pos 136.98251180445894 + ] + node [ + id 161 + label "R_Node:221" + active 0 + pos 53.337608337402344 + pos 85.12073516845703 + ] + node [ + id 162 + label "R_Node:220" + active 0 + pos 54.04327665056501 + pos 87.17374856131417 + ] + node [ + id 163 + label "R_Node:223" + active 0 + pos 52.32830581665039 + pos 80.42354125976563 + ] + node [ + id 164 + label "R_Node:222" + active 0 + pos 52.85615921020508 + pos 82.7434310913086 + ] + node [ + id 165 + label "R_Node:225" + active 0 + pos 51.27259902954101 + pos 75.78376159667968 + ] + node [ + id 166 + label "R_Node:224" + active 0 + pos 51.800452423095706 + pos 78.10365142822266 + ] + node [ + id 167 + label "R_Node:348" + active 0 + pos 180.20611312541556 + pos 132.04324584311627 + ] + node [ + id 168 + label "R_Node:349" + active 0 + pos 178.30630752888132 + pos 131.33763642006733 + ] + node [ + id 169 + label "R_Node:589" + active 0 + pos 229.1866912841797 + pos 146.33322143554688 + ] + node [ + id 170 + label "R_Node:251" + active 0 + pos 40.4602165222168 + pos 20.564404169718426 + ] + node [ + id 171 + label "R_Node:548" + active 0 + pos 109.86565399169922 + pos 134.80704498291016 + ] + node [ + id 172 + label "R_Node:549" + active 0 + pos 111.69802284240723 + pos 135.69972801208496 + ] + node [ + id 173 + label "R_Node:540" + active 0 + pos 90.82673645019531 + pos 130.15594482421875 + ] + node [ + id 174 + label "R_Node:541" + active 0 + pos 93.16297912597656 + pos 130.05372111002603 + ] + node [ + id 175 + label "R_Node:542" + active 0 + pos 95.49922180175781 + pos 129.95149739583334 + ] + node [ + id 176 + label "R_Node:543" + active 0 + pos 97.83546447753906 + pos 129.84927368164062 + ] + node [ + id 177 + label "R_Node:544" + active 0 + pos 102.53617858886719 + pos 131.23631286621094 + ] + node [ + id 178 + label "R_Node:545" + active 0 + pos 104.3685474395752 + pos 132.12899589538574 + ] + node [ + id 179 + label "R_Node:546" + active 0 + pos 106.2009162902832 + pos 133.02167892456055 + ] + node [ + id 180 + label "R_Node:547" + active 0 + pos 108.03328514099121 + pos 133.91436195373535 + ] + node [ + id 181 + label "R_Node:463" + active 0 + pos 61.36751492818197 + pos 110.5137201944987 + ] + node [ + id 182 + label "R_Node:462" + active 0 + pos 61.439013163248696 + pos 112.68739827473958 + ] + node [ + id 183 + label "R_Node:461" + active 0 + pos 61.51051139831543 + pos 114.86107635498047 + ] + node [ + id 184 + label "R_Node:460" + active 0 + pos 61.582009633382164 + pos 117.03475443522136 + ] + node [ + id 185 + label "R_Node:467" + active 0 + pos 65.64030202229817 + pos 106.05684407552083 + ] + node [ + id 186 + label "R_Node:466" + active 0 + pos 64.06136767069499 + pos 104.58820215861003 + ] + node [ + id 187 + label "R_Node:465" + active 0 + pos 62.4824333190918 + pos 103.11956024169922 + ] + node [ + id 188 + label "R_Node:464" + active 0 + pos 61.296016693115234 + pos 108.34004211425781 + ] + node [ + id 189 + label "R_Node:469" + active 0 + pos 68.79817072550456 + pos 108.99412790934245 + ] + node [ + id 190 + label "R_Node:468" + active 0 + pos 67.21923637390137 + pos 107.52548599243164 + ] + node [ + id 191 + label "R_Node:238" + active 0 + pos 47.64808600289481 + pos 47.708046504429404 + ] + node [ + id 192 + label "R_Node:239" + active 0 + pos 47.46214321681431 + pos 45.631482805524556 + ] + node [ + id 193 + label "R_Node:388" + active 0 + pos 129.69590759277344 + pos 117.93450164794922 + ] + node [ + id 194 + label "R_Node:389" + active 0 + pos 129.51547171852806 + pos 120.10107699307528 + ] + node [ + id 195 + label "R_Node:265" + active 0 + pos 13.253376007080078 + pos -3.6941885948181152 + ] + node [ + id 196 + label "R_Node:264" + active 0 + pos 20.0776309967041 + pos -3.232879638671875 + ] + node [ + id 197 + label "R_Node:267" + active 0 + pos 7.81241512298584 + pos 3.8712637424468994 + ] + node [ + id 198 + label "R_Node:261" + active 0 + pos 19.063213348388672 + pos 9.868268966674805 + ] + node [ + id 199 + label "R_Node:263" + active 0 + pos 22.475341796875 + pos 0.4575856924057007 + ] + node [ + id 200 + label "R_Node:262" + active 0 + pos 22.106464385986328 + pos 6.085541725158691 + ] + node [ + id 201 + label "R_Node:269" + active 0 + pos 8.457951545715332 + pos 2.4873392581939697 + ] + node [ + id 202 + label "R_Node:268" + active 0 + pos 13.345596313476562 + pos 6.823634624481201 + ] + node [ + id 203 + label "R_Node:339" + active 0 + pos 197.30436349422374 + pos 138.39373065055685 + ] + node [ + id 204 + label "R_Node:338" + active 0 + pos 199.20416909075797 + pos 139.0993400736058 + ] + node [ + id 205 + label "R_Node:319" + active 0 + pos 215.46606737502077 + pos 141.6094373337766 + ] + node [ + id 206 + label "R_Node:318" + active 0 + pos 213.56426742229056 + pos 140.92820285228973 + ] + node [ + id 207 + label "R_Node:311" + active 0 + pos 200.25166775317902 + pos 136.15956148188164 + ] + node [ + id 208 + label "R_Node:310" + active 0 + pos 198.3498678004488 + pos 135.47832700039478 + ] + node [ + id 209 + label "R_Node:313" + active 0 + pos 204.05526765863948 + pos 137.52203044485537 + ] + node [ + id 210 + label "R_Node:312" + active 0 + pos 202.15346770590924 + pos 136.84079596336852 + ] + node [ + id 211 + label "R_Node:315" + active 0 + pos 207.8588675640999 + pos 138.88449940782914 + ] + node [ + id 212 + label "R_Node:314" + active 0 + pos 205.95706761136967 + pos 138.20326492634226 + ] + node [ + id 213 + label "R_Node:317" + active 0 + pos 211.66246746956034 + pos 140.24696837080285 + ] + node [ + id 214 + label "R_Node:316" + active 0 + pos 209.76066751683013 + pos 139.565733889316 + ] + node [ + id 215 + label "R_Node:168" + active 0 + pos 30.19686524073283 + pos 12.331284205118815 + ] + node [ + id 216 + label "R_Node:169" + active 0 + pos 31.862379391988117 + pos 13.517716725667318 + ] + node [ + id 217 + label "R_Node:258" + active 0 + pos 27.437116622924805 + pos 13.336549758911133 + ] + node [ + id 218 + label "R_Node:393" + active 0 + pos 128.79372822154653 + pos 128.76737837357956 + ] + node [ + id 219 + label "R_Node:529" + active 0 + pos 65.75289154052734 + pos 138.24468994140625 + ] + node [ + id 220 + label "R_Node:584" + active 0 + pos 67.94364356994629 + pos 110.93163871765137 + ] + node [ + id 221 + label "R_Node:585" + active 0 + pos 66.33842849731445 + pos 109.7099494934082 + ] + node [ + id 222 + label "R_Node:586" + active 0 + pos 64.73321342468262 + pos 108.48826026916504 + ] + node [ + id 223 + label "R_Node:587" + active 0 + pos 63.12799835205078 + pos 107.26657104492188 + ] + node [ + id 224 + label "R_Node:580" + active 0 + pos 75.33075714111328 + pos 116.59120178222656 + ] + node [ + id 225 + label "R_Node:581" + active 0 + pos 73.09071350097656 + pos 115.0128173828125 + ] + node [ + id 226 + label "R_Node:582" + active 0 + pos 70.85066986083984 + pos 113.43443298339844 + ] + node [ + id 227 + label "R_Node:583" + active 0 + pos 69.54885864257812 + pos 112.15332794189453 + ] + node [ + id 228 + label "R_Node:422" + active 0 + pos 101.05796813964844 + pos 132.81764221191406 + ] + node [ + id 229 + label "R_Node:421" + active 0 + pos 102.96003646850586 + pos 133.7566909790039 + ] + node [ + id 230 + label "R_Node:420" + active 0 + pos 104.86210479736329 + pos 134.69573974609375 + ] + node [ + id 231 + label "R_Node:250" + active 0 + pos 42.37858581542969 + pos 22.35539182027181 + ] + node [ + id 232 + label "R_Node:398" + active 0 + pos 127.89154885031961 + pos 139.60025509920987 + ] + node [ + id 233 + label "R_Node:252" + active 0 + pos 38.541847229003906 + pos 18.77341651916504 + ] + node [ + id 234 + label "R_Node:253" + active 0 + pos 37.09257125854492 + pos 18.101320266723633 + ] + node [ + id 235 + label "R_Node:526" + active 0 + pos 63.510460662841794 + pos 132.88221435546876 + ] + node [ + id 236 + label "R_Node:527" + active 0 + pos 63.285498046875 + pos 135.09158172607422 + ] + node [ + id 237 + label "R_Node:256" + active 0 + pos 31.29929847717285 + pos 15.242457962036132 + ] + node [ + id 238 + label "R_Node:257" + active 0 + pos 29.36820755004883 + pos 14.289503860473634 + ] + node [ + id 239 + label "R_Node:513" + active 0 + pos 89.8988265991211 + pos 128.95999145507812 + ] + node [ + id 240 + label "R_Node:512" + active 0 + pos 99.23931121826172 + pos 128.9898681640625 + ] + node [ + id 241 + label "R_Node:458" + active 0 + pos 61.725006103515625 + pos 121.38211059570312 + ] + node [ + id 242 + label "R_Node:459" + active 0 + pos 61.65350786844889 + pos 119.20843251546223 + ] + node [ + id 243 + label "R_Node:517" + active 0 + pos 64.3510144551595 + pos 111.53230158487956 + ] + node [ + id 244 + label "R_Node:516" + active 0 + pos 64.33849334716797 + pos 109.28131103515625 + ] + node [ + id 245 + label "R_Node:515" + active 0 + pos 90.18960571289062 + pos 123.43578338623047 + ] + node [ + id 246 + label "R_Node:514" + active 0 + pos 90.04421615600586 + pos 126.1978874206543 + ] + node [ + id 247 + label "R_Node:452" + active 0 + pos 61.14606857299805 + pos 135.52987670898438 + ] + node [ + id 248 + label "R_Node:453" + active 0 + pos 61.28652420043945 + pos 133.4188674926758 + ] + node [ + id 249 + label "R_Node:519" + active 0 + pos 64.37605667114258 + pos 116.03428268432617 + ] + node [ + id 250 + label "R_Node:518" + active 0 + pos 64.36353556315105 + pos 113.78329213460286 + ] + node [ + id 251 + label "R_Node:456" + active 0 + pos 61.70789108276367 + pos 127.08583984375 + ] + node [ + id 252 + label "R_Node:457" + active 0 + pos 61.84834671020508 + pos 124.9748306274414 + ] + node [ + id 253 + label "R_Node:454" + active 0 + pos 61.42697982788086 + pos 131.3078582763672 + ] + node [ + id 254 + label "R_Node:455" + active 0 + pos 61.56743545532227 + pos 129.19684906005858 + ] + node [ + id 255 + label "R_Node:511" + active 0 + pos 99.34874725341797 + pos 126.38595962524414 + ] + node [ + id 256 + label "R_Node:510" + active 0 + pos 99.45818328857422 + pos 123.78205108642578 + ] + node [ + id 257 + label "R_Node:450" + active 0 + pos 67.5706672668457 + pos 140.12034606933594 + ] + node [ + id 258 + label "R_Node:355" + active 0 + pos 166.90747394967588 + pos 127.1039798817736 + ] + node [ + id 259 + label "R_Node:354" + active 0 + pos 168.8072795462101 + pos 127.80958930482255 + ] + node [ + id 260 + label "R_Node:357" + active 0 + pos 163.10786275660737 + pos 125.6927610356757 + ] + node [ + id 261 + label "R_Node:451" + active 0 + pos 65.65707397460938 + pos 141.1488800048828 + ] + node [ + id 262 + label "R_Node:351" + active 0 + pos 174.50669633581282 + pos 129.92641757396942 + ] + node [ + id 263 + label "R_Node:350" + active 0 + pos 176.40650193234708 + pos 130.63202699701836 + ] + node [ + id 264 + label "R_Node:353" + active 0 + pos 170.70708514274435 + pos 128.5151987278715 + ] + node [ + id 265 + label "R_Node:352" + active 0 + pos 172.60689073927858 + pos 129.22080815092045 + ] + node [ + id 266 + label "R_Node:214" + active 0 + pos 58.277286529541016 + pos 99.49182891845703 + ] + node [ + id 267 + label "R_Node:215" + active 0 + pos 57.57161821637835 + pos 97.43881552559989 + ] + node [ + id 268 + label "R_Node:216" + active 0 + pos 56.86594990321568 + pos 95.38580213274274 + ] + node [ + id 269 + label "R_Node:217" + active 0 + pos 56.16028159005301 + pos 93.3327887398856 + ] + node [ + id 270 + label "R_Node:210" + active 0 + pos 58.41413170950754 + pos 92.72304861886161 + ] + node [ + id 271 + label "R_Node:358" + active 0 + pos 161.20805716007314 + pos 124.98715161262675 + ] + node [ + id 272 + label "R_Node:448" + active 0 + pos 71.39785385131836 + pos 138.0632781982422 + ] + node [ + id 273 + label "R_Node:559" + active 0 + pos 124.39880752563477 + pos 114.96366500854492 + ] + node [ + id 274 + label "R_Node:558" + active 0 + pos 126.9132080078125 + pos 114.74713897705078 + ] + node [ + id 275 + label "R_Node:557" + active 0 + pos 122.32067108154297 + pos 143.33338928222656 + ] + node [ + id 276 + label "R_Node:556" + active 0 + pos 124.96231079101562 + pos 144.14073181152344 + ] + node [ + id 277 + label "R_Node:555" + active 0 + pos 123.02173614501953 + pos 141.43768310546875 + ] + node [ + id 278 + label "R_Node:554" + active 0 + pos 120.79087829589844 + pos 140.38500213623047 + ] + node [ + id 279 + label "R_Node:553" + active 0 + pos 118.56002044677734 + pos 139.3323211669922 + ] + node [ + id 280 + label "R_Node:552" + active 0 + pos 117.19512939453125 + pos 138.37777709960938 + ] + node [ + id 281 + label "R_Node:551" + active 0 + pos 115.36276054382324 + pos 137.48509407043457 + ] + node [ + id 282 + label "R_Node:550" + active 0 + pos 113.53039169311523 + pos 136.59241104125977 + ] + node [ + id 283 + label "R_Node:416" + active 0 + pos 112.47037811279297 + pos 138.45193481445312 + ] + node [ + id 284 + label "R_Node:417" + active 0 + pos 110.56830978393555 + pos 137.51288604736328 + ] + node [ + id 285 + label "R_Node:414" + active 0 + pos 116.2745147705078 + pos 140.3300323486328 + ] + node [ + id 286 + label "R_Node:415" + active 0 + pos 114.3724464416504 + pos 139.39098358154297 + ] + node [ + id 287 + label "R_Node:412" + active 0 + pos 120.07865142822266 + pos 142.2081298828125 + ] + node [ + id 288 + label "R_Node:413" + active 0 + pos 118.17658309936523 + pos 141.26908111572266 + ] + node [ + id 289 + label "R_Node:410" + active 0 + pos 127.1610995205966 + pos 119.7258134321733 + ] + node [ + id 290 + label "R_Node:411" + active 0 + pos 127.32754516601562 + pos 117.65153503417969 + ] + node [ + id 291 + label "R_Node:418" + active 0 + pos 108.66624145507812 + pos 136.57383728027344 + ] + node [ + id 292 + label "R_Node:419" + active 0 + pos 106.7641731262207 + pos 135.6347885131836 + ] + node [ + id 293 + label "R_Node:391" + active 0 + pos 129.15459997003728 + pos 124.43422768332742 + ] + node [ + id 294 + label "R_Node:390" + active 0 + pos 129.33503584428266 + pos 122.26765233820134 + ] + node [ + id 295 + label "R_Node:528" + active 0 + pos 63.0605354309082 + pos 137.3009490966797 + ] + node [ + id 296 + label "R_Node:392" + active 0 + pos 128.9741640957919 + pos 126.60080302845348 + ] + node [ + id 297 + label "R_Node:395" + active 0 + pos 128.43285647305575 + pos 133.1005290638317 + ] + node [ + id 298 + label "R_Node:394" + active 0 + pos 128.61329234730113 + pos 130.93395371870562 + ] + node [ + id 299 + label "R_Node:397" + active 0 + pos 128.071984724565 + pos 137.4336797540838 + ] + node [ + id 300 + label "R_Node:396" + active 0 + pos 128.25242059881037 + pos 135.26710440895775 + ] + node [ + id 301 + label "R_Node:399" + active 0 + pos 127.71111297607422 + pos 141.76683044433594 + ] + node [ + id 302 + label "R_Node:523" + active 0 + pos 64.18534851074219 + pos 126.25411224365234 + ] + node [ + id 303 + label "R_Node:520" + active 0 + pos 64.38857777913411 + pos 118.28527323404948 + ] + node [ + id 304 + label "R_Node:521" + active 0 + pos 64.40109888712566 + pos 120.53626378377278 + ] + node [ + id 305 + label "R_Node:254" + active 0 + pos 35.1614803314209 + pos 17.148366165161132 + ] + node [ + id 306 + label "R_Node:255" + active 0 + pos 33.23038940429687 + pos 16.19541206359863 + ] + node [ + id 307 + label "R_Node:524" + active 0 + pos 63.96038589477539 + pos 128.4634796142578 + ] + node [ + id 308 + label "R_Node:525" + active 0 + pos 63.7354232788086 + pos 130.67284698486327 + ] + node [ + id 309 + label "R_Node:328" + active 0 + pos 218.2022250561004 + pos 146.15543430409534 + ] + node [ + id 310 + label "R_Node:329" + active 0 + pos 216.30241945956615 + pos 145.44982488104637 + ] + node [ + id 311 + label "R_Node:324" + active 0 + pos 224.97506713867188 + pos 145.01560974121094 + ] + node [ + id 312 + label "R_Node:325" + active 0 + pos 223.90164184570312 + pos 148.2722625732422 + ] + node [ + id 313 + label "R_Node:326" + active 0 + pos 222.0018362491689 + pos 147.56665315019325 + ] + node [ + id 314 + label "R_Node:327" + active 0 + pos 220.10203065263465 + pos 146.86104372714428 + ] + node [ + id 315 + label "R_Node:320" + active 0 + pos 217.36786732775101 + pos 142.29067181526347 + ] + node [ + id 316 + label "R_Node:321" + active 0 + pos 219.2696672804812 + pos 142.97190629675032 + ] + node [ + id 317 + label "R_Node:322" + active 0 + pos 221.17146723321144 + pos 143.6531407782372 + ] + node [ + id 318 + label "R_Node:323" + active 0 + pos 223.07326718594166 + pos 144.33437525972408 + ] + node [ + id 319 + label "R_Node:180" + active 0 + pos 48.754188537597656 + pos 28.451602935791016 + ] + node [ + id 320 + label "R_Node:181" + active 0 + pos 48.873538970947266 + pos 30.452623639787948 + ] + node [ + id 321 + label "R_Node:182" + active 0 + pos 48.992889404296875 + pos 32.45364434378488 + ] + node [ + id 322 + label "R_Node:183" + active 0 + pos 49.112239837646484 + pos 34.45466504778181 + ] + node [ + id 323 + label "R_Node:184" + active 0 + pos 49.231590270996094 + pos 36.45568575177874 + ] + node [ + id 324 + label "R_Node:185" + active 0 + pos 49.3509407043457 + pos 38.456706455775674 + ] + node [ + id 325 + label "R_Node:186" + active 0 + pos 49.47029113769531 + pos 40.4577271597726 + ] + node [ + id 326 + label "R_Node:187" + active 0 + pos 49.58964157104492 + pos 42.45874786376953 + ] + node [ + id 327 + label "R_Node:188" + active 0 + pos 49.70899200439453 + pos 44.45976856776646 + ] + node [ + id 328 + label "R_Node:189" + active 0 + pos 49.82834243774414 + pos 46.460789271763396 + ] + node [ + id 329 + label "R_Node:356" + active 0 + pos 165.00766835314164 + pos 126.39837045872466 + ] + node [ + id 330 + label "R_Node:218" + active 0 + pos 55.45461327689035 + pos 91.27977534702846 + ] + node [ + id 331 + label "R_Node:219" + active 0 + pos 54.74894496372768 + pos 89.22676195417132 + ] + node [ + id 332 + label "R_Node:359" + active 0 + pos 159.3082515635389 + pos 124.28154218957779 + ] + node [ + id 333 + label "R_Node:211" + active 0 + pos 59.13609095982143 + pos 94.68306950160435 + ] + node [ + id 334 + label "R_Node:449" + active 0 + pos 69.48426055908203 + pos 139.09181213378906 + ] + node [ + id 335 + label "R_Node:567" + active 0 + pos 105.99969736735027 + pos 121.35093688964844 + ] + node [ + id 336 + label "R_Node:296" + active 0 + pos 171.72466846222574 + pos 125.94104425957863 + ] + node [ + id 337 + label "R_Node:297" + active 0 + pos 173.62646841495595 + pos 126.62227874106549 + ] + node [ + id 338 + label "R_Node:562" + active 0 + pos 117.61172231038411 + pos 117.25505828857422 + ] + node [ + id 339 + label "R_Node:563" + active 0 + pos 115.46932474772136 + pos 118.32209777832031 + ] + node [ + id 340 + label "R_Node:560" + active 0 + pos 121.88440704345703 + pos 115.18019104003906 + ] + node [ + id 341 + label "R_Node:561" + active 0 + pos 119.75411987304688 + pos 116.18801879882812 + ] + node [ + id 342 + label "R_Node:441" + active 0 + pos 89.2180404663086 + pos 132.46986389160156 + ] + node [ + id 343 + label "R_Node:440" + active 0 + pos 91.27174186706543 + pos 132.47150421142578 + ] + node [ + id 344 + label "R_Node:443" + active 0 + pos 83.50938987731934 + pos 133.47468948364258 + ] + node [ + id 345 + label "R_Node:442" + active 0 + pos 85.80358123779297 + pos 132.85723876953125 + ] + node [ + id 346 + label "R_Node:298" + active 0 + pos 175.52826836768617 + pos 127.30351322255237 + ] + node [ + id 347 + label "R_Node:299" + active 0 + pos 177.43006832041638 + pos 127.98474770403922 + ] + node [ + id 348 + label "R_Node:568" + active 0 + pos 103.73926544189453 + pos 121.7582778930664 + ] + node [ + id 349 + label "R_Node:569" + active 0 + pos 98.00495910644531 + pos 122.3366470336914 + ] + node [ + id 350 + label "R_Node:593" + active 0 + pos 242.3580780029297 + pos 145.98580932617188 + ] + node [ + id 351 + label "R_Node:592" + active 0 + pos 237.8785858154297 + pos 144.04434204101562 + ] + node [ + id 352 + label "R_Node:591" + active 0 + pos 234.37088012695312 + pos 144.2286834716797 + ] + node [ + id 353 + label "R_Node:590" + active 0 + pos 232.29957580566406 + pos 146.43507385253906 + ] + node [ + id 354 + label "R_Node:597" + active 0 + pos 230.0952606201172 + pos 149.51654052734375 + ] + node [ + id 355 + label "R_Node:596" + active 0 + pos 235.41139221191406 + pos 150.87991333007812 + ] + node [ + id 356 + label "R_Node:595" + active 0 + pos 239.3179168701172 + pos 150.83837890625 + ] + node [ + id 357 + label "R_Node:594" + active 0 + pos 242.24362182617188 + pos 149.38795471191406 + ] + node [ + id 358 + label "R_Node:522" + active 0 + pos 64.41361999511719 + pos 122.7872543334961 + ] + node [ + id 359 + label "R_Node:368" + active 0 + pos 142.21000119473072 + pos 117.93105738213723 + ] + node [ + id 360 + label "R_Node:369" + active 0 + pos 140.31019559819646 + pos 117.22544795908826 + ] + node [ + id 361 + label "R_Node:360" + active 0 + pos 157.40844596700464 + pos 123.57593276652884 + ] + node [ + id 362 + label "R_Node:361" + active 0 + pos 155.5086403704704 + pos 122.87032334347988 + ] + node [ + id 363 + label "R_Node:362" + active 0 + pos 153.60883477393617 + pos 122.16471392043093 + ] + node [ + id 364 + label "R_Node:363" + active 0 + pos 151.70902917740193 + pos 121.45910449738199 + ] + node [ + id 365 + label "R_Node:364" + active 0 + pos 149.8092235808677 + pos 120.75349507433303 + ] + node [ + id 366 + label "R_Node:365" + active 0 + pos 147.90941798433346 + pos 120.04788565128408 + ] + node [ + id 367 + label "R_Node:366" + active 0 + pos 146.00961238779922 + pos 119.34227622823512 + ] + node [ + id 368 + label "R_Node:367" + active 0 + pos 144.10980679126496 + pos 118.63666680518617 + ] + node [ + id 369 + label "R_Node:203" + active 0 + pos 53.78477401733399 + pos 76.9343147277832 + ] + node [ + id 370 + label "R_Node:202" + active 0 + pos 53.404009628295896 + pos 74.79874992370605 + ] + node [ + id 371 + label "R_Node:201" + active 0 + pos 53.02324523925781 + pos 72.6631851196289 + ] + node [ + id 372 + label "R_Node:200" + active 0 + pos 52.64248085021973 + pos 70.52762031555176 + ] + node [ + id 373 + label "R_Node:207" + active 0 + pos 56.24825395856585 + pos 86.84298597063336 + ] + node [ + id 374 + label "R_Node:206" + active 0 + pos 55.52629470825195 + pos 84.88296508789062 + ] + node [ + id 375 + label "R_Node:205" + active 0 + pos 54.546302795410156 + pos 81.2054443359375 + ] + node [ + id 376 + label "R_Node:204" + active 0 + pos 54.16553840637207 + pos 79.06987953186035 + ] + node [ + id 377 + label "R_Node:209" + active 0 + pos 57.692172459193635 + pos 90.76302773611886 + ] + node [ + id 378 + label "R_Node:208" + active 0 + pos 56.97021320887974 + pos 88.80300685337612 + ] + node [ + id 379 + label "R_Node:167" + active 0 + pos 28.53135108947754 + pos 11.144851684570312 + ] + node [ + id 380 + label "R_Node:571" + active 0 + pos 93.82036844889323 + pos 122.10953521728516 + ] + node [ + id 381 + label "R_Node:570" + active 0 + pos 95.91266377766927 + pos 122.22309112548828 + ] + edge [ + source 0 + target 3 + weight 2.080945704544439 + ] + edge [ + source 1 + target 0 + weight 2.0809457045444106 + ] + edge [ + source 2 + target 9 + weight 2.080945704544425 + ] + edge [ + source 3 + target 2 + weight 2.0809457045444106 + ] + edge [ + source 4 + target 7 + weight 2.080945704544439 + ] + edge [ + source 5 + target 4 + weight 2.0809457045444106 + ] + edge [ + source 6 + target 1 + weight 2.080945704544439 + ] + edge [ + source 7 + target 6 + weight 2.0809457045444115 + ] + edge [ + source 8 + target 289 + weight 2.080945704544425 + ] + edge [ + source 9 + target 8 + weight 2.0809457045444257 + ] + edge [ + source 10 + target 11 + weight 2.1563725946088415 + ] + edge [ + source 11 + target 83 + weight 2.6851347633192657 + ] + edge [ + source 12 + target 145 + weight 2.050959601572082 + ] + edge [ + source 13 + target 14 + weight 2.344632696692467 + ] + edge [ + source 14 + target 12 + weight 2.0508491500118478 + ] + edge [ + source 15 + target 16 + weight 2.344632696692467 + ] + edge [ + source 16 + target 13 + weight 2.344632696692467 + ] + edge [ + source 17 + target 173 + weight 4.524166590736115 + ] + edge [ + source 17 + target 239 + weight 4.044790633199692 + ] + edge [ + source 18 + target 17 + weight 2.15783822867493 + ] + edge [ + source 19 + target 231 + weight 2.624457564826847 + ] + edge [ + source 20 + target 19 + weight 3.169063260658222 + ] + edge [ + source 21 + target 20 + weight 2.084872062095125 + ] + edge [ + source 22 + target 21 + weight 2.084872062095129 + ] + edge [ + source 23 + target 22 + weight 2.084872062095125 + ] + edge [ + source 24 + target 120 + weight 2.2495422083609298 + ] + edge [ + source 25 + target 121 + weight 2.084872062095129 + ] + edge [ + source 26 + target 25 + weight 2.084872062095129 + ] + edge [ + source 27 + target 18 + weight 2.157838228674922 + ] + edge [ + source 28 + target 124 + weight 2.084872062095129 + ] + edge [ + source 29 + target 130 + weight 2.0201295698472737 + ] + edge [ + source 30 + target 37 + weight 2.0266094745950203 + ] + edge [ + source 31 + target 30 + weight 2.02660947459501 + ] + edge [ + source 32 + target 31 + weight 2.0266094745950367 + ] + edge [ + source 33 + target 32 + weight 2.0266094745950203 + ] + edge [ + source 34 + target 204 + weight 2.026609474595047 + ] + edge [ + source 35 + target 34 + weight 2.02660947459501 + ] + edge [ + source 36 + target 35 + weight 2.0266094745950203 + ] + edge [ + source 37 + target 36 + weight 2.02660947459501 + ] + edge [ + source 38 + target 39 + weight 2.0097202911722882 + ] + edge [ + source 39 + target 44 + weight 2.31111402055776 + ] + edge [ + source 40 + target 41 + weight 2.0097202911722802 + ] + edge [ + source 41 + target 38 + weight 2.0097202911722882 + ] + edge [ + source 42 + target 43 + weight 2.084872062095129 + ] + edge [ + source 43 + target 191 + weight 2.0848720620951293 + ] + edge [ + source 44 + target 45 + weight 2.084872062095129 + ] + edge [ + source 45 + target 42 + weight 2.084872062095129 + ] + edge [ + source 46 + target 55 + weight 2.1692437743076782 + ] + edge [ + source 47 + target 46 + weight 2.169243774307677 + ] + edge [ + source 48 + target 47 + weight 2.169243774307677 + ] + edge [ + source 49 + target 48 + weight 3.3984004312346316 + ] + edge [ + source 50 + target 49 + weight 2.004576859031627 + ] + edge [ + source 51 + target 50 + weight 2.004576859031627 + ] + edge [ + source 52 + target 51 + weight 2.004576859031627 + ] + edge [ + source 53 + target 52 + weight 2.004576859031634 + ] + edge [ + source 54 + target 372 + weight 2.169243774307677 + ] + edge [ + source 55 + target 54 + weight 2.169243774307677 + ] + edge [ + source 56 + target 137 + weight 2.0201295698472737 + ] + edge [ + source 57 + target 40 + weight 2.009720291172295 + ] + edge [ + source 58 + target 133 + weight 2.0201295698472737 + ] + edge [ + source 59 + target 58 + weight 2.0201295698472737 + ] + edge [ + source 60 + target 57 + weight 2.009720291172281 + ] + edge [ + source 61 + target 68 + weight 2.0201295698472737 + ] + edge [ + source 62 + target 61 + weight 2.0201295698472737 + ] + edge [ + source 63 + target 62 + weight 2.0201295698472737 + ] + edge [ + source 64 + target 63 + weight 2.0201295698473003 + ] + edge [ + source 65 + target 59 + weight 2.0201295698472737 + ] + edge [ + source 66 + target 65 + weight 2.0201295698473003 + ] + edge [ + source 67 + target 66 + weight 2.0201295698472737 + ] + edge [ + source 68 + target 67 + weight 2.0201295698472737 + ] + edge [ + source 69 + target 72 + weight 2.008766241196523 + ] + edge [ + source 70 + target 69 + weight 2.0087662411965184 + ] + edge [ + source 71 + target 82 + weight 2.4826503466580028 + ] + edge [ + source 72 + target 71 + weight 1.6212559320143511 + ] + edge [ + source 73 + target 74 + weight 2.3142928157940905 + ] + edge [ + source 74 + target 135 + weight 2.3142928157940883 + ] + edge [ + source 75 + target 70 + weight 2.008766241196523 + ] + edge [ + source 76 + target 75 + weight 3.0159193917421874 + ] + edge [ + source 77 + target 78 + weight 2.305332595709828 + ] + edge [ + source 78 + target 79 + weight 2.305332595709809 + ] + edge [ + source 79 + target 80 + weight 2.305332595709828 + ] + edge [ + source 80 + target 73 + weight 1.719492332043214 + ] + edge [ + source 81 + target 224 + weight 1.8130070136264997 + ] + edge [ + source 82 + target 81 + weight 2.4826503466580028 + ] + edge [ + source 83 + target 84 + weight 2.305332595709828 + ] + edge [ + source 84 + target 77 + weight 2.305332595709809 + ] + edge [ + source 85 + target 60 + weight 2.881220803806643 + ] + edge [ + source 86 + target 85 + weight 2.3791843214815556 + ] + edge [ + source 87 + target 193 + weight 5.6693533942322825 + ] + edge [ + source 87 + target 274 + weight 7.706053759144949 + ] + edge [ + source 88 + target 87 + weight 2.0266094745950154 + ] + edge [ + source 89 + target 88 + weight 2.0266094745950154 + ] + edge [ + source 90 + target 319 + weight 3.0786711954567356 + ] + edge [ + source 91 + target 90 + weight 2.0448861860374254 + ] + edge [ + source 92 + target 266 + weight 7.288995173663438 + ] + edge [ + source 93 + target 195 + weight 4.660685932840957 + ] + edge [ + source 94 + target 93 + weight 4.711681034165182 + ] + edge [ + source 94 + target 201 + weight 3.7287614645841507 + ] + edge [ + source 95 + target 96 + weight 10.820132247981824 + ] + edge [ + source 96 + target 379 + weight 5.173343655600031 + ] + edge [ + source 97 + target 100 + weight 2.044886186037433 + ] + edge [ + source 98 + target 97 + weight 2.0448861860374272 + ] + edge [ + source 99 + target 102 + weight 2.044886186037433 + ] + edge [ + source 100 + target 99 + weight 2.0448861860374254 + ] + edge [ + source 101 + target 104 + weight 2.0448861860374254 + ] + edge [ + source 102 + target 101 + weight 2.0448861860374272 + ] + edge [ + source 103 + target 91 + weight 2.0448861860374272 + ] + edge [ + source 104 + target 103 + weight 2.044886186037433 + ] + edge [ + source 105 + target 117 + weight 2.0201295698472737 + ] + edge [ + source 106 + target 107 + weight 2.0201295698472688 + ] + edge [ + source 107 + target 208 + weight 2.0201295698472785 + ] + edge [ + source 108 + target 109 + weight 2.0201295698472688 + ] + edge [ + source 109 + target 114 + weight 2.0201295698472785 + ] + edge [ + source 110 + target 111 + weight 2.0201295698472954 + ] + edge [ + source 111 + target 108 + weight 2.0201295698472785 + ] + edge [ + source 112 + target 113 + weight 2.0201295698472688 + ] + edge [ + source 113 + target 106 + weight 2.020129569847305 + ] + edge [ + source 114 + target 115 + weight 2.0201295698472688 + ] + edge [ + source 115 + target 112 + weight 2.0201295698472785 + ] + edge [ + source 116 + target 24 + weight 2.2495422083609298 + ] + edge [ + source 117 + target 119 + weight 2.0201295698472737 + ] + edge [ + source 118 + target 116 + weight 2.2495422083609298 + ] + edge [ + source 119 + target 64 + weight 2.0201295698472737 + ] + edge [ + source 120 + target 123 + weight 2.117142392013725 + ] + edge [ + source 121 + target 23 + weight 2.0848720620951293 + ] + edge [ + source 122 + target 125 + weight 2.157838228674922 + ] + edge [ + source 123 + target 122 + weight 2.15783822867493 + ] + edge [ + source 124 + target 26 + weight 2.084872062095129 + ] + edge [ + source 125 + target 27 + weight 2.15783822867493 + ] + edge [ + source 126 + target 127 + weight 2.053702055829841 + ] + edge [ + source 127 + target 343 + weight 2.053702055829841 + ] + edge [ + source 128 + target 126 + weight 2.053702055829841 + ] + edge [ + source 129 + target 335 + weight 2.2968411313551944 + ] + edge [ + source 130 + target 336 + weight 2.0201295698472785 + ] + edge [ + source 131 + target 132 + weight 3.0317600105642475 + ] + edge [ + source 132 + target 129 + weight 2.2968411313552086 + ] + edge [ + source 133 + target 56 + weight 2.0201295698472737 + ] + edge [ + source 134 + target 136 + weight 2.3142928157940883 + ] + edge [ + source 135 + target 134 + weight 2.3142928157941047 + ] + edge [ + source 136 + target 15 + weight 4.0806922305340105 + ] + edge [ + source 136 + target 256 + weight 5.306902472231597 + ] + edge [ + source 137 + target 138 + weight 2.0201295698472737 + ] + edge [ + source 138 + target 29 + weight 2.0201295698473003 + ] + edge [ + source 139 + target 193 + weight 6.389117780975195 + ] + edge [ + source 139 + target 140 + weight 2.451369978022462 + ] + edge [ + source 140 + target 105 + weight 6.685272580394912 + ] + edge [ + source 141 + target 142 + weight 2.050959601572082 + ] + edge [ + source 142 + target 143 + weight 2.533264682856116 + ] + edge [ + source 143 + target 144 + weight 2.451369978022462 + ] + edge [ + source 144 + target 139 + weight 2.451369978022478 + ] + edge [ + source 145 + target 146 + weight 2.0509596015720954 + ] + edge [ + source 146 + target 147 + weight 2.050959601572082 + ] + edge [ + source 147 + target 148 + weight 2.050959601572082 + ] + edge [ + source 148 + target 141 + weight 2.0509596015720954 + ] + edge [ + source 149 + target 152 + weight 2.375828146737143 + ] + edge [ + source 150 + target 149 + weight 2.375828146737143 + ] + edge [ + source 151 + target 272 + weight 2.17249196653599 + ] + edge [ + source 152 + target 151 + weight 3.7293320576746427 + ] + edge [ + source 153 + target 154 + weight 2.0266094745950367 + ] + edge [ + source 154 + target 167 + weight 2.0266094745950203 + ] + edge [ + source 155 + target 156 + weight 2.02660947459501 + ] + edge [ + source 156 + target 153 + weight 2.0266094745950203 + ] + edge [ + source 157 + target 158 + weight 2.0266094745950203 + ] + edge [ + source 158 + target 155 + weight 2.02660947459501 + ] + edge [ + source 159 + target 160 + weight 2.0266094745950203 + ] + edge [ + source 160 + target 157 + weight 2.0266094745950367 + ] + edge [ + source 161 + target 164 + weight 2.425565488150257 + ] + edge [ + source 162 + target 161 + weight 2.170905746330924 + ] + edge [ + source 163 + target 166 + weight 2.3791843214815556 + ] + edge [ + source 164 + target 163 + weight 2.3791843214815556 + ] + edge [ + source 165 + target 86 + weight 2.3791843214815556 + ] + edge [ + source 166 + target 165 + weight 2.3791843214815707 + ] + edge [ + source 167 + target 168 + weight 2.02660947459501 + ] + edge [ + source 168 + target 263 + weight 2.0266094745950203 + ] + edge [ + source 169 + target 353 + weight 3.1145503622423827 + ] + edge [ + source 170 + target 233 + weight 2.624457564826847 + ] + edge [ + source 171 + target 172 + weight 2.0382489042365974 + ] + edge [ + source 172 + target 282 + weight 2.0382489042365974 + ] + edge [ + source 173 + target 174 + weight 2.3384780366479583 + ] + edge [ + source 174 + target 175 + weight 2.338478036647957 + ] + edge [ + source 175 + target 176 + weight 2.3384780366479583 + ] + edge [ + source 176 + target 240 + weight 1.6460144334365205 + ] + edge [ + source 176 + target 177 + weight 4.901080580440689 + ] + edge [ + source 177 + target 178 + weight 2.0382489042365974 + ] + edge [ + source 178 + target 179 + weight 2.0382489042365974 + ] + edge [ + source 179 + target 180 + weight 2.0382489042365974 + ] + edge [ + source 180 + target 171 + weight 2.0382489042365974 + ] + edge [ + source 181 + target 188 + weight 2.174853648900859 + ] + edge [ + source 182 + target 181 + weight 2.1748536489008443 + ] + edge [ + source 182 + target 189 + weight 8.23392045249578 + ] + edge [ + source 183 + target 182 + weight 2.174853648900859 + ] + edge [ + source 184 + target 183 + weight 2.174853648900859 + ] + edge [ + source 185 + target 190 + weight 2.1563725946088415 + ] + edge [ + source 186 + target 185 + weight 2.156372594608821 + ] + edge [ + source 186 + target 244 + weight 4.70128382122134 + ] + edge [ + source 187 + target 186 + weight 2.1563725946088415 + ] + edge [ + source 188 + target 92 + weight 2.094461599956369 + ] + edge [ + source 189 + target 10 + weight 2.156372594608821 + ] + edge [ + source 190 + target 189 + weight 2.1563725946088415 + ] + edge [ + source 191 + target 192 + weight 2.0848720620951218 + ] + edge [ + source 192 + target 28 + weight 2.084872062095129 + ] + edge [ + source 193 + target 194 + weight 2.174075856731501 + ] + edge [ + source 194 + target 294 + weight 2.1740758567315037 + ] + edge [ + source 195 + target 196 + weight 6.83982909994315 + ] + edge [ + source 196 + target 199 + weight 4.400971647391255 + ] + edge [ + source 197 + target 93 + weight 4.939000353494403 + ] + edge [ + source 198 + target 202 + weight 6.477726671879712 + ] + edge [ + source 199 + target 200 + weight 5.640031883851785 + ] + edge [ + source 200 + target 96 + weight 3.467744111707182 + ] + edge [ + source 201 + target 95 + weight 5.963733527964965 + ] + edge [ + source 202 + target 197 + weight 6.271569812406168 + ] + edge [ + source 203 + target 159 + weight 2.02660947459501 + ] + edge [ + source 204 + target 203 + weight 2.02660947459501 + ] + edge [ + source 205 + target 315 + weight 2.0201295698472954 + ] + edge [ + source 206 + target 205 + weight 2.0201295698472785 + ] + edge [ + source 207 + target 210 + weight 2.0201295698472785 + ] + edge [ + source 208 + target 207 + weight 2.0201295698472688 + ] + edge [ + source 209 + target 212 + weight 2.0201295698472514 + ] + edge [ + source 210 + target 209 + weight 2.0201295698472954 + ] + edge [ + source 211 + target 214 + weight 2.0201295698472688 + ] + edge [ + source 212 + target 211 + weight 2.020129569847305 + ] + edge [ + source 213 + target 206 + weight 2.0201295698472785 + ] + edge [ + source 214 + target 213 + weight 2.0201295698472688 + ] + edge [ + source 215 + target 216 + weight 2.0448861860374272 + ] + edge [ + source 216 + target 98 + weight 2.0448861860374294 + ] + edge [ + source 217 + target 198 + weight 9.063731444889704 + ] + edge [ + source 218 + target 298 + weight 2.1740758567315037 + ] + edge [ + source 219 + target 118 + weight 2.2495422083609298 + ] + edge [ + source 220 + target 221 + weight 2.017235729912668 + ] + edge [ + source 220 + target 250 + weight 4.577018740482775 + ] + edge [ + source 221 + target 222 + weight 2.017235729912668 + ] + edge [ + source 222 + target 223 + weight 2.017235729912668 + ] + edge [ + source 223 + target 92 + weight 2.397953772004691 + ] + edge [ + source 224 + target 225 + weight 2.7402723992389246 + ] + edge [ + source 225 + target 226 + weight 2.7402723992389246 + ] + edge [ + source 226 + target 227 + weight 1.8264562889263969 + ] + edge [ + source 227 + target 220 + weight 2.017235729912668 + ] + edge [ + source 228 + target 128 + weight 3.6411452997300513 + ] + edge [ + source 229 + target 228 + weight 2.1212440959529935 + ] + edge [ + source 230 + target 229 + weight 2.1212440959529935 + ] + edge [ + source 231 + target 170 + weight 2.624457564826845 + ] + edge [ + source 232 + target 301 + weight 2.1740758567315024 + ] + edge [ + source 233 + target 234 + weight 1.597533790282889 + ] + edge [ + source 234 + target 305 + weight 2.153423713184546 + ] + edge [ + source 235 + target 236 + weight 2.2207909304747084 + ] + edge [ + source 236 + target 295 + weight 2.2207909304747084 + ] + edge [ + source 237 + target 238 + weight 2.153423713184542 + ] + edge [ + source 238 + target 217 + weight 2.153423713184546 + ] + edge [ + source 239 + target 246 + weight 2.765927840749201 + ] + edge [ + source 240 + target 177 + weight 3.9894671648196076 + ] + edge [ + source 241 + target 242 + weight 2.174853648900859 + ] + edge [ + source 242 + target 184 + weight 2.1748536489008443 + ] + edge [ + source 243 + target 250 + weight 2.2510253737105965 + ] + edge [ + source 244 + target 243 + weight 2.2510253737106103 + ] + edge [ + source 245 + target 134 + weight 4.1708129992210425 + ] + edge [ + source 245 + target 75 + weight 2.131895612368234 + ] + edge [ + source 246 + target 245 + weight 2.765927840749201 + ] + edge [ + source 247 + target 248 + weight 2.115676651716835 + ] + edge [ + source 248 + target 253 + weight 2.115676651716835 + ] + edge [ + source 249 + target 303 + weight 2.2510253737106103 + ] + edge [ + source 250 + target 249 + weight 2.2510253737106103 + ] + edge [ + source 251 + target 252 + weight 2.115676651716835 + ] + edge [ + source 252 + target 241 + weight 3.5948365931864052 + ] + edge [ + source 253 + target 254 + weight 2.1156766517168637 + ] + edge [ + source 254 + target 251 + weight 2.115676651716835 + ] + edge [ + source 255 + target 240 + weight 2.6062071913648546 + ] + edge [ + source 256 + target 255 + weight 2.6062071913648546 + ] + edge [ + source 257 + target 261 + weight 2.17249196653599 + ] + edge [ + source 258 + target 329 + weight 2.02660947459501 + ] + edge [ + source 259 + target 258 + weight 2.0266094745950154 + ] + edge [ + source 260 + target 271 + weight 2.0266094745950154 + ] + edge [ + source 261 + target 247 + weight 7.205717713918863 + ] + edge [ + source 262 + target 265 + weight 2.0266094745950203 + ] + edge [ + source 263 + target 262 + weight 2.0266094745950367 + ] + edge [ + source 264 + target 259 + weight 2.0266094745950154 + ] + edge [ + source 265 + target 264 + weight 2.02660947459501 + ] + edge [ + source 266 + target 267 + weight 2.170905746330924 + ] + edge [ + source 267 + target 268 + weight 2.170905746330938 + ] + edge [ + source 268 + target 269 + weight 2.170905746330924 + ] + edge [ + source 269 + target 330 + weight 2.170905746330922 + ] + edge [ + source 270 + target 333 + weight 2.088757290807486 + ] + edge [ + source 271 + target 332 + weight 2.0266094745950154 + ] + edge [ + source 272 + target 334 + weight 2.17249196653599 + ] + edge [ + source 273 + target 340 + weight 2.5237062640272194 + ] + edge [ + source 274 + target 273 + weight 2.5237062640272194 + ] + edge [ + source 275 + target 287 + weight 2.508557522131839 + ] + edge [ + source 276 + target 275 + weight 2.7622567430045772 + ] + edge [ + source 277 + target 5 + weight 2.657873463993669 + ] + edge [ + source 278 + target 277 + weight 2.466751703350307 + ] + edge [ + source 279 + target 278 + weight 2.466751703350307 + ] + edge [ + source 280 + target 279 + weight 1.665557552616292 + ] + edge [ + source 281 + target 280 + weight 2.0382489042365974 + ] + edge [ + source 282 + target 281 + weight 2.0382489042365974 + ] + edge [ + source 283 + target 284 + weight 2.1212440959529935 + ] + edge [ + source 284 + target 291 + weight 2.1212440959529935 + ] + edge [ + source 285 + target 286 + weight 2.1212440959529806 + ] + edge [ + source 286 + target 283 + weight 2.1212440959529935 + ] + edge [ + source 287 + target 288 + weight 2.1212440959529935 + ] + edge [ + source 288 + target 285 + weight 2.1212440959529935 + ] + edge [ + source 289 + target 290 + weight 2.080945704544425 + ] + edge [ + source 290 + target 140 + weight 5.887227379628547 + ] + edge [ + source 290 + target 273 + weight 3.9751917489461412 + ] + edge [ + source 291 + target 292 + weight 2.1212440959529935 + ] + edge [ + source 292 + target 230 + weight 2.1212440959529806 + ] + edge [ + source 293 + target 296 + weight 2.174075856731501 + ] + edge [ + source 294 + target 293 + weight 2.1740758567315153 + ] + edge [ + source 295 + target 219 + weight 2.85296831440672 + ] + edge [ + source 296 + target 218 + weight 2.1740758567315153 + ] + edge [ + source 297 + target 300 + weight 2.174075856731501 + ] + edge [ + source 298 + target 297 + weight 2.174075856731501 + ] + edge [ + source 299 + target 232 + weight 2.1740758567315024 + ] + edge [ + source 300 + target 299 + weight 2.174075856731501 + ] + edge [ + source 301 + target 276 + weight 3.6319858416185467 + ] + edge [ + source 302 + target 307 + weight 2.2207909304747084 + ] + edge [ + source 303 + target 304 + weight 2.2510253737105965 + ] + edge [ + source 304 + target 358 + weight 2.2510253737106103 + ] + edge [ + source 305 + target 306 + weight 2.153423713184546 + ] + edge [ + source 306 + target 237 + weight 2.153423713184542 + ] + edge [ + source 307 + target 308 + weight 2.2207909304747084 + ] + edge [ + source 308 + target 235 + weight 2.2207909304747377 + ] + edge [ + source 309 + target 310 + weight 2.0266094745950203 + ] + edge [ + source 310 + target 33 + weight 2.02660947459501 + ] + edge [ + source 311 + target 169 + weight 4.412921766820168 + ] + edge [ + source 312 + target 313 + weight 2.02660947459501 + ] + edge [ + source 313 + target 314 + weight 2.0266094745950203 + ] + edge [ + source 314 + target 309 + weight 2.0266094745950367 + ] + edge [ + source 315 + target 316 + weight 2.020129569847242 + ] + edge [ + source 316 + target 317 + weight 2.020129569847305 + ] + edge [ + source 317 + target 318 + weight 2.0201295698472785 + ] + edge [ + source 318 + target 311 + weight 2.0201295698472688 + ] + edge [ + source 319 + target 320 + weight 2.0045768590316304 + ] + edge [ + source 320 + target 321 + weight 2.0045768590316304 + ] + edge [ + source 321 + target 322 + weight 2.004576859031627 + ] + edge [ + source 322 + target 323 + weight 2.004576859031627 + ] + edge [ + source 323 + target 324 + weight 2.004576859031634 + ] + edge [ + source 324 + target 325 + weight 2.004576859031627 + ] + edge [ + source 325 + target 326 + weight 2.004576859031627 + ] + edge [ + source 326 + target 327 + weight 2.004576859031627 + ] + edge [ + source 327 + target 328 + weight 2.004576859031634 + ] + edge [ + source 328 + target 53 + weight 2.004576859031627 + ] + edge [ + source 329 + target 260 + weight 2.0266094745950416 + ] + edge [ + source 330 + target 331 + weight 2.170905746330924 + ] + edge [ + source 331 + target 162 + weight 2.170905746330938 + ] + edge [ + source 332 + target 361 + weight 2.0266094745950416 + ] + edge [ + source 333 + target 187 + weight 9.07592326946155 + ] + edge [ + source 334 + target 257 + weight 2.17249196653599 + ] + edge [ + source 335 + target 348 + weight 2.2968411313552086 + ] + edge [ + source 336 + target 337 + weight 2.0201295698472688 + ] + edge [ + source 337 + target 346 + weight 2.0201295698472785 + ] + edge [ + source 338 + target 339 + weight 2.393416091944921 + ] + edge [ + source 339 + target 131 + weight 2.393416091944934 + ] + edge [ + source 340 + target 341 + weight 2.356658698199613 + ] + edge [ + source 341 + target 338 + weight 2.393416091944934 + ] + edge [ + source 342 + target 345 + weight 3.4363630656911903 + ] + edge [ + source 343 + target 342 + weight 2.053702055829841 + ] + edge [ + source 343 + target 239 + weight 3.770360482891123 + ] + edge [ + source 344 + target 150 + weight 2.375828146737143 + ] + edge [ + source 345 + target 344 + weight 2.375828146737143 + ] + edge [ + source 346 + target 347 + weight 2.0201295698472688 + ] + edge [ + source 347 + target 110 + weight 2.0201295698472785 + ] + edge [ + source 348 + target 256 + weight 4.735327057515424 + ] + edge [ + source 348 + target 349 + weight 5.763400039178293 + ] + edge [ + source 349 + target 381 + weight 2.095374593504918 + ] + edge [ + source 350 + target 357 + weight 3.404070128849415 + ] + edge [ + source 351 + target 350 + weight 4.88212509847971 + ] + edge [ + source 352 + target 351 + weight 3.5125462217642216 + ] + edge [ + source 353 + target 352 + weight 3.026294781434803 + ] + edge [ + source 354 + target 312 + weight 6.317368213887609 + ] + edge [ + source 355 + target 354 + weight 5.488172783407658 + ] + edge [ + source 356 + target 355 + weight 3.9067454503092183 + ] + edge [ + source 357 + target 356 + weight 3.2654984050521314 + ] + edge [ + source 358 + target 302 + weight 3.474364926111206 + ] + edge [ + source 359 + target 360 + weight 2.026609474595047 + ] + edge [ + source 360 + target 89 + weight 2.02660947459501 + ] + edge [ + source 361 + target 362 + weight 2.0266094745950154 + ] + edge [ + source 362 + target 363 + weight 2.0266094745950154 + ] + edge [ + source 363 + target 364 + weight 2.02660947459501 + ] + edge [ + source 364 + target 365 + weight 2.0266094745950154 + ] + edge [ + source 365 + target 366 + weight 2.0266094745950154 + ] + edge [ + source 366 + target 367 + weight 2.0266094745950154 + ] + edge [ + source 367 + target 368 + weight 2.0266094745950416 + ] + edge [ + source 368 + target 359 + weight 2.02660947459501 + ] + edge [ + source 369 + target 376 + weight 2.169243774307677 + ] + edge [ + source 370 + target 369 + weight 2.1692437743076782 + ] + edge [ + source 371 + target 370 + weight 2.169243774307677 + ] + edge [ + source 372 + target 371 + weight 2.169243774307677 + ] + edge [ + source 373 + target 378 + weight 2.088757290807499 + ] + edge [ + source 374 + target 373 + weight 2.088757290807486 + ] + edge [ + source 375 + target 374 + weight 3.805856412199651 + ] + edge [ + source 376 + target 375 + weight 2.169243774307677 + ] + edge [ + source 377 + target 270 + weight 2.0887572908075014 + ] + edge [ + source 378 + target 377 + weight 2.088757290807486 + ] + edge [ + source 379 + target 215 + weight 2.0448861860374294 + ] + edge [ + source 380 + target 76 + weight 2.095374593504918 + ] + edge [ + source 381 + target 380 + weight 2.095374593504904 + ] +] diff --git a/cart_endpoints/launch/hardware_interface.launch b/cart_endpoints/launch/hardware_interface.launch index 162b9ab6..543244c0 100644 --- a/cart_endpoints/launch/hardware_interface.launch +++ b/cart_endpoints/launch/hardware_interface.launch @@ -34,9 +34,9 @@ " /> - - + diff --git a/cart_planning/launch/constants.launch b/cart_planning/launch/constants.launch index 0672ca32..5a23be79 100755 --- a/cart_planning/launch/constants.launch +++ b/cart_planning/launch/constants.launch @@ -9,6 +9,6 @@ anchor_theta : 0 - graph_file : "/home/jeffercize/catkin_ws/src/ai-navigation/EastCampusLiteV4.gml" + graph_file : "/home/jeffercize/catkin_ws/src/ai-navigation/EastCampusLiteV5.gml" diff --git a/cart_planning/scripts/affine.py b/cart_planning/scripts/affine.py deleted file mode 100755 index 6e4aaac0..00000000 --- a/cart_planning/scripts/affine.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python - -import transformations -import gps_util -import numpy as np - -anchor_lat = 38.432147 # 38.431960 -anchor_long = -78.876115 # -78.875910 -anchor_elev = 396 #meters above sea level -anchor_theta = 0 #angle pointing directly north, originally: 0 - - -#X -v0 = [[35.9750671387, -14.0169754028, --3.60410761833, -17.4223442078, -30.7783546448, -59.0794563293, -47.9315681458], -#Y -[36.4229431152, -1.30921435356, -8.7294960022, -46.9932327271, -43.7685050964, -72.0065460205, -86.720085144]] - - - - - -#Latitude -v1 = [[38.431686, -38.432053, -38.432108, -38.431724, -38.431672, -38.431312, -38.431282], -#Longitude -[-78.876137, --78.876221, --78.876016, --78.875895, --78.876047, --78.876070, --78.875866]] - -affine = transformations.affine_matrix_from_points(v0, v1) -# print(affine) - -'''#!/usr/bin/env python - -import transformations - -#X -v0 = [[36.4229431152, -1.30921435356, -8.7294960022, -46.9932327271, -43.7685050964, -72.0065460205, -86.720085144], -#Y -[35.9750671387, -14.0169754028, --3.60410761833, -17.4223442078, -30.7783546448, -59.0794563293, -47.9315681458]] - - - -#Latitude -v1 = [[-78.876137, --78.876221, --78.876016, --78.875895, --78.876047, --78.876070, --78.875866], -#Longitude -[38.431686, -38.432053, -38.432108, -38.431724, -38.431672, -38.431312, -38.431282]] - - - - -affine = transformations.affine_matrix_from_points(v0, v1) -print(affine) -''' diff --git a/cart_planning/scripts/cubic_spline_planner.pyc b/cart_planning/scripts/cubic_spline_planner.pyc index 95f96db1..10c0cff5 100644 Binary files a/cart_planning/scripts/cubic_spline_planner.pyc and b/cart_planning/scripts/cubic_spline_planner.pyc differ diff --git a/cart_planning/scripts/global_planner.py b/cart_planning/scripts/global_planner.py index 4af0650b..901dfd7b 100755 --- a/cart_planning/scripts/global_planner.py +++ b/cart_planning/scripts/global_planner.py @@ -37,6 +37,9 @@ def __init__(self): #The points on the map self.local_array = None + # Minimizng travel will have the cart stop when its closest to the passenger regardless of which side of the road the summon comes from + self.minimize_travel = True + # Temporary solution for destinations, TODO: Make destinations embedded in graph nodes self.dest_dict = {"home":(22.9, 4.21), "cafeteria":(127, 140), "clinic":(63.3, 130), "reccenter":(73.7, 113), "office":(114, 117)} @@ -100,6 +103,7 @@ def calc_nav(self, point): # Get the node closest to where we want to go destination_point = self.get_closest_node(point.x, point.y) + """ # Remove our previous node to prevent searching directly behind cart name = None @@ -132,7 +136,12 @@ def calc_nav(self, point): rospy.loginfo("Out edge: u,v " + str(u) + "," + str(v)) self.global_graph.add_edge(name, v, weight=data['weight']) - + """ + if self.minimize_travel: + nodelist = self.calc_efficient_destination(destination_point) + else: + nodelist = nx.dijkstra_path(self.global_graph, self.current_cart_node, destination_point) + # Set all nodes back to a state of not being a part of the previous/current path for node in self.global_graph: self.global_graph.node[node]['active'] = False @@ -149,6 +158,44 @@ def calc_nav(self, point): self.logic_graph = copy.deepcopy(self.global_graph) self.path_pub.publish(points_arr) + def calc_efficient_destination(self, destination): + # Find nodes within 3 meters of destination node + close_nodes = [destination] + local_logic_graph = copy.deepcopy(self.logic_graph) + dest_node_pos = local_logic_graph.node[destination]['pos'] + + for node in self.global_graph.nodes: + inefficient = True + node_pos = local_logic_graph.node[node]['pos'] + + # Is node close enough and also not incident to the destination + dist = self.dis(node_pos[0], node_pos[1], dest_node_pos[0], dest_node_pos[1]) + if dist < 3 and node is not destination: + for u, v in local_logic_graph.out_edges(node): + if u is destination or v is destination: + inefficient = True + break + else: + inefficient = False + + # if node is not an inefficient destination add it + if not inefficient: + close_nodes.append(node) + + min_path = None + # Out of the most efficient paths, which one has the least driving distance + for node in close_nodes: + node_path = nx.dijkstra_path(local_logic_graph, self.current_cart_node, node) + if min_path is None: + min_path = node_path + + # TODO replace with cost analysis + if len(node_path) < len(min_path): + min_path = node_path + + return min_path + + # Closest node to given point def get_closest_node(self, x, y, cart_trans=False): min_dist = 99999 diff --git a/cart_planning/scripts/gps_util.py b/cart_planning/scripts/gps_util.py deleted file mode 100755 index 8679d282..00000000 --- a/cart_planning/scripts/gps_util.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python - -import sys -import tf -import rospy -import numpy as np -import affine -import math -import transformations - -#This class still needs testing - -from geometry_msgs.msg import Pose, Point #point is able to be used for path planning in a 3d space -from sensor_msgs.msg import NavSatFix #standard ros message for GPS data - -#current anchor is the center of the xlabs building, with direction pointing directly north -anchor_lat = 38.432150 # 38.431691 # 38.432147 # 38.431960 -anchor_long = -78.876106 # -78.876036 #-78.876115 # -78.875910 -anchor_elev = 396 #meters above sea level -anchor_theta = 40 #angle pointing directly north, originally: 0 -earth_radius = 6371000 #meters - -""" -#This array is used to transform points from the frame based on this anchor point to the map frame used by sensors -#This array was created using 7 points, their x,y positions in each frame, and their gps coordinates. -#The affine matrices method from this code was used: https://www.lfd.uci.edu/~gohlke/code/transformations.py.html -""" - - -'''M = np.array([[-0.45644886, -0.77822273, -2.79976147], - [ 0.84299717, -0.50090785, 41.31691467], - [ 0.0, 0.0, 1.0]])''' - - -v0 = None -v1 = None -M = None - - -""" -Always go from GPS to XYZ as soon as you can. Then never go back. Ever. Dont even think about it -. -If you get a batch of waypoints in lat/long, immediately convert all of them. Then do whatever other math you wanted to do. -Through a combination of an anchor point, distance_between_points, and direction between points, we can convert any lat/long point to an xyz point in our coordinate frame - -TODO: move all the geometry methods to another utility file -""" - -def get_point(current_gps): - """ - Returns a Point() (xyz) of a lat/long relative to the set anchor point - - This relies on the xy_between_coordinates method - - Zack - """ - relative_point = Point() - current_lat = current_gps.latitude - current_long = current_gps.longitude - - #The point is found in xyz in reference to the anchor being 0,0,0 - result = xy_between_coordinates(anchor_lat, anchor_long, anchor_theta, current_lat, current_long) - - planning_point = np.array([[result[0]], [result[1]], [1]]) #3rd value is to make point homogenous - sensors_map_point = np.dot(M, planning_point) #dot product to get transformed point - relative_point.x = sensors_map_point[0,0] - relative_point.y = sensors_map_point[1,0] - rospy.loginfo(relative_point) - return relative_point - -def xy_between_coordinates(lat1, lng1, theta1, lat2, lng2): - """ - Returns a tuple of x and y distances between two coordinates - - this relies on distance & direction between coordinates methods - - Zack - """ - distance_flat = distance_between_coordinates(lat1,lng1,lat2,lng2) - angle = math.radians( (theta1+direction_between_coordinates(lat1,lng1,lat2,lng2)) % 360 ) - x = math.sin(angle)*distance_flat - y = math.cos(angle)*distance_flat - return (x, y) - -def distance_between_coordinates(lat1, lng1, lat2, lng2): - """ - :return: distance (meters) between two points. This is approximate as the math assumes the earth is a sphere - - https://www.movable-type.co.uk/scripts/latlong.html - uses meters for earth radius - - Zack - """ - global earth_radius - lat1 = math.radians(lat1) - lng1 = math.radians(lng1) - lat2 = math.radians(lat2) - lng2 = math.radians(lng2) - - a = math.sin((lat2-lat1)/2)*math.sin((lat2-lat1)/2) + math.cos(lat1) * math.cos(lat2) * math.sin((lng2-lng1)/2)*math.sin((lng2-lng1)/2) - c = 2 * math.atan2(math.sqrt(a), math.sqrt((1-a))) - distance = earth_radius * c - return distance -def direction_between_coordinates(lat1, lng1, lat2, lng2): - """ - :return: bearing between two points (degrees) - This calculates for the bearing between two points. - - Zack - """ - lat1 = math.radians(lat1) - lng1 = math.radians(lng1) - lat2 = math.radians(lat2) - lng2 = math.radians(lng2) - - bearing = math.atan2((math.sin(lng2-lng1)*math.cos(lat2)),(math.cos(lat1)*math.sin(lat2)-math.sin(lat1)*math.cos(lat2)*math.cos(lng2-lng1))) - bearing = (math.degrees(bearing)+360)%360 - return bearing - - -""" -TODO -Every method below here is a geometry util that should go in a separate file. -These are used for Pure Pursuit""" - -def xy_angle_between_points(point1, point2): - distx = point2.x - point1.x - disty = point2.y - point1.y - #y is forward while x is sideways - return (math.atan2(distx, disty)*180/math.pi)%360 - -def xyz_dist_between_points(point1, point2): - """ - distance between two xyz points in a 3-dimensional coordinate plane - """ - distx = point1.x - point2.x - disty = point1.y - point2.y - distz = point1.z - point2.z - return math.sqrt(disty ** 2 + distx ** 2 + distz ** 2) - -def midpoint(p1, p2): - """ - used to find a geometric midpoint in an x/y coordinate frame - """ - x = (p1.x + p2.x) / 2.0 - y = (p1.y + p2.y) / 2.0 - - return Point(x, y, 0) - -def add_intermediate_points(points, threshold): - """ - Method for adding more points to a list of geometric points within a threshold. - """ - #threshold = 5.0 - - #keeps the final point to add at the end - final = points[0] - - newPoints = [] - prev = points.pop() - - #loop until points is empty - #we are using points as a stack here - while points: - #get the next point on the stack - new = points.pop() - dist = xyz_dist_between_points(prev, new) - - #if the distance is greater than the threshold - if dist > threshold: - #put the point on the stack - points.append(new) - mid = midpoint(new, prev) - #add the midpoint to the stack - points.append(mid) - else: - #add the start point to the newPoints and switch new point to the prev point - newPoints.append(prev) - prev = new - - #add the final point - newPoints.append(final) - newPoints.reverse() - return newPoints - -#X -v0 = [[35.9750671387, -14.0169754028, --3.60410761833, -17.4223442078, -30.7783546448, -59.0794563293, -47.9315681458], -#Y -[36.4229431152, -1.30921435356, -8.7294960022, -46.9932327271, -43.7685050964, -72.0065460205, -86.720085144]] - - - - - -#Latitude -v1 = [[38.431686, -38.432053, -38.432108, -38.431724, -38.431672, -38.431312, -38.431282], -#Longitude -[-78.876137, --78.876221, --78.876016, --78.875895, --78.876047, --78.876070, --78.875866]] - - -v1_np = np.array(v1) -new_arr = [[],[]] -''' -# Setup for averaging -anchor_lat = 0 -anchor_long = 0 - -for i in range(v1_np.shape[1]): - - lat = v1_np[0][i] - anchor_lat += lat - - lng = v1_np[1][i] - anchor_long += lng - -# Average for anchor point -anchor_lat = anchor_lat / 7 -anchor_long = anchor_long / 7''' - -# End averaging, begin converting - -for i in range(v1_np.shape[1]): - - lat = v1_np[0][i] - - lng = v1_np[1][i] - - elem = xy_between_coordinates(anchor_lat, anchor_long, anchor_theta, lat, lng) - new_arr[0].append(elem[0]) - new_arr[1].append(elem[1]) - - - -M = transformations.affine_matrix_from_points(v0, new_arr) -#M = transformations.affine_matrix_from_points(v0, v1_np) diff --git a/cart_planning/scripts/transformations.py b/cart_planning/scripts/transformations.py deleted file mode 100755 index 7c0bcd79..00000000 --- a/cart_planning/scripts/transformations.py +++ /dev/null @@ -1,1954 +0,0 @@ - - -# -*- coding: utf-8 -*- -# transformations.py - -# Copyright (c) 2006-2019, Christoph Gohlke -# Copyright (c) 2006-2019, The Regents of the University of California -# Produced at the Laboratory for Fluorescence Dynamics -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, -# this list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# * Neither the name of the copyright holder nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -"""Homogeneous Transformation Matrices and Quaternions. - -Transformations is a Python library for calculating 4x4 matrices for -translating, rotating, reflecting, scaling, shearing, projecting, -orthogonalizing, and superimposing arrays of 3D homogeneous coordinates -as well as for converting between rotation matrices, Euler angles, -and quaternions. Also includes an Arcball control object and -functions to decompose transformation matrices. - -:Author: - `Christoph Gohlke `_ - -:Organization: - Laboratory for Fluorescence Dynamics. University of California, Irvine - -:License: 3-clause BSD - -:Version: 2019.2.20 - -Requirements ------------- -* `CPython 2.7 or 3.5+ `_ -* `Numpy 1.14 `_ -* A Python distutils compatible C compiler (build) - -Revisions ---------- -2019.1.1 - Update copyright year. - -Notes ------ -Transformations.py is no longer actively developed and has a few known issues -and numerical instabilities. The module is mostly superseded by other modules -for 3D transformations and quaternions: - -* `Scipy.spatial.transform `_ -* `Transforms3d `_ - (includes most code of this module) -* `Numpy-quaternion `_ -* `Blender.mathutils `_ - -The API is not stable yet and is expected to change between revisions. - -Python 2.7 and 3.4 are deprecated. - -This Python code is not optimized for speed. Refer to the transformations.c -module for a faster implementation of some functions. - -Documentation in HTML format can be generated with epydoc. - -Matrices (M) can be inverted using numpy.linalg.inv(M), be concatenated using -numpy.dot(M0, M1), or transform homogeneous coordinate arrays (v) using -numpy.dot(M, v) for shape (4, \*) column vectors, respectively -numpy.dot(v, M.T) for shape (\*, 4) row vectors ("array of points"). - -This module follows the "column vectors on the right" and "row major storage" -(C contiguous) conventions. The translation components are in the right column -of the transformation matrix, i.e. M[:3, 3]. -The transpose of the transformation matrices may have to be used to interface -with other graphics systems, e.g. OpenGL's glMultMatrixd(). See also [16]. - -Calculations are carried out with numpy.float64 precision. - -Vector, point, quaternion, and matrix function arguments are expected to be -"array like", i.e. tuple, list, or numpy arrays. - -Return types are numpy arrays unless specified otherwise. - -Angles are in radians unless specified otherwise. - -Quaternions w+ix+jy+kz are represented as [w, x, y, z]. - -A triple of Euler angles can be applied/interpreted in 24 ways, which can -be specified using a 4 character string or encoded 4-tuple: - - *Axes 4-string*: e.g. 'sxyz' or 'ryxy' - - - first character : rotations are applied to 's'tatic or 'r'otating frame - - remaining characters : successive rotation axis 'x', 'y', or 'z' - - *Axes 4-tuple*: e.g. (0, 0, 0, 0) or (1, 1, 1, 1) - - - inner axis: code of axis ('x':0, 'y':1, 'z':2) of rightmost matrix. - - parity : even (0) if inner axis 'x' is followed by 'y', 'y' is followed - by 'z', or 'z' is followed by 'x'. Otherwise odd (1). - - repetition : first and last axis are same (1) or different (0). - - frame : rotations are applied to static (0) or rotating (1) frame. - -References ----------- -(1) Matrices and transformations. Ronald Goldman. - In "Graphics Gems I", pp 472-475. Morgan Kaufmann, 1990. -(2) More matrices and transformations: shear and pseudo-perspective. - Ronald Goldman. In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991. -(3) Decomposing a matrix into simple transformations. Spencer Thomas. - In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991. -(4) Recovering the data from the transformation matrix. Ronald Goldman. - In "Graphics Gems II", pp 324-331. Morgan Kaufmann, 1991. -(5) Euler angle conversion. Ken Shoemake. - In "Graphics Gems IV", pp 222-229. Morgan Kaufmann, 1994. -(6) Arcball rotation control. Ken Shoemake. - In "Graphics Gems IV", pp 175-192. Morgan Kaufmann, 1994. -(7) Representing attitude: Euler angles, unit quaternions, and rotation - vectors. James Diebel. 2006. -(8) A discussion of the solution for the best rotation to relate two sets - of vectors. W Kabsch. Acta Cryst. 1978. A34, 827-828. -(9) Closed-form solution of absolute orientation using unit quaternions. - BKP Horn. J Opt Soc Am A. 1987. 4(4):629-642. -(10) Quaternions. Ken Shoemake. - http://www.sfu.ca/~jwa3/cmpt461/files/quatut.pdf -(11) From quaternion to matrix and back. JMP van Waveren. 2005. - http://www.intel.com/cd/ids/developer/asmo-na/eng/293748.htm -(12) Uniform random rotations. Ken Shoemake. - In "Graphics Gems III", pp 124-132. Morgan Kaufmann, 1992. -(13) Quaternion in molecular modeling. CFF Karney. - J Mol Graph Mod, 25(5):595-604 -(14) New method for extracting the quaternion from a rotation matrix. - Itzhack Y Bar-Itzhack, J Guid Contr Dynam. 2000. 23(6): 1085-1087. -(15) Multiple View Geometry in Computer Vision. Hartley and Zissermann. - Cambridge University Press; 2nd Ed. 2004. Chapter 4, Algorithm 4.7, p 130. -(16) Column Vectors vs. Row Vectors. - http://steve.hollasch.net/cgindex/math/matrix/column-vec.html - -Examples --------- ->>> alpha, beta, gamma = 0.123, -1.234, 2.345 ->>> origin, xaxis, yaxis, zaxis = [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1] ->>> I = identity_matrix() ->>> Rx = rotation_matrix(alpha, xaxis) ->>> Ry = rotation_matrix(beta, yaxis) ->>> Rz = rotation_matrix(gamma, zaxis) ->>> R = concatenate_matrices(Rx, Ry, Rz) ->>> euler = euler_from_matrix(R, 'rxyz') ->>> numpy.allclose([alpha, beta, gamma], euler) -True ->>> Re = euler_matrix(alpha, beta, gamma, 'rxyz') ->>> is_same_transform(R, Re) -True ->>> al, be, ga = euler_from_matrix(Re, 'rxyz') ->>> is_same_transform(Re, euler_matrix(al, be, ga, 'rxyz')) -True ->>> qx = quaternion_about_axis(alpha, xaxis) ->>> qy = quaternion_about_axis(beta, yaxis) ->>> qz = quaternion_about_axis(gamma, zaxis) ->>> q = quaternion_multiply(qx, qy) ->>> q = quaternion_multiply(q, qz) ->>> Rq = quaternion_matrix(q) ->>> is_same_transform(R, Rq) -True ->>> S = scale_matrix(1.23, origin) ->>> T = translation_matrix([1, 2, 3]) ->>> Z = shear_matrix(beta, xaxis, origin, zaxis) ->>> R = random_rotation_matrix(numpy.random.rand(3)) ->>> M = concatenate_matrices(T, R, Z, S) ->>> scale, shear, angles, trans, persp = decompose_matrix(M) ->>> numpy.allclose(scale, 1.23) -True ->>> numpy.allclose(trans, [1, 2, 3]) -True ->>> numpy.allclose(shear, [0, math.tan(beta), 0]) -True ->>> is_same_transform(R, euler_matrix(axes='sxyz', *angles)) -True ->>> M1 = compose_matrix(scale, shear, angles, trans, persp) ->>> is_same_transform(M, M1) -True ->>> v0, v1 = random_vector(3), random_vector(3) ->>> M = rotation_matrix(angle_between_vectors(v0, v1), vector_product(v0, v1)) ->>> v2 = numpy.dot(v0, M[:3,:3].T) ->>> numpy.allclose(unit_vector(v1), unit_vector(v2)) -True - -""" - -from __future__ import division, print_function - -__version__ = '2019.2.20' -__docformat__ = 'restructuredtext en' - -import math - -import numpy - - -def identity_matrix(): - """Return 4x4 identity/unit matrix. - - >>> I = identity_matrix() - >>> numpy.allclose(I, numpy.dot(I, I)) - True - >>> numpy.sum(I), numpy.trace(I) - (4.0, 4.0) - >>> numpy.allclose(I, numpy.identity(4)) - True - - """ - return numpy.identity(4) - - -def translation_matrix(direction): - """Return matrix to translate by direction vector. - - >>> v = numpy.random.random(3) - 0.5 - >>> numpy.allclose(v, translation_matrix(v)[:3, 3]) - True - - """ - M = numpy.identity(4) - M[:3, 3] = direction[:3] - return M - - -def translation_from_matrix(matrix): - """Return translation vector from translation matrix. - - >>> v0 = numpy.random.random(3) - 0.5 - >>> v1 = translation_from_matrix(translation_matrix(v0)) - >>> numpy.allclose(v0, v1) - True - - """ - return numpy.array(matrix, copy=False)[:3, 3].copy() - - -def reflection_matrix(point, normal): - """Return matrix to mirror at plane defined by point and normal vector. - - >>> v0 = numpy.random.random(4) - 0.5 - >>> v0[3] = 1. - >>> v1 = numpy.random.random(3) - 0.5 - >>> R = reflection_matrix(v0, v1) - >>> numpy.allclose(2, numpy.trace(R)) - True - >>> numpy.allclose(v0, numpy.dot(R, v0)) - True - >>> v2 = v0.copy() - >>> v2[:3] += v1 - >>> v3 = v0.copy() - >>> v2[:3] -= v1 - >>> numpy.allclose(v2, numpy.dot(R, v3)) - True - - """ - normal = unit_vector(normal[:3]) - M = numpy.identity(4) - M[:3, :3] -= 2.0 * numpy.outer(normal, normal) - M[:3, 3] = (2.0 * numpy.dot(point[:3], normal)) * normal - return M - - -def reflection_from_matrix(matrix): - """Return mirror plane point and normal vector from reflection matrix. - - >>> v0 = numpy.random.random(3) - 0.5 - >>> v1 = numpy.random.random(3) - 0.5 - >>> M0 = reflection_matrix(v0, v1) - >>> point, normal = reflection_from_matrix(M0) - >>> M1 = reflection_matrix(point, normal) - >>> is_same_transform(M0, M1) - True - - """ - M = numpy.array(matrix, dtype=numpy.float64, copy=False) - # normal: unit eigenvector corresponding to eigenvalue -1 - w, V = numpy.linalg.eig(M[:3, :3]) - i = numpy.where(abs(numpy.real(w) + 1.0) < 1e-8)[0] - if not len(i): - raise ValueError('no unit eigenvector corresponding to eigenvalue -1') - normal = numpy.real(V[:, i[0]]).squeeze() - # point: any unit eigenvector corresponding to eigenvalue 1 - w, V = numpy.linalg.eig(M) - i = numpy.where(abs(numpy.real(w) - 1.0) < 1e-8)[0] - if not len(i): - raise ValueError('no unit eigenvector corresponding to eigenvalue 1') - point = numpy.real(V[:, i[-1]]).squeeze() - point /= point[3] - return point, normal - - -def rotation_matrix(angle, direction, point=None): - """Return matrix to rotate about axis defined by point and direction. - - >>> R = rotation_matrix(math.pi/2, [0, 0, 1], [1, 0, 0]) - >>> numpy.allclose(numpy.dot(R, [0, 0, 0, 1]), [1, -1, 0, 1]) - True - >>> angle = (random.random() - 0.5) * (2*math.pi) - >>> direc = numpy.random.random(3) - 0.5 - >>> point = numpy.random.random(3) - 0.5 - >>> R0 = rotation_matrix(angle, direc, point) - >>> R1 = rotation_matrix(angle-2*math.pi, direc, point) - >>> is_same_transform(R0, R1) - True - >>> R0 = rotation_matrix(angle, direc, point) - >>> R1 = rotation_matrix(-angle, -direc, point) - >>> is_same_transform(R0, R1) - True - >>> I = numpy.identity(4, numpy.float64) - >>> numpy.allclose(I, rotation_matrix(math.pi*2, direc)) - True - >>> numpy.allclose(2, numpy.trace(rotation_matrix(math.pi/2, - ... direc, point))) - True - - """ - sina = math.sin(angle) - cosa = math.cos(angle) - direction = unit_vector(direction[:3]) - # rotation matrix around unit vector - R = numpy.diag([cosa, cosa, cosa]) - R += numpy.outer(direction, direction) * (1.0 - cosa) - direction *= sina - R += numpy.array([[ 0.0, -direction[2], direction[1]], - [ direction[2], 0.0, -direction[0]], - [-direction[1], direction[0], 0.0]]) - M = numpy.identity(4) - M[:3, :3] = R - if point is not None: - # rotation not around origin - point = numpy.array(point[:3], dtype=numpy.float64, copy=False) - M[:3, 3] = point - numpy.dot(R, point) - return M - - -def rotation_from_matrix(matrix): - """Return rotation angle and axis from rotation matrix. - - >>> angle = (random.random() - 0.5) * (2*math.pi) - >>> direc = numpy.random.random(3) - 0.5 - >>> point = numpy.random.random(3) - 0.5 - >>> R0 = rotation_matrix(angle, direc, point) - >>> angle, direc, point = rotation_from_matrix(R0) - >>> R1 = rotation_matrix(angle, direc, point) - >>> is_same_transform(R0, R1) - True - - """ - R = numpy.array(matrix, dtype=numpy.float64, copy=False) - R33 = R[:3, :3] - # direction: unit eigenvector of R33 corresponding to eigenvalue of 1 - w, W = numpy.linalg.eig(R33.T) - i = numpy.where(abs(numpy.real(w) - 1.0) < 1e-8)[0] - if not len(i): - raise ValueError('no unit eigenvector corresponding to eigenvalue 1') - direction = numpy.real(W[:, i[-1]]).squeeze() - # point: unit eigenvector of R33 corresponding to eigenvalue of 1 - w, Q = numpy.linalg.eig(R) - i = numpy.where(abs(numpy.real(w) - 1.0) < 1e-8)[0] - if not len(i): - raise ValueError('no unit eigenvector corresponding to eigenvalue 1') - point = numpy.real(Q[:, i[-1]]).squeeze() - point /= point[3] - # rotation angle depending on direction - cosa = (numpy.trace(R33) - 1.0) / 2.0 - if abs(direction[2]) > 1e-8: - sina = (R[1, 0] + (cosa-1.0)*direction[0]*direction[1]) / direction[2] - elif abs(direction[1]) > 1e-8: - sina = (R[0, 2] + (cosa-1.0)*direction[0]*direction[2]) / direction[1] - else: - sina = (R[2, 1] + (cosa-1.0)*direction[1]*direction[2]) / direction[0] - angle = math.atan2(sina, cosa) - return angle, direction, point - - -def scale_matrix(factor, origin=None, direction=None): - """Return matrix to scale by factor around origin in direction. - - Use factor -1 for point symmetry. - - >>> v = (numpy.random.rand(4, 5) - 0.5) * 20 - >>> v[3] = 1 - >>> S = scale_matrix(-1.234) - >>> numpy.allclose(numpy.dot(S, v)[:3], -1.234*v[:3]) - True - >>> factor = random.random() * 10 - 5 - >>> origin = numpy.random.random(3) - 0.5 - >>> direct = numpy.random.random(3) - 0.5 - >>> S = scale_matrix(factor, origin) - >>> S = scale_matrix(factor, origin, direct) - - """ - if direction is None: - # uniform scaling - M = numpy.diag([factor, factor, factor, 1.0]) - if origin is not None: - M[:3, 3] = origin[:3] - M[:3, 3] *= 1.0 - factor - else: - # nonuniform scaling - direction = unit_vector(direction[:3]) - factor = 1.0 - factor - M = numpy.identity(4) - M[:3, :3] -= factor * numpy.outer(direction, direction) - if origin is not None: - M[:3, 3] = (factor * numpy.dot(origin[:3], direction)) * direction - return M - - -def scale_from_matrix(matrix): - """Return scaling factor, origin and direction from scaling matrix. - - >>> factor = random.random() * 10 - 5 - >>> origin = numpy.random.random(3) - 0.5 - >>> direct = numpy.random.random(3) - 0.5 - >>> S0 = scale_matrix(factor, origin) - >>> factor, origin, direction = scale_from_matrix(S0) - >>> S1 = scale_matrix(factor, origin, direction) - >>> is_same_transform(S0, S1) - True - >>> S0 = scale_matrix(factor, origin, direct) - >>> factor, origin, direction = scale_from_matrix(S0) - >>> S1 = scale_matrix(factor, origin, direction) - >>> is_same_transform(S0, S1) - True - - """ - M = numpy.array(matrix, dtype=numpy.float64, copy=False) - M33 = M[:3, :3] - factor = numpy.trace(M33) - 2.0 - try: - # direction: unit eigenvector corresponding to eigenvalue factor - w, V = numpy.linalg.eig(M33) - i = numpy.where(abs(numpy.real(w) - factor) < 1e-8)[0][0] - direction = numpy.real(V[:, i]).squeeze() - direction /= vector_norm(direction) - except IndexError: - # uniform scaling - factor = (factor + 2.0) / 3.0 - direction = None - # origin: any eigenvector corresponding to eigenvalue 1 - w, V = numpy.linalg.eig(M) - i = numpy.where(abs(numpy.real(w) - 1.0) < 1e-8)[0] - if not len(i): - raise ValueError('no eigenvector corresponding to eigenvalue 1') - origin = numpy.real(V[:, i[-1]]).squeeze() - origin /= origin[3] - return factor, origin, direction - - -def projection_matrix(point, normal, direction=None, - perspective=None, pseudo=False): - """Return matrix to project onto plane defined by point and normal. - - Using either perspective point, projection direction, or none of both. - - If pseudo is True, perspective projections will preserve relative depth - such that Perspective = dot(Orthogonal, PseudoPerspective). - - >>> P = projection_matrix([0, 0, 0], [1, 0, 0]) - >>> numpy.allclose(P[1:, 1:], numpy.identity(4)[1:, 1:]) - True - >>> point = numpy.random.random(3) - 0.5 - >>> normal = numpy.random.random(3) - 0.5 - >>> direct = numpy.random.random(3) - 0.5 - >>> persp = numpy.random.random(3) - 0.5 - >>> P0 = projection_matrix(point, normal) - >>> P1 = projection_matrix(point, normal, direction=direct) - >>> P2 = projection_matrix(point, normal, perspective=persp) - >>> P3 = projection_matrix(point, normal, perspective=persp, pseudo=True) - >>> is_same_transform(P2, numpy.dot(P0, P3)) - True - >>> P = projection_matrix([3, 0, 0], [1, 1, 0], [1, 0, 0]) - >>> v0 = (numpy.random.rand(4, 5) - 0.5) * 20 - >>> v0[3] = 1 - >>> v1 = numpy.dot(P, v0) - >>> numpy.allclose(v1[1], v0[1]) - True - >>> numpy.allclose(v1[0], 3-v1[1]) - True - - """ - M = numpy.identity(4) - point = numpy.array(point[:3], dtype=numpy.float64, copy=False) - normal = unit_vector(normal[:3]) - if perspective is not None: - # perspective projection - perspective = numpy.array(perspective[:3], dtype=numpy.float64, - copy=False) - M[0, 0] = M[1, 1] = M[2, 2] = numpy.dot(perspective-point, normal) - M[:3, :3] -= numpy.outer(perspective, normal) - if pseudo: - # preserve relative depth - M[:3, :3] -= numpy.outer(normal, normal) - M[:3, 3] = numpy.dot(point, normal) * (perspective+normal) - else: - M[:3, 3] = numpy.dot(point, normal) * perspective - M[3, :3] = -normal - M[3, 3] = numpy.dot(perspective, normal) - elif direction is not None: - # parallel projection - direction = numpy.array(direction[:3], dtype=numpy.float64, copy=False) - scale = numpy.dot(direction, normal) - M[:3, :3] -= numpy.outer(direction, normal) / scale - M[:3, 3] = direction * (numpy.dot(point, normal) / scale) - else: - # orthogonal projection - M[:3, :3] -= numpy.outer(normal, normal) - M[:3, 3] = numpy.dot(point, normal) * normal - return M - - -def projection_from_matrix(matrix, pseudo=False): - """Return projection plane and perspective point from projection matrix. - - Return values are same as arguments for projection_matrix function: - point, normal, direction, perspective, and pseudo. - - >>> point = numpy.random.random(3) - 0.5 - >>> normal = numpy.random.random(3) - 0.5 - >>> direct = numpy.random.random(3) - 0.5 - >>> persp = numpy.random.random(3) - 0.5 - >>> P0 = projection_matrix(point, normal) - >>> result = projection_from_matrix(P0) - >>> P1 = projection_matrix(*result) - >>> is_same_transform(P0, P1) - True - >>> P0 = projection_matrix(point, normal, direct) - >>> result = projection_from_matrix(P0) - >>> P1 = projection_matrix(*result) - >>> is_same_transform(P0, P1) - True - >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=False) - >>> result = projection_from_matrix(P0, pseudo=False) - >>> P1 = projection_matrix(*result) - >>> is_same_transform(P0, P1) - True - >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=True) - >>> result = projection_from_matrix(P0, pseudo=True) - >>> P1 = projection_matrix(*result) - >>> is_same_transform(P0, P1) - True - - """ - M = numpy.array(matrix, dtype=numpy.float64, copy=False) - M33 = M[:3, :3] - w, V = numpy.linalg.eig(M) - i = numpy.where(abs(numpy.real(w) - 1.0) < 1e-8)[0] - if not pseudo and len(i): - # point: any eigenvector corresponding to eigenvalue 1 - point = numpy.real(V[:, i[-1]]).squeeze() - point /= point[3] - # direction: unit eigenvector corresponding to eigenvalue 0 - w, V = numpy.linalg.eig(M33) - i = numpy.where(abs(numpy.real(w)) < 1e-8)[0] - if not len(i): - raise ValueError('no eigenvector corresponding to eigenvalue 0') - direction = numpy.real(V[:, i[0]]).squeeze() - direction /= vector_norm(direction) - # normal: unit eigenvector of M33.T corresponding to eigenvalue 0 - w, V = numpy.linalg.eig(M33.T) - i = numpy.where(abs(numpy.real(w)) < 1e-8)[0] - if len(i): - # parallel projection - normal = numpy.real(V[:, i[0]]).squeeze() - normal /= vector_norm(normal) - return point, normal, direction, None, False - else: - # orthogonal projection, where normal equals direction vector - return point, direction, None, None, False - else: - # perspective projection - i = numpy.where(abs(numpy.real(w)) > 1e-8)[0] - if not len(i): - raise ValueError( - 'no eigenvector not corresponding to eigenvalue 0') - point = numpy.real(V[:, i[-1]]).squeeze() - point /= point[3] - normal = - M[3, :3] - perspective = M[:3, 3] / numpy.dot(point[:3], normal) - if pseudo: - perspective -= normal - return point, normal, None, perspective, pseudo - - -def clip_matrix(left, right, bottom, top, near, far, perspective=False): - """Return matrix to obtain normalized device coordinates from frustum. - - The frustum bounds are axis-aligned along x (left, right), - y (bottom, top) and z (near, far). - - Normalized device coordinates are in range [-1, 1] if coordinates are - inside the frustum. - - If perspective is True the frustum is a truncated pyramid with the - perspective point at origin and direction along z axis, otherwise an - orthographic canonical view volume (a box). - - Homogeneous coordinates transformed by the perspective clip matrix - need to be dehomogenized (divided by w coordinate). - - >>> frustum = numpy.random.rand(6) - >>> frustum[1] += frustum[0] - >>> frustum[3] += frustum[2] - >>> frustum[5] += frustum[4] - >>> M = clip_matrix(perspective=False, *frustum) - >>> numpy.dot(M, [frustum[0], frustum[2], frustum[4], 1]) - array([-1., -1., -1., 1.]) - >>> numpy.dot(M, [frustum[1], frustum[3], frustum[5], 1]) - array([ 1., 1., 1., 1.]) - >>> M = clip_matrix(perspective=True, *frustum) - >>> v = numpy.dot(M, [frustum[0], frustum[2], frustum[4], 1]) - >>> v / v[3] - array([-1., -1., -1., 1.]) - >>> v = numpy.dot(M, [frustum[1], frustum[3], frustum[4], 1]) - >>> v / v[3] - array([ 1., 1., -1., 1.]) - - """ - if left >= right or bottom >= top or near >= far: - raise ValueError('invalid frustum') - if perspective: - if near <= _EPS: - raise ValueError('invalid frustum: near <= 0') - t = 2.0 * near - M = [[t/(left-right), 0.0, (right+left)/(right-left), 0.0], - [0.0, t/(bottom-top), (top+bottom)/(top-bottom), 0.0], - [0.0, 0.0, (far+near)/(near-far), t*far/(far-near)], - [0.0, 0.0, -1.0, 0.0]] - else: - M = [[2.0/(right-left), 0.0, 0.0, (right+left)/(left-right)], - [0.0, 2.0/(top-bottom), 0.0, (top+bottom)/(bottom-top)], - [0.0, 0.0, 2.0/(far-near), (far+near)/(near-far)], - [0.0, 0.0, 0.0, 1.0]] - return numpy.array(M) - - -def shear_matrix(angle, direction, point, normal): - """Return matrix to shear by angle along direction vector on shear plane. - - The shear plane is defined by a point and normal vector. The direction - vector must be orthogonal to the plane's normal vector. - - A point P is transformed by the shear matrix into P" such that - the vector P-P" is parallel to the direction vector and its extent is - given by the angle of P-P'-P", where P' is the orthogonal projection - of P onto the shear plane. - - >>> angle = (random.random() - 0.5) * 4*math.pi - >>> direct = numpy.random.random(3) - 0.5 - >>> point = numpy.random.random(3) - 0.5 - >>> normal = numpy.cross(direct, numpy.random.random(3)) - >>> S = shear_matrix(angle, direct, point, normal) - >>> numpy.allclose(1, numpy.linalg.det(S)) - True - - """ - normal = unit_vector(normal[:3]) - direction = unit_vector(direction[:3]) - if abs(numpy.dot(normal, direction)) > 1e-6: - raise ValueError('direction and normal vectors are not orthogonal') - angle = math.tan(angle) - M = numpy.identity(4) - M[:3, :3] += angle * numpy.outer(direction, normal) - M[:3, 3] = -angle * numpy.dot(point[:3], normal) * direction - return M - - -def shear_from_matrix(matrix): - """Return shear angle, direction and plane from shear matrix. - - >>> angle = (random.random() - 0.5) * 4*math.pi - >>> direct = numpy.random.random(3) - 0.5 - >>> point = numpy.random.random(3) - 0.5 - >>> normal = numpy.cross(direct, numpy.random.random(3)) - >>> S0 = shear_matrix(angle, direct, point, normal) - >>> angle, direct, point, normal = shear_from_matrix(S0) - >>> S1 = shear_matrix(angle, direct, point, normal) - >>> is_same_transform(S0, S1) - True - - """ - M = numpy.array(matrix, dtype=numpy.float64, copy=False) - M33 = M[:3, :3] - # normal: cross independent eigenvectors corresponding to the eigenvalue 1 - w, V = numpy.linalg.eig(M33) - i = numpy.where(abs(numpy.real(w) - 1.0) < 1e-4)[0] - if len(i) < 2: - raise ValueError('no two linear independent eigenvectors found %s' % w) - V = numpy.real(V[:, i]).squeeze().T - lenorm = -1.0 - for i0, i1 in ((0, 1), (0, 2), (1, 2)): - n = numpy.cross(V[i0], V[i1]) - w = vector_norm(n) - if w > lenorm: - lenorm = w - normal = n - normal /= lenorm - # direction and angle - direction = numpy.dot(M33 - numpy.identity(3), normal) - angle = vector_norm(direction) - direction /= angle - angle = math.atan(angle) - # point: eigenvector corresponding to eigenvalue 1 - w, V = numpy.linalg.eig(M) - i = numpy.where(abs(numpy.real(w) - 1.0) < 1e-8)[0] - if not len(i): - raise ValueError('no eigenvector corresponding to eigenvalue 1') - point = numpy.real(V[:, i[-1]]).squeeze() - point /= point[3] - return angle, direction, point, normal - - -def decompose_matrix(matrix): - """Return sequence of transformations from transformation matrix. - - matrix : array_like - Non-degenerative homogeneous transformation matrix - - Return tuple of: - scale : vector of 3 scaling factors - shear : list of shear factors for x-y, x-z, y-z axes - angles : list of Euler angles about static x, y, z axes - translate : translation vector along x, y, z axes - perspective : perspective partition of matrix - - Raise ValueError if matrix is of wrong type or degenerative. - - >>> T0 = translation_matrix([1, 2, 3]) - >>> scale, shear, angles, trans, persp = decompose_matrix(T0) - >>> T1 = translation_matrix(trans) - >>> numpy.allclose(T0, T1) - True - >>> S = scale_matrix(0.123) - >>> scale, shear, angles, trans, persp = decompose_matrix(S) - >>> scale[0] - 0.123 - >>> R0 = euler_matrix(1, 2, 3) - >>> scale, shear, angles, trans, persp = decompose_matrix(R0) - >>> R1 = euler_matrix(*angles) - >>> numpy.allclose(R0, R1) - True - - """ - M = numpy.array(matrix, dtype=numpy.float64, copy=True).T - if abs(M[3, 3]) < _EPS: - raise ValueError('M[3, 3] is zero') - M /= M[3, 3] - P = M.copy() - P[:, 3] = 0.0, 0.0, 0.0, 1.0 - if not numpy.linalg.det(P): - raise ValueError('matrix is singular') - - scale = numpy.zeros((3, )) - shear = [0.0, 0.0, 0.0] - angles = [0.0, 0.0, 0.0] - - if any(abs(M[:3, 3]) > _EPS): - perspective = numpy.dot(M[:, 3], numpy.linalg.inv(P.T)) - M[:, 3] = 0.0, 0.0, 0.0, 1.0 - else: - perspective = numpy.array([0.0, 0.0, 0.0, 1.0]) - - translate = M[3, :3].copy() - M[3, :3] = 0.0 - - row = M[:3, :3].copy() - scale[0] = vector_norm(row[0]) - row[0] /= scale[0] - shear[0] = numpy.dot(row[0], row[1]) - row[1] -= row[0] * shear[0] - scale[1] = vector_norm(row[1]) - row[1] /= scale[1] - shear[0] /= scale[1] - shear[1] = numpy.dot(row[0], row[2]) - row[2] -= row[0] * shear[1] - shear[2] = numpy.dot(row[1], row[2]) - row[2] -= row[1] * shear[2] - scale[2] = vector_norm(row[2]) - row[2] /= scale[2] - shear[1:] /= scale[2] - - if numpy.dot(row[0], numpy.cross(row[1], row[2])) < 0: - numpy.negative(scale, scale) - numpy.negative(row, row) - - angles[1] = math.asin(-row[0, 2]) - if math.cos(angles[1]): - angles[0] = math.atan2(row[1, 2], row[2, 2]) - angles[2] = math.atan2(row[0, 1], row[0, 0]) - else: - # angles[0] = math.atan2(row[1, 0], row[1, 1]) - angles[0] = math.atan2(-row[2, 1], row[1, 1]) - angles[2] = 0.0 - - return scale, shear, angles, translate, perspective - - -def compose_matrix(scale=None, shear=None, angles=None, translate=None, - perspective=None): - """Return transformation matrix from sequence of transformations. - - This is the inverse of the decompose_matrix function. - - Sequence of transformations: - scale : vector of 3 scaling factors - shear : list of shear factors for x-y, x-z, y-z axes - angles : list of Euler angles about static x, y, z axes - translate : translation vector along x, y, z axes - perspective : perspective partition of matrix - - >>> scale = numpy.random.random(3) - 0.5 - >>> shear = numpy.random.random(3) - 0.5 - >>> angles = (numpy.random.random(3) - 0.5) * (2*math.pi) - >>> trans = numpy.random.random(3) - 0.5 - >>> persp = numpy.random.random(4) - 0.5 - >>> M0 = compose_matrix(scale, shear, angles, trans, persp) - >>> result = decompose_matrix(M0) - >>> M1 = compose_matrix(*result) - >>> is_same_transform(M0, M1) - True - - """ - M = numpy.identity(4) - if perspective is not None: - P = numpy.identity(4) - P[3, :] = perspective[:4] - M = numpy.dot(M, P) - if translate is not None: - T = numpy.identity(4) - T[:3, 3] = translate[:3] - M = numpy.dot(M, T) - if angles is not None: - R = euler_matrix(angles[0], angles[1], angles[2], 'sxyz') - M = numpy.dot(M, R) - if shear is not None: - Z = numpy.identity(4) - Z[1, 2] = shear[2] - Z[0, 2] = shear[1] - Z[0, 1] = shear[0] - M = numpy.dot(M, Z) - if scale is not None: - S = numpy.identity(4) - S[0, 0] = scale[0] - S[1, 1] = scale[1] - S[2, 2] = scale[2] - M = numpy.dot(M, S) - M /= M[3, 3] - return M - - -def orthogonalization_matrix(lengths, angles): - """Return orthogonalization matrix for crystallographic cell coordinates. - - Angles are expected in degrees. - - The de-orthogonalization matrix is the inverse. - - >>> O = orthogonalization_matrix([10, 10, 10], [90, 90, 90]) - >>> numpy.allclose(O[:3, :3], numpy.identity(3, float) * 10) - True - >>> O = orthogonalization_matrix([9.8, 12.0, 15.5], [87.2, 80.7, 69.7]) - >>> numpy.allclose(numpy.sum(O), 43.063229) - True - - """ - a, b, c = lengths - angles = numpy.radians(angles) - sina, sinb, _ = numpy.sin(angles) - cosa, cosb, cosg = numpy.cos(angles) - co = (cosa * cosb - cosg) / (sina * sinb) - return numpy.array([ - [ a*sinb*math.sqrt(1.0-co*co), 0.0, 0.0, 0.0], - [-a*sinb*co, b*sina, 0.0, 0.0], - [ a*cosb, b*cosa, c, 0.0], - [ 0.0, 0.0, 0.0, 1.0]]) - - -def affine_matrix_from_points(v0, v1, shear=True, scale=True, usesvd=True): - """Return affine transform matrix to register two point sets. - - v0 and v1 are shape (ndims, \*) arrays of at least ndims non-homogeneous - coordinates, where ndims is the dimensionality of the coordinate space. - - If shear is False, a similarity transformation matrix is returned. - If also scale is False, a rigid/Euclidean transformation matrix - is returned. - - By default the algorithm by Hartley and Zissermann [15] is used. - If usesvd is True, similarity and Euclidean transformation matrices - are calculated by minimizing the weighted sum of squared deviations - (RMSD) according to the algorithm by Kabsch [8]. - Otherwise, and if ndims is 3, the quaternion based algorithm by Horn [9] - is used, which is slower when using this Python implementation. - - The returned matrix performs rotation, translation and uniform scaling - (if specified). - - >>> v0 = [[0, 1031, 1031, 0], [0, 0, 1600, 1600]] - >>> v1 = [[675, 826, 826, 677], [55, 52, 281, 277]] - >>> affine_matrix_from_points(v0, v1) - array([[ 0.14549, 0.00062, 675.50008], - [ 0.00048, 0.14094, 53.24971], - [ 0. , 0. , 1. ]]) - >>> T = translation_matrix(numpy.random.random(3)-0.5) - >>> R = random_rotation_matrix(numpy.random.random(3)) - >>> S = scale_matrix(random.random()) - >>> M = concatenate_matrices(T, R, S) - >>> v0 = (numpy.random.rand(4, 100) - 0.5) * 20 - >>> v0[3] = 1 - >>> v1 = numpy.dot(M, v0) - >>> v0[:3] += numpy.random.normal(0, 1e-8, 300).reshape(3, -1) - >>> M = affine_matrix_from_points(v0[:3], v1[:3]) - >>> numpy.allclose(v1, numpy.dot(M, v0)) - True - - More examples in superimposition_matrix() - - """ - v0 = numpy.array(v0, dtype=numpy.float64, copy=True) - v1 = numpy.array(v1, dtype=numpy.float64, copy=True) - - ndims = v0.shape[0] - if ndims < 2 or v0.shape[1] < ndims or v0.shape != v1.shape: - raise ValueError('input arrays are of wrong shape or type') - - # move centroids to origin - t0 = -numpy.mean(v0, axis=1) - M0 = numpy.identity(ndims+1) - M0[:ndims, ndims] = t0 - v0 += t0.reshape(ndims, 1) - t1 = -numpy.mean(v1, axis=1) - M1 = numpy.identity(ndims+1) - M1[:ndims, ndims] = t1 - v1 += t1.reshape(ndims, 1) - - if shear: - # Affine transformation - A = numpy.concatenate((v0, v1), axis=0) - u, s, vh = numpy.linalg.svd(A.T) - vh = vh[:ndims].T - B = vh[:ndims] - C = vh[ndims:2*ndims] - t = numpy.dot(C, numpy.linalg.pinv(B)) - t = numpy.concatenate((t, numpy.zeros((ndims, 1))), axis=1) - M = numpy.vstack((t, ((0.0,)*ndims) + (1.0,))) - elif usesvd or ndims != 3: - # Rigid transformation via SVD of covariance matrix - u, s, vh = numpy.linalg.svd(numpy.dot(v1, v0.T)) - # rotation matrix from SVD orthonormal bases - R = numpy.dot(u, vh) - if numpy.linalg.det(R) < 0.0: - # R does not constitute right handed system - R -= numpy.outer(u[:, ndims-1], vh[ndims-1, :]*2.0) - s[-1] *= -1.0 - # homogeneous transformation matrix - M = numpy.identity(ndims+1) - M[:ndims, :ndims] = R - else: - # Rigid transformation matrix via quaternion - # compute symmetric matrix N - xx, yy, zz = numpy.sum(v0 * v1, axis=1) - xy, yz, zx = numpy.sum(v0 * numpy.roll(v1, -1, axis=0), axis=1) - xz, yx, zy = numpy.sum(v0 * numpy.roll(v1, -2, axis=0), axis=1) - N = [[xx+yy+zz, 0.0, 0.0, 0.0], - [yz-zy, xx-yy-zz, 0.0, 0.0], - [zx-xz, xy+yx, yy-xx-zz, 0.0], - [xy-yx, zx+xz, yz+zy, zz-xx-yy]] - # quaternion: eigenvector corresponding to most positive eigenvalue - w, V = numpy.linalg.eigh(N) - q = V[:, numpy.argmax(w)] - q /= vector_norm(q) # unit quaternion - # homogeneous transformation matrix - M = quaternion_matrix(q) - - if scale and not shear: - # Affine transformation; scale is ratio of RMS deviations from centroid - v0 *= v0 - v1 *= v1 - M[:ndims, :ndims] *= math.sqrt(numpy.sum(v1) / numpy.sum(v0)) - - # move centroids back - M = numpy.dot(numpy.linalg.inv(M1), numpy.dot(M, M0)) - M /= M[ndims, ndims] - return M - - -def superimposition_matrix(v0, v1, scale=False, usesvd=True): - """Return matrix to transform given 3D point set into second point set. - - v0 and v1 are shape (3, \*) or (4, \*) arrays of at least 3 points. - - The parameters scale and usesvd are explained in the more general - affine_matrix_from_points function. - - The returned matrix is a similarity or Euclidean transformation matrix. - This function has a fast C implementation in transformations.c. - - >>> v0 = numpy.random.rand(3, 10) - >>> M = superimposition_matrix(v0, v0) - >>> numpy.allclose(M, numpy.identity(4)) - True - >>> R = random_rotation_matrix(numpy.random.random(3)) - >>> v0 = [[1,0,0], [0,1,0], [0,0,1], [1,1,1]] - >>> v1 = numpy.dot(R, v0) - >>> M = superimposition_matrix(v0, v1) - >>> numpy.allclose(v1, numpy.dot(M, v0)) - True - >>> v0 = (numpy.random.rand(4, 100) - 0.5) * 20 - >>> v0[3] = 1 - >>> v1 = numpy.dot(R, v0) - >>> M = superimposition_matrix(v0, v1) - >>> numpy.allclose(v1, numpy.dot(M, v0)) - True - >>> S = scale_matrix(random.random()) - >>> T = translation_matrix(numpy.random.random(3)-0.5) - >>> M = concatenate_matrices(T, R, S) - >>> v1 = numpy.dot(M, v0) - >>> v0[:3] += numpy.random.normal(0, 1e-9, 300).reshape(3, -1) - >>> M = superimposition_matrix(v0, v1, scale=True) - >>> numpy.allclose(v1, numpy.dot(M, v0)) - True - >>> M = superimposition_matrix(v0, v1, scale=True, usesvd=False) - >>> numpy.allclose(v1, numpy.dot(M, v0)) - True - >>> v = numpy.empty((4, 100, 3)) - >>> v[:, :, 0] = v0 - >>> M = superimposition_matrix(v0, v1, scale=True, usesvd=False) - >>> numpy.allclose(v1, numpy.dot(M, v[:, :, 0])) - True - - """ - v0 = numpy.array(v0, dtype=numpy.float64, copy=False)[:3] - v1 = numpy.array(v1, dtype=numpy.float64, copy=False)[:3] - return affine_matrix_from_points(v0, v1, shear=False, - scale=scale, usesvd=usesvd) - - -def euler_matrix(ai, aj, ak, axes='sxyz'): - """Return homogeneous rotation matrix from Euler angles and axis sequence. - - ai, aj, ak : Euler's roll, pitch and yaw angles - axes : One of 24 axis sequences as string or encoded tuple - - >>> R = euler_matrix(1, 2, 3, 'syxz') - >>> numpy.allclose(numpy.sum(R[0]), -1.34786452) - True - >>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1)) - >>> numpy.allclose(numpy.sum(R[0]), -0.383436184) - True - >>> ai, aj, ak = (4*math.pi) * (numpy.random.random(3) - 0.5) - >>> for axes in _AXES2TUPLE.keys(): - ... R = euler_matrix(ai, aj, ak, axes) - >>> for axes in _TUPLE2AXES.keys(): - ... R = euler_matrix(ai, aj, ak, axes) - - """ - try: - firstaxis, parity, repetition, frame = _AXES2TUPLE[axes] - except (AttributeError, KeyError): - _TUPLE2AXES[axes] # noqa: validation - firstaxis, parity, repetition, frame = axes - - i = firstaxis - j = _NEXT_AXIS[i+parity] - k = _NEXT_AXIS[i-parity+1] - - if frame: - ai, ak = ak, ai - if parity: - ai, aj, ak = -ai, -aj, -ak - - si, sj, sk = math.sin(ai), math.sin(aj), math.sin(ak) - ci, cj, ck = math.cos(ai), math.cos(aj), math.cos(ak) - cc, cs = ci*ck, ci*sk - sc, ss = si*ck, si*sk - - M = numpy.identity(4) - if repetition: - M[i, i] = cj - M[i, j] = sj*si - M[i, k] = sj*ci - M[j, i] = sj*sk - M[j, j] = -cj*ss+cc - M[j, k] = -cj*cs-sc - M[k, i] = -sj*ck - M[k, j] = cj*sc+cs - M[k, k] = cj*cc-ss - else: - M[i, i] = cj*ck - M[i, j] = sj*sc-cs - M[i, k] = sj*cc+ss - M[j, i] = cj*sk - M[j, j] = sj*ss+cc - M[j, k] = sj*cs-sc - M[k, i] = -sj - M[k, j] = cj*si - M[k, k] = cj*ci - return M - - -def euler_from_matrix(matrix, axes='sxyz'): - """Return Euler angles from rotation matrix for specified axis sequence. - - axes : One of 24 axis sequences as string or encoded tuple - - Note that many Euler angle triplets can describe one matrix. - - >>> R0 = euler_matrix(1, 2, 3, 'syxz') - >>> al, be, ga = euler_from_matrix(R0, 'syxz') - >>> R1 = euler_matrix(al, be, ga, 'syxz') - >>> numpy.allclose(R0, R1) - True - >>> angles = (4*math.pi) * (numpy.random.random(3) - 0.5) - >>> for axes in _AXES2TUPLE.keys(): - ... R0 = euler_matrix(axes=axes, *angles) - ... R1 = euler_matrix(axes=axes, *euler_from_matrix(R0, axes)) - ... if not numpy.allclose(R0, R1): print(axes, "failed") - - """ - try: - firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()] - except (AttributeError, KeyError): - _TUPLE2AXES[axes] # noqa: validation - firstaxis, parity, repetition, frame = axes - - i = firstaxis - j = _NEXT_AXIS[i+parity] - k = _NEXT_AXIS[i-parity+1] - - M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:3, :3] - if repetition: - sy = math.sqrt(M[i, j]*M[i, j] + M[i, k]*M[i, k]) - if sy > _EPS: - ax = math.atan2( M[i, j], M[i, k]) - ay = math.atan2( sy, M[i, i]) - az = math.atan2( M[j, i], -M[k, i]) - else: - ax = math.atan2(-M[j, k], M[j, j]) - ay = math.atan2( sy, M[i, i]) - az = 0.0 - else: - cy = math.sqrt(M[i, i]*M[i, i] + M[j, i]*M[j, i]) - if cy > _EPS: - ax = math.atan2( M[k, j], M[k, k]) - ay = math.atan2(-M[k, i], cy) - az = math.atan2( M[j, i], M[i, i]) - else: - ax = math.atan2(-M[j, k], M[j, j]) - ay = math.atan2(-M[k, i], cy) - az = 0.0 - - if parity: - ax, ay, az = -ax, -ay, -az - if frame: - ax, az = az, ax - return ax, ay, az - - -def euler_from_quaternion(quaternion, axes='sxyz'): - """Return Euler angles from quaternion for specified axis sequence. - - >>> angles = euler_from_quaternion([0.99810947, 0.06146124, 0, 0]) - >>> numpy.allclose(angles, [0.123, 0, 0]) - True - - """ - return euler_from_matrix(quaternion_matrix(quaternion), axes) - - -def quaternion_from_euler(ai, aj, ak, axes='sxyz'): - """Return quaternion from Euler angles and axis sequence. - - ai, aj, ak : Euler's roll, pitch and yaw angles - axes : One of 24 axis sequences as string or encoded tuple - - >>> q = quaternion_from_euler(1, 2, 3, 'ryxz') - >>> numpy.allclose(q, [0.435953, 0.310622, -0.718287, 0.444435]) - True - - """ - try: - firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()] - except (AttributeError, KeyError): - _TUPLE2AXES[axes] # noqa: validation - firstaxis, parity, repetition, frame = axes - - i = firstaxis + 1 - j = _NEXT_AXIS[i+parity-1] + 1 - k = _NEXT_AXIS[i-parity] + 1 - - if frame: - ai, ak = ak, ai - if parity: - aj = -aj - - ai /= 2.0 - aj /= 2.0 - ak /= 2.0 - ci = math.cos(ai) - si = math.sin(ai) - cj = math.cos(aj) - sj = math.sin(aj) - ck = math.cos(ak) - sk = math.sin(ak) - cc = ci*ck - cs = ci*sk - sc = si*ck - ss = si*sk - - q = numpy.empty((4, )) - if repetition: - q[0] = cj*(cc - ss) - q[i] = cj*(cs + sc) - q[j] = sj*(cc + ss) - q[k] = sj*(cs - sc) - else: - q[0] = cj*cc + sj*ss - q[i] = cj*sc - sj*cs - q[j] = cj*ss + sj*cc - q[k] = cj*cs - sj*sc - if parity: - q[j] *= -1.0 - - return q - - -def quaternion_about_axis(angle, axis): - """Return quaternion for rotation about axis. - - >>> q = quaternion_about_axis(0.123, [1, 0, 0]) - >>> numpy.allclose(q, [0.99810947, 0.06146124, 0, 0]) - True - - """ - q = numpy.array([0.0, axis[0], axis[1], axis[2]]) - qlen = vector_norm(q) - if qlen > _EPS: - q *= math.sin(angle/2.0) / qlen - q[0] = math.cos(angle/2.0) - return q - - -def quaternion_matrix(quaternion): - """Return homogeneous rotation matrix from quaternion. - - >>> M = quaternion_matrix([0.99810947, 0.06146124, 0, 0]) - >>> numpy.allclose(M, rotation_matrix(0.123, [1, 0, 0])) - True - >>> M = quaternion_matrix([1, 0, 0, 0]) - >>> numpy.allclose(M, numpy.identity(4)) - True - >>> M = quaternion_matrix([0, 1, 0, 0]) - >>> numpy.allclose(M, numpy.diag([1, -1, -1, 1])) - True - - """ - q = numpy.array(quaternion, dtype=numpy.float64, copy=True) - n = numpy.dot(q, q) - if n < _EPS: - return numpy.identity(4) - q *= math.sqrt(2.0 / n) - q = numpy.outer(q, q) - return numpy.array([ - [1.0-q[2, 2]-q[3, 3], q[1, 2]-q[3, 0], q[1, 3]+q[2, 0], 0.0], - [ q[1, 2]+q[3, 0], 1.0-q[1, 1]-q[3, 3], q[2, 3]-q[1, 0], 0.0], - [ q[1, 3]-q[2, 0], q[2, 3]+q[1, 0], 1.0-q[1, 1]-q[2, 2], 0.0], - [ 0.0, 0.0, 0.0, 1.0]]) - - -def quaternion_from_matrix(matrix, isprecise=False): - """Return quaternion from rotation matrix. - - If isprecise is True, the input matrix is assumed to be a precise rotation - matrix and a faster algorithm is used. - - >>> q = quaternion_from_matrix(numpy.identity(4), True) - >>> numpy.allclose(q, [1, 0, 0, 0]) - True - >>> q = quaternion_from_matrix(numpy.diag([1, -1, -1, 1])) - >>> numpy.allclose(q, [0, 1, 0, 0]) or numpy.allclose(q, [0, -1, 0, 0]) - True - >>> R = rotation_matrix(0.123, (1, 2, 3)) - >>> q = quaternion_from_matrix(R, True) - >>> numpy.allclose(q, [0.9981095, 0.0164262, 0.0328524, 0.0492786]) - True - >>> R = [[-0.545, 0.797, 0.260, 0], [0.733, 0.603, -0.313, 0], - ... [-0.407, 0.021, -0.913, 0], [0, 0, 0, 1]] - >>> q = quaternion_from_matrix(R) - >>> numpy.allclose(q, [0.19069, 0.43736, 0.87485, -0.083611]) - True - >>> R = [[0.395, 0.362, 0.843, 0], [-0.626, 0.796, -0.056, 0], - ... [-0.677, -0.498, 0.529, 0], [0, 0, 0, 1]] - >>> q = quaternion_from_matrix(R) - >>> numpy.allclose(q, [0.82336615, -0.13610694, 0.46344705, -0.29792603]) - True - >>> R = random_rotation_matrix() - >>> q = quaternion_from_matrix(R) - >>> is_same_transform(R, quaternion_matrix(q)) - True - >>> is_same_quaternion(quaternion_from_matrix(R, isprecise=False), - ... quaternion_from_matrix(R, isprecise=True)) - True - >>> R = euler_matrix(0.0, 0.0, numpy.pi/2.0) - >>> is_same_quaternion(quaternion_from_matrix(R, isprecise=False), - ... quaternion_from_matrix(R, isprecise=True)) - True - - """ - M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:4, :4] - if isprecise: - q = numpy.empty((4, )) - t = numpy.trace(M) - if t > M[3, 3]: - q[0] = t - q[3] = M[1, 0] - M[0, 1] - q[2] = M[0, 2] - M[2, 0] - q[1] = M[2, 1] - M[1, 2] - else: - i, j, k = 0, 1, 2 - if M[1, 1] > M[0, 0]: - i, j, k = 1, 2, 0 - if M[2, 2] > M[i, i]: - i, j, k = 2, 0, 1 - t = M[i, i] - (M[j, j] + M[k, k]) + M[3, 3] - q[i] = t - q[j] = M[i, j] + M[j, i] - q[k] = M[k, i] + M[i, k] - q[3] = M[k, j] - M[j, k] - q = q[[3, 0, 1, 2]] - q *= 0.5 / math.sqrt(t * M[3, 3]) - else: - m00 = M[0, 0] - m01 = M[0, 1] - m02 = M[0, 2] - m10 = M[1, 0] - m11 = M[1, 1] - m12 = M[1, 2] - m20 = M[2, 0] - m21 = M[2, 1] - m22 = M[2, 2] - # symmetric matrix K - K = numpy.array([[m00-m11-m22, 0.0, 0.0, 0.0], - [m01+m10, m11-m00-m22, 0.0, 0.0], - [m02+m20, m12+m21, m22-m00-m11, 0.0], - [m21-m12, m02-m20, m10-m01, m00+m11+m22]]) - K /= 3.0 - # quaternion is eigenvector of K that corresponds to largest eigenvalue - w, V = numpy.linalg.eigh(K) - q = V[[3, 0, 1, 2], numpy.argmax(w)] - if q[0] < 0.0: - numpy.negative(q, q) - return q - - -def quaternion_multiply(quaternion1, quaternion0): - """Return multiplication of two quaternions. - - >>> q = quaternion_multiply([4, 1, -2, 3], [8, -5, 6, 7]) - >>> numpy.allclose(q, [28, -44, -14, 48]) - True - - """ - w0, x0, y0, z0 = quaternion0 - w1, x1, y1, z1 = quaternion1 - return numpy.array([ - -x1*x0 - y1*y0 - z1*z0 + w1*w0, - x1*w0 + y1*z0 - z1*y0 + w1*x0, - -x1*z0 + y1*w0 + z1*x0 + w1*y0, - x1*y0 - y1*x0 + z1*w0 + w1*z0], dtype=numpy.float64) - - -def quaternion_conjugate(quaternion): - """Return conjugate of quaternion. - - >>> q0 = random_quaternion() - >>> q1 = quaternion_conjugate(q0) - >>> q1[0] == q0[0] and all(q1[1:] == -q0[1:]) - True - - """ - q = numpy.array(quaternion, dtype=numpy.float64, copy=True) - numpy.negative(q[1:], q[1:]) - return q - - -def quaternion_inverse(quaternion): - """Return inverse of quaternion. - - >>> q0 = random_quaternion() - >>> q1 = quaternion_inverse(q0) - >>> numpy.allclose(quaternion_multiply(q0, q1), [1, 0, 0, 0]) - True - - """ - q = numpy.array(quaternion, dtype=numpy.float64, copy=True) - numpy.negative(q[1:], q[1:]) - return q / numpy.dot(q, q) - - -def quaternion_real(quaternion): - """Return real part of quaternion. - - >>> quaternion_real([3, 0, 1, 2]) - 3.0 - - """ - return float(quaternion[0]) - - -def quaternion_imag(quaternion): - """Return imaginary part of quaternion. - - >>> quaternion_imag([3, 0, 1, 2]) - array([ 0., 1., 2.]) - - """ - return numpy.array(quaternion[1:4], dtype=numpy.float64, copy=True) - - -def quaternion_slerp(quat0, quat1, fraction, spin=0, shortestpath=True): - """Return spherical linear interpolation between two quaternions. - - >>> q0 = random_quaternion() - >>> q1 = random_quaternion() - >>> q = quaternion_slerp(q0, q1, 0) - >>> numpy.allclose(q, q0) - True - >>> q = quaternion_slerp(q0, q1, 1, 1) - >>> numpy.allclose(q, q1) - True - >>> q = quaternion_slerp(q0, q1, 0.5) - >>> angle = math.acos(numpy.dot(q0, q)) - >>> numpy.allclose(2, math.acos(numpy.dot(q0, q1)) / angle) or \ - numpy.allclose(2, math.acos(-numpy.dot(q0, q1)) / angle) - True - - """ - q0 = unit_vector(quat0[:4]) - q1 = unit_vector(quat1[:4]) - if fraction == 0.0: - return q0 - elif fraction == 1.0: - return q1 - d = numpy.dot(q0, q1) - if abs(abs(d) - 1.0) < _EPS: - return q0 - if shortestpath and d < 0.0: - # invert rotation - d = -d - numpy.negative(q1, q1) - angle = math.acos(d) + spin * math.pi - if abs(angle) < _EPS: - return q0 - isin = 1.0 / math.sin(angle) - q0 *= math.sin((1.0 - fraction) * angle) * isin - q1 *= math.sin(fraction * angle) * isin - q0 += q1 - return q0 - - -def random_quaternion(rand=None): - """Return uniform random unit quaternion. - - rand: array like or None - Three independent random variables that are uniformly distributed - between 0 and 1. - - >>> q = random_quaternion() - >>> numpy.allclose(1, vector_norm(q)) - True - >>> q = random_quaternion(numpy.random.random(3)) - >>> len(q.shape), q.shape[0]==4 - (1, True) - - """ - if rand is None: - rand = numpy.random.rand(3) - else: - assert len(rand) == 3 - r1 = numpy.sqrt(1.0 - rand[0]) - r2 = numpy.sqrt(rand[0]) - pi2 = math.pi * 2.0 - t1 = pi2 * rand[1] - t2 = pi2 * rand[2] - return numpy.array([numpy.cos(t2)*r2, numpy.sin(t1)*r1, - numpy.cos(t1)*r1, numpy.sin(t2)*r2]) - - -def random_rotation_matrix(rand=None): - """Return uniform random rotation matrix. - - rand: array like - Three independent random variables that are uniformly distributed - between 0 and 1 for each returned quaternion. - - >>> R = random_rotation_matrix() - >>> numpy.allclose(numpy.dot(R.T, R), numpy.identity(4)) - True - - """ - return quaternion_matrix(random_quaternion(rand)) - - -class Arcball(object): - """Virtual Trackball Control. - - >>> ball = Arcball() - >>> ball = Arcball(initial=numpy.identity(4)) - >>> ball.place([320, 320], 320) - >>> ball.down([500, 250]) - >>> ball.drag([475, 275]) - >>> R = ball.matrix() - >>> numpy.allclose(numpy.sum(R), 3.90583455) - True - >>> ball = Arcball(initial=[1, 0, 0, 0]) - >>> ball.place([320, 320], 320) - >>> ball.setaxes([1, 1, 0], [-1, 1, 0]) - >>> ball.constrain = True - >>> ball.down([400, 200]) - >>> ball.drag([200, 400]) - >>> R = ball.matrix() - >>> numpy.allclose(numpy.sum(R), 0.2055924) - True - >>> ball.next() - - """ - def __init__(self, initial=None): - """Initialize virtual trackball control. - - initial : quaternion or rotation matrix - - """ - self._axis = None - self._axes = None - self._radius = 1.0 - self._center = [0.0, 0.0] - self._vdown = numpy.array([0.0, 0.0, 1.0]) - self._constrain = False - if initial is None: - self._qdown = numpy.array([1.0, 0.0, 0.0, 0.0]) - else: - initial = numpy.array(initial, dtype=numpy.float64) - if initial.shape == (4, 4): - self._qdown = quaternion_from_matrix(initial) - elif initial.shape == (4, ): - initial /= vector_norm(initial) - self._qdown = initial - else: - raise ValueError("initial not a quaternion or matrix") - self._qnow = self._qpre = self._qdown - - def place(self, center, radius): - """Place Arcball, e.g. when window size changes. - - center : sequence[2] - Window coordinates of trackball center. - radius : float - Radius of trackball in window coordinates. - - """ - self._radius = float(radius) - self._center[0] = center[0] - self._center[1] = center[1] - - def setaxes(self, *axes): - """Set axes to constrain rotations.""" - if axes is None: - self._axes = None - else: - self._axes = [unit_vector(axis) for axis in axes] - - @property - def constrain(self): - """Return state of constrain to axis mode.""" - return self._constrain - - @constrain.setter - def constrain(self, value): - """Set state of constrain to axis mode.""" - self._constrain = bool(value) - - def down(self, point): - """Set initial cursor window coordinates and pick constrain-axis.""" - self._vdown = arcball_map_to_sphere(point, self._center, self._radius) - self._qdown = self._qpre = self._qnow - if self._constrain and self._axes is not None: - self._axis = arcball_nearest_axis(self._vdown, self._axes) - self._vdown = arcball_constrain_to_axis(self._vdown, self._axis) - else: - self._axis = None - - def drag(self, point): - """Update current cursor window coordinates.""" - vnow = arcball_map_to_sphere(point, self._center, self._radius) - if self._axis is not None: - vnow = arcball_constrain_to_axis(vnow, self._axis) - self._qpre = self._qnow - t = numpy.cross(self._vdown, vnow) - if numpy.dot(t, t) < _EPS: - self._qnow = self._qdown - else: - q = [numpy.dot(self._vdown, vnow), t[0], t[1], t[2]] - self._qnow = quaternion_multiply(q, self._qdown) - - def next(self, acceleration=0.0): - """Continue rotation in direction of last drag.""" - q = quaternion_slerp(self._qpre, self._qnow, 2.0+acceleration, False) - self._qpre, self._qnow = self._qnow, q - - def matrix(self): - """Return homogeneous rotation matrix.""" - return quaternion_matrix(self._qnow) - - -def arcball_map_to_sphere(point, center, radius): - """Return unit sphere coordinates from window coordinates.""" - v0 = (point[0] - center[0]) / radius - v1 = (center[1] - point[1]) / radius - n = v0*v0 + v1*v1 - if n > 1.0: - # position outside of sphere - n = math.sqrt(n) - return numpy.array([v0/n, v1/n, 0.0]) - else: - return numpy.array([v0, v1, math.sqrt(1.0 - n)]) - - -def arcball_constrain_to_axis(point, axis): - """Return sphere point perpendicular to axis.""" - v = numpy.array(point, dtype=numpy.float64, copy=True) - a = numpy.array(axis, dtype=numpy.float64, copy=True) - v -= a * numpy.dot(a, v) # on plane - n = vector_norm(v) - if n > _EPS: - if v[2] < 0.0: - numpy.negative(v, v) - v /= n - return v - if a[2] == 1.0: - return numpy.array([1.0, 0.0, 0.0]) - return unit_vector([-a[1], a[0], 0.0]) - - -def arcball_nearest_axis(point, axes): - """Return axis, which arc is nearest to point.""" - point = numpy.array(point, dtype=numpy.float64, copy=False) - nearest = None - mx = -1.0 - for axis in axes: - t = numpy.dot(arcball_constrain_to_axis(point, axis), point) - if t > mx: - nearest = axis - mx = t - return nearest - - -# epsilon for testing whether a number is close to zero -_EPS = numpy.finfo(float).eps * 4.0 - -# axis sequences for Euler angles -_NEXT_AXIS = [1, 2, 0, 1] - -# map axes strings to/from tuples of inner axis, parity, repetition, frame -_AXES2TUPLE = { - 'sxyz': (0, 0, 0, 0), 'sxyx': (0, 0, 1, 0), 'sxzy': (0, 1, 0, 0), - 'sxzx': (0, 1, 1, 0), 'syzx': (1, 0, 0, 0), 'syzy': (1, 0, 1, 0), - 'syxz': (1, 1, 0, 0), 'syxy': (1, 1, 1, 0), 'szxy': (2, 0, 0, 0), - 'szxz': (2, 0, 1, 0), 'szyx': (2, 1, 0, 0), 'szyz': (2, 1, 1, 0), - 'rzyx': (0, 0, 0, 1), 'rxyx': (0, 0, 1, 1), 'ryzx': (0, 1, 0, 1), - 'rxzx': (0, 1, 1, 1), 'rxzy': (1, 0, 0, 1), 'ryzy': (1, 0, 1, 1), - 'rzxy': (1, 1, 0, 1), 'ryxy': (1, 1, 1, 1), 'ryxz': (2, 0, 0, 1), - 'rzxz': (2, 0, 1, 1), 'rxyz': (2, 1, 0, 1), 'rzyz': (2, 1, 1, 1)} - -_TUPLE2AXES = dict((v, k) for k, v in _AXES2TUPLE.items()) - - -def vector_norm(data, axis=None, out=None): - """Return length, i.e. Euclidean norm, of ndarray along axis. - - >>> v = numpy.random.random(3) - >>> n = vector_norm(v) - >>> numpy.allclose(n, numpy.linalg.norm(v)) - True - >>> v = numpy.random.rand(6, 5, 3) - >>> n = vector_norm(v, axis=-1) - >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=2))) - True - >>> n = vector_norm(v, axis=1) - >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1))) - True - >>> v = numpy.random.rand(5, 4, 3) - >>> n = numpy.empty((5, 3)) - >>> vector_norm(v, axis=1, out=n) - >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1))) - True - >>> vector_norm([]) - 0.0 - >>> vector_norm([1]) - 1.0 - - """ - data = numpy.array(data, dtype=numpy.float64, copy=True) - if out is None: - if data.ndim == 1: - return math.sqrt(numpy.dot(data, data)) - data *= data - out = numpy.atleast_1d(numpy.sum(data, axis=axis)) - numpy.sqrt(out, out) - return out - else: - data *= data - numpy.sum(data, axis=axis, out=out) - numpy.sqrt(out, out) - - -def unit_vector(data, axis=None, out=None): - """Return ndarray normalized by length, i.e. Euclidean norm, along axis. - - >>> v0 = numpy.random.random(3) - >>> v1 = unit_vector(v0) - >>> numpy.allclose(v1, v0 / numpy.linalg.norm(v0)) - True - >>> v0 = numpy.random.rand(5, 4, 3) - >>> v1 = unit_vector(v0, axis=-1) - >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=2)), 2) - >>> numpy.allclose(v1, v2) - True - >>> v1 = unit_vector(v0, axis=1) - >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=1)), 1) - >>> numpy.allclose(v1, v2) - True - >>> v1 = numpy.empty((5, 4, 3)) - >>> unit_vector(v0, axis=1, out=v1) - >>> numpy.allclose(v1, v2) - True - >>> list(unit_vector([])) - [] - >>> list(unit_vector([1])) - [1.0] - - """ - if out is None: - data = numpy.array(data, dtype=numpy.float64, copy=True) - if data.ndim == 1: - data /= math.sqrt(numpy.dot(data, data)) - return data - else: - if out is not data: - out[:] = numpy.array(data, copy=False) - data = out - length = numpy.atleast_1d(numpy.sum(data*data, axis)) - numpy.sqrt(length, length) - if axis is not None: - length = numpy.expand_dims(length, axis) - data /= length - if out is None: - return data - - -def random_vector(size): - """Return array of random doubles in the half-open interval [0.0, 1.0). - - >>> v = random_vector(10000) - >>> numpy.all(v >= 0) and numpy.all(v < 1) - True - >>> v0 = random_vector(10) - >>> v1 = random_vector(10) - >>> numpy.any(v0 == v1) - False - - """ - return numpy.random.random(size) - - -def vector_product(v0, v1, axis=0): - """Return vector perpendicular to vectors. - - >>> v = vector_product([2, 0, 0], [0, 3, 0]) - >>> numpy.allclose(v, [0, 0, 6]) - True - >>> v0 = [[2, 0, 0, 2], [0, 2, 0, 2], [0, 0, 2, 2]] - >>> v1 = [[3], [0], [0]] - >>> v = vector_product(v0, v1) - >>> numpy.allclose(v, [[0, 0, 0, 0], [0, 0, 6, 6], [0, -6, 0, -6]]) - True - >>> v0 = [[2, 0, 0], [2, 0, 0], [0, 2, 0], [2, 0, 0]] - >>> v1 = [[0, 3, 0], [0, 0, 3], [0, 0, 3], [3, 3, 3]] - >>> v = vector_product(v0, v1, axis=1) - >>> numpy.allclose(v, [[0, 0, 6], [0, -6, 0], [6, 0, 0], [0, -6, 6]]) - True - - """ - return numpy.cross(v0, v1, axis=axis) - - -def angle_between_vectors(v0, v1, directed=True, axis=0): - """Return angle between vectors. - - If directed is False, the input vectors are interpreted as undirected axes, - i.e. the maximum angle is pi/2. - - >>> a = angle_between_vectors([1, -2, 3], [-1, 2, -3]) - >>> numpy.allclose(a, math.pi) - True - >>> a = angle_between_vectors([1, -2, 3], [-1, 2, -3], directed=False) - >>> numpy.allclose(a, 0) - True - >>> v0 = [[2, 0, 0, 2], [0, 2, 0, 2], [0, 0, 2, 2]] - >>> v1 = [[3], [0], [0]] - >>> a = angle_between_vectors(v0, v1) - >>> numpy.allclose(a, [0, 1.5708, 1.5708, 0.95532]) - True - >>> v0 = [[2, 0, 0], [2, 0, 0], [0, 2, 0], [2, 0, 0]] - >>> v1 = [[0, 3, 0], [0, 0, 3], [0, 0, 3], [3, 3, 3]] - >>> a = angle_between_vectors(v0, v1, axis=1) - >>> numpy.allclose(a, [1.5708, 1.5708, 1.5708, 0.95532]) - True - - """ - v0 = numpy.array(v0, dtype=numpy.float64, copy=False) - v1 = numpy.array(v1, dtype=numpy.float64, copy=False) - dot = numpy.sum(v0 * v1, axis=axis) - dot /= vector_norm(v0, axis=axis) * vector_norm(v1, axis=axis) - dot = numpy.clip(dot, -1.0, 1.0) - return numpy.arccos(dot if directed else numpy.fabs(dot)) - - -def inverse_matrix(matrix): - """Return inverse of square transformation matrix. - - >>> M0 = random_rotation_matrix() - >>> M1 = inverse_matrix(M0.T) - >>> numpy.allclose(M1, numpy.linalg.inv(M0.T)) - True - >>> for size in range(1, 7): - ... M0 = numpy.random.rand(size, size) - ... M1 = inverse_matrix(M0) - ... if not numpy.allclose(M1, numpy.linalg.inv(M0)): print(size) - - """ - return numpy.linalg.inv(matrix) - - -def concatenate_matrices(*matrices): - """Return concatenation of series of transformation matrices. - - >>> M = numpy.random.rand(16).reshape((4, 4)) - 0.5 - >>> numpy.allclose(M, concatenate_matrices(M)) - True - >>> numpy.allclose(numpy.dot(M, M.T), concatenate_matrices(M, M.T)) - True - - """ - M = numpy.identity(4) - for i in matrices: - M = numpy.dot(M, i) - return M - - -def is_same_transform(matrix0, matrix1): - """Return True if two matrices perform same transformation. - - >>> is_same_transform(numpy.identity(4), numpy.identity(4)) - True - >>> is_same_transform(numpy.identity(4), random_rotation_matrix()) - False - - """ - matrix0 = numpy.array(matrix0, dtype=numpy.float64, copy=True) - matrix0 /= matrix0[3, 3] - matrix1 = numpy.array(matrix1, dtype=numpy.float64, copy=True) - matrix1 /= matrix1[3, 3] - return numpy.allclose(matrix0, matrix1) - - -def is_same_quaternion(q0, q1): - """Return True if two quaternions are equal.""" - q0 = numpy.array(q0) - q1 = numpy.array(q1) - return numpy.allclose(q0, q1) or numpy.allclose(q0, -q1) - - -def _import_module(name, package=None, warn=True, postfix='_py', ignore='_'): - """Try import all public attributes from module into global namespace. - - Existing attributes with name clashes are renamed with prefix. - Attributes starting with underscore are ignored by default. - - Return True on successful import. - - """ - import warnings - from importlib import import_module - try: - if not package: - module = import_module(name) - else: - module = import_module('.' + name, package=package) - except ImportError as err: - if warn: - warnings.warn(str(err)) - else: - for attr in dir(module): - if ignore and attr.startswith(ignore): - continue - if postfix: - if attr in globals(): - globals()[attr + postfix] = globals()[attr] - elif warn: - warnings.warn('no Python implementation of ' + attr) - globals()[attr] = getattr(module, attr) - return True - - -_import_module('_transformations', __package__) - - -if __name__ == '__main__': - import doctest - import random # noqa: used in doctests - try: - numpy.set_printoptions(suppress=True, precision=5, legacy='1.13') - except TypeError: - numpy.set_printoptions(suppress=True, precision=5) - doctest.testmod() - -