From 0f6683ca6d438df1d6e9060f3ec657fa658d4a35 Mon Sep 17 00:00:00 2001 From: Pomax Date: Sun, 18 Oct 2020 14:27:57 -0700 Subject: [PATCH] ascii --- docs/chapters/arclength/content.en-GB.md | 8 +- docs/chapters/bsplines/content.en-GB.md | 20 +- docs/chapters/circles/content.en-GB.md | 16 +- docs/chapters/circles_cubic/content.en-GB.md | 32 +- docs/chapters/control/content.en-GB.md | 4 +- docs/chapters/control/content.zh-CN.md | 4 +- docs/chapters/derivatives/content.en-GB.md | 24 +- docs/chapters/explanation/content.en-GB.md | 4 +- docs/chapters/explanation/content.zh-CN.md | 4 +- docs/chapters/extremities/content.en-GB.md | 6 +- docs/chapters/inflections/content.en-GB.md | 8 +- docs/chapters/matrixsplit/content.en-GB.md | 6 +- docs/chapters/pointvectors/content.en-GB.md | 2 +- docs/chapters/reordering/content.en-GB.md | 10 +- docs/chapters/weightcontrol/content.en-GB.md | 2 +- docs/chapters/whatis/content.en-GB.md | 6 +- docs/chapters/whatis/content.zh-CN.md | 6 +- .../00480d8ea1d0b86eb66939bced85e14b.svg | 1 + .../041c2f2d5c115e27f059595775732dfa.svg | 1 - .../17282cb081f862dec197e591718c5f41.svg | 1 - .../203a75eeab5295c3ace2725e12893672.svg | 1 - .../6acf1a1e496f47c11e079a1d13f0a368.svg | 1 + .../72ab12864982fd8d9ee757689be93f2c.svg | 1 - .../a75137c250be63877a30f4bda8d801f8.svg | 1 + .../f6767b16ff8e04646f45fb9a1f3e4024.svg | 1 + .../56533f47e73ad9fea08fa9bb3f597d49.png | Bin 11010 -> 11031 bytes .../5ce02cbdbc47585c588f2656d5161a32.png | Bin 11513 -> 11527 bytes ...g => f251e86158649c0e57f7a772ebff83b4.svg} | 0 .../fe2663b205d14c157a5a02bfbbd55987.png | Bin 12354 -> 12388 bytes ...g => 20e910bbea2e6eff511cb13cef18ef3b.svg} | 0 ...g => a88566be442b67fb71f727de6bdb66df.svg} | 0 ...g => 1829e42ea956ee4df0e45d9ac5334ef7.svg} | 0 ...g => 7ab3da0922477af4cc09f5852100976b.svg} | 0 ...g => 8b4e1d0a62380ed011f27c645ed13b28.svg} | 0 ...g => 942c90bc8311e49d94059b3127fc78d5.svg} | 0 ...g => d4bfb47b623c968e3231566c9705c6c4.svg} | 0 ...g => 2d9df7ddd2aa223a951016b93d9620c2.svg} | 0 ...g => 329dc34299d2fdb3c5f17828e3a23da0.svg} | 0 ...g => 38b58b3c759b9bf340a3cf3de8bc599e.svg} | 0 ...g => 459c037fb92685566d624f81a298e9c8.svg} | 0 ...g => 6a14e5a71dd9e0cefe158640eabb8696.svg} | 0 ...g => 8b4e1d0a62380ed011f27c645ed13b28.svg} | 0 ...g => bc884416145a846cebddc8c5d13f147f.svg} | 0 ...g => eeff3b36af960053cb4eb692abe36cd8.svg} | 0 ...g => b58fb122c5c8159938182c185f287142.svg} | 0 ...g => 2d733684f81b65a42c4cdb3f1e589c8b.svg} | 0 ...g => 2fc50617b6886534d1ab4638ed8a24ac.svg} | 0 ...g => 50616f9c922967c0c9c179af9b091947.svg} | 0 ...g => 6a3672344bb571eadb72669f60a93ff4.svg} | 0 ...g => a7c61e0e8b42010df6dab641c92ef13d.svg} | 0 ...g => b58fb122c5c8159938182c185f287142.svg} | 0 ...g => f29a9d52897d2060a0c8a37073ed04fc.svg} | 0 ...g => f79dd2f2d992e22b8d057fdc641290b0.svg} | 0 ...g => 2c398b492aadc90eb4e4853fc20b23e9.svg} | 0 ...g => c4858be225d004441b2aefedacda89a3.svg} | 0 ...g => 2dbf3071d74e2ba37ab888aaa3c1a17c.svg} | 0 ...g => d7d564126099bc0740058a7cdd744772.svg} | 0 ...g => f9f2258e59b038659087a5e87ba2e0af.svg} | 0 ...g => 55b45214ba90c96978cdc9cdfee24fef.svg} | 0 ...g => 598739d23cf8dbcdebe033e4c7f1d28a.svg} | 0 ...g => 7a1e792cd3fa6f3482459e154abf2e7d.svg} | 0 ...g => 58b19accb8a68c665ff5cbed610eea4e.svg} | 0 .../c4874e1205aabe624e5504abe154eae9.png | Bin 11653 -> 11933 bytes ...g => e9fc9c715bb55a702db68b2bb6da0a68.svg} | 0 .../02165788eb08947243196b24b10c19c0.svg | 1 - .../2ec04091c55fe31bf85ac28c5b6d95cb.svg | 1 + ...g => c3f06301f5ce610df1217bc633257297.svg} | 0 .../15225da473048d8c7b5b473b89de0b66.ascii | 11 + .../50543216f39c1b10af7cf4823844dd31.ascii | 7 + .../6a65a8327c06bc6f14cc4e0751d8e49e.ascii | 4 + .../b9854fbcb1096f736607d292dbe48371.ascii | 5 + .../bb8674f5f36b054b7734e34b91ed924f.ascii | 5 + .../c018aab3952ea9193848564aab12b241.ascii | 7 + .../c10cf18edeffed67dc94d250310db475.ascii | 7 + .../c14d8ce6eccca2c8063af40e5ac0bfd4.ascii | 10 + .../eccc1bdb9423bbfe2d42418fc8a7dd24.ascii | 10 + .../f78ce50f725f208f25090abc7fd741b7.ascii | 7 + .../00480d8ea1d0b86eb66939bced85e14b.ascii | 6 + .../6acf1a1e496f47c11e079a1d13f0a368.ascii | 6 + .../a75137c250be63877a30f4bda8d801f8.ascii | 6 + .../f6767b16ff8e04646f45fb9a1f3e4024.ascii | 6 + .../046bbb52e8c8ed617fdf3a4fd18d62e1.ascii | 7 + .../0748ad25185548150b6c1c4c7039207e.ascii | 12 + .../2f80643c66d8f1448b13537a7b24eb45.ascii | 6 + .../59ebc3a7c3547a50998d1ea3664fb688.ascii | 6 + .../a91fbfb7abc38ff712ef660d85679f2e.ascii | 14 + .../f251e86158649c0e57f7a772ebff83b4.ascii | 9 + .../20e910bbea2e6eff511cb13cef18ef3b.ascii | 30 + .../89f8e37237d066fa70ccf6d37b3a4922.ascii | 5 + .../a88566be442b67fb71f727de6bdb66df.ascii | 5 + .../c7af721e5e201fc3742bce67ff6cd560.ascii | 5 + .../cbdf5a61de10eeb6f23be077cf047ab5.ascii | 7 + .../ee203de6e554936588eb93adead0a3e5.ascii | 5 + .../f0bf7d0f1931060cd801ff707f482c16.ascii | 5 + .../2b6478075f2f9f5e5973e01b3b3a0c8b.ascii | 5 + .../464b4ec0b67f248459792752be86d46d.ascii | 6 + .../5f174bc5019245f467ca63ae84b90a4b.ascii | 13 + .../674d251590411398d06fb99cba7920f7.ascii | 6 + .../6959a552f2c90a2bcaa787c23e19f488.ascii | 7 + .../7ed8b53100737cbf7d87aa6267395d2b.ascii | 5 + .../88e3fae7aeef6d7614290587422542c9.ascii | 7 + .../8e39a9e0c7469b4b45a260dd23bd4c6a.ascii | 11 + .../9420fd9d7a8de30714e23b8f31b3aa6d.ascii | 9 + .../ccbfd22cbccf633d182f7f451dee5164.ascii | 9 + .../e61fd49e554a0ffc7d64893c75cd376d.ascii | 24 + .../f855cbf1d73e4bb7bccbbd4721d95f41.ascii | 7 + .../00357d2a2168fe313cd0b38d95a1a681.ascii | 14 + .../157b287d6b74109d8c8b634990ea6549.ascii | 14 + .../1cef6bbf7b3d10e8c0aaecfac816cc86.ascii | 10 + .../1f9fc156aeed9eb092573cd7446593d9.ascii | 10 + .../211dadbb9d0f6b2e381f18ea3c4d12fb.ascii | 14 + .../4c8684109149b0dc79f5583a5912fcd9.ascii | 10 + .../4e0da16710a7339f04dd844c7705423e.ascii | 12 + .../53f216327c0bbcf02b2a331fbf44d389.ascii | 12 + .../574bed6665be06b309b8da722c616a41.ascii | 12 + .../65e589eafae8ff2f39392d8143d2845c.ascii | 12 + .../7bab9dd3da654b05fa065076894e2d82.ascii | 10 + .../8a2a00812363fe1a6cfa7f81b48d31d1.ascii | 12 + .../8d3a5ca7188f53b914229133b3dbe5fe.ascii | 10 + .../8de53f207d68b25854a5f0b924ac6010.ascii | 14 + .../917b176a45959b026c56f81999505dc7.ascii | 12 + .../9593c057c84ebf9beb70fd57a11c7e12.ascii | 10 + .../a55773fdcdfd99947acc4f86ad2d4a3d.ascii | 14 + .../a8158b35ec221cccff51a53cdc7f440b.ascii | 10 + .../b59ff8d654e65df4c874901983208893.ascii | 12 + .../b94a4dafc12ba7e4fbf3aff924f55464.ascii | 14 + .../c0e30b49fbfce6f6b3c81eaa6ca5154f.ascii | 14 + .../c1f8861583b4176a9b607aa6a05f9356.ascii | 10 + .../d09e7466c267614c89ead28d6a900ba1.ascii | 10 + .../defc6fa4b51fa3c1945d15449f0f392d.ascii | 10 + .../fe2e6fd487df224b2f55a601898ce333.ascii | 10 + .../06369b00338310df0a810c592485aa0a.ascii | 5 + .../1829e42ea956ee4df0e45d9ac5334ef7.ascii | 3 + .../5a23f3bc298c85540c6dd18e304d9224.ascii | 17 + .../7ab3da0922477af4cc09f5852100976b.ascii | 5 + .../8237af1396bb567d70c8b5e4dd7f8115.ascii | 6 + .../8b4e1d0a62380ed011f27c645ed13b28.ascii | 5 + .../942c90bc8311e49d94059b3127fc78d5.ascii | 15 + .../986ae9104e0bc52e95689ae7ae4504db.ascii | 8 + .../a04bd1558a76e60b8ca6e1fe4fa38c00.ascii | 5 + .../d4bfb47b623c968e3231566c9705c6c4.ascii | 5 + .../f9d15462df31186feef8c3d53c0f6163.ascii | 8 + .../046e0bec7cc3d8a502b2f76b4722be2d.ascii | 8 + .../0b4c1e8f1f7a9c1292787f127ddb1624.ascii | 5 + .../2ba4e0e2dbbdf3ea7dbd9cff3e049d0d.ascii | 8 + .../2d9df7ddd2aa223a951016b93d9620c2.ascii | 4 + .../329dc34299d2fdb3c5f17828e3a23da0.ascii | 5 + .../38b58b3c759b9bf340a3cf3de8bc599e.ascii | 5 + .../459c037fb92685566d624f81a298e9c8.ascii | 18 + .../6a14e5a71dd9e0cefe158640eabb8696.ascii | 6 + .../750e2c874fb58237608ebade1589fccc.ascii | 5 + .../8b4e1d0a62380ed011f27c645ed13b28.ascii | 5 + .../bc884416145a846cebddc8c5d13f147f.ascii | 11 + .../d28eb43a1b34befb7659dcdfb3a9e718.ascii | 5 + .../eeff3b36af960053cb4eb692abe36cd8.ascii | 5 + .../fa5d308b0b50400fbae1411f390bc7ce.ascii | 12 + .../20b0be6397fbd726298de6ec70a8544b.ascii | 6 + .../9df7dc66b51db8e3046e1f359874c38e.ascii | 5 + .../b58fb122c5c8159938182c185f287142.ascii | 7 + .../060acd6ff0a050fe4d98a7802a2b3a3f.ascii | 8 + .../561ab3a938d655550de0abf458ac2494.ascii | 5 + .../afd8cb8b0fe291ff703752c1c9cc33d4.ascii | 10 + .../06605e008956609e8844ef95697c9096.ascii | 5 + .../2f82371abb7835f9b9d440dc5dd151a8.ascii | 6 + .../31d659cbc72bf304abf4c9a75b6b81de.ascii | 7 + .../38bb81bdd3eaa72c2336514187aa374b.ascii | 11 + .../409d10c3005b0c93489d72a5dba692d7.ascii | 7 + .../464dbfb5adb6233108053dfac6fa4fe5.ascii | 5 + .../4dd55c228a26bb50da912a45e8721024.ascii | 11 + .../505ab1ada6a187e9ba392d19739ac2c5.ascii | 5 + .../6f734d319a1cfe0de76574a65abb07e1.ascii | 8 + .../7b0199bb515d2754c03d8f796b29febf.ascii | 4 + .../7c6b50cee5dc685515943a199d7a65fc.ascii | 9 + .../8068231b915832938136d5833f74751d.ascii | 4 + .../940455f4016ab1be6d46c6f176fd2f76.ascii | 5 + .../9651a687e1522b00bcba063881230902.ascii | 6 + .../989f2ad06ae308f71cef527a5594129a.ascii | 4 + .../9dec10b81a61b456ca1550cd9b7ba513.ascii | 4 + .../a6faaf6083c818431988fef49421cc47.ascii | 7 + .../b017da988c9a778a4ce6a6f4ea4790d4.ascii | 9 + .../ea24b0e42f0a89464bda275ac8f9bacf.ascii | 5 + .../12fa7f83f055ef2078cc9f04e1468663.ascii | 5 + .../18c6e782012234a2c7425204505c8888.ascii | 13 + .../2d733684f81b65a42c4cdb3f1e589c8b.ascii | 6 + .../2fc50617b6886534d1ab4638ed8a24ac.ascii | 7 + .../50616f9c922967c0c9c179af9b091947.ascii | 5 + .../64c06c61727d0912a67c0f287a395e47.ascii | 11 + .../67ca2710769505572e097ffb40de099f.ascii | 5 + .../6a3672344bb571eadb72669f60a93ff4.ascii | 7 + .../897cfd8648720dc21463a9358cc65ab4.ascii | 14 + .../a7c61e0e8b42010df6dab641c92ef13d.ascii | 6 + .../a992185a346518b5ca159484019b6917.ascii | 5 + .../b58fb122c5c8159938182c185f287142.ascii | 7 + .../c3ac18fe4ba0606a15bc111e52b17a9a.ascii | 5 + .../f29a9d52897d2060a0c8a37073ed04fc.ascii | 9 + .../f67d2d379ba6dfaa7f7686a7d1eae367.ascii | 5 + .../0cc876c56200446c60114c1b0eeeb2cc.ascii | 3 + .../2493468e73b73f43eba8f66f0c189d1a.ascii | 7 + .../2c47081c2a9c20d2110f13daa482a3ab.ascii | 8 + .../6914ba615733c387251682db7a3db045.ascii | 4 + .../6aa5d4e20e83be1c95eaad792517dde9.ascii | 6 + .../7acc94ec70f053fd10dab69d424b02a6.ascii | 6 + .../855a34c7f72733be6529c3fb33fa1a23.ascii | 4 + .../8986c536df8153b30197c3a5407d233a.ascii | 6 + .../9229934d71b0b02921bc92594ef11a98.ascii | 8 + .../a2891980850ddbb27d308ac112d69f74.ascii | 4 + .../adc7729f7872d71f3fbb1a79741ce10f.ascii | 7 + .../b5977078d36d847fb299cbe3e7e2c3ba.ascii | 5 + .../f79dd2f2d992e22b8d057fdc641290b0.ascii | 5 + .../b0eb0b24e7fa29c545ab1479d2df0554.ascii | 4 + .../e2e71b397009b51af8a3ee848bc727b4.ascii | 4 + .../f56f59f3c0b057c8ec79a477e4e38bec.ascii | 4 + .../fd520a6e2c7f39e90496e5cf494cce2e.ascii | 4 + .../1fab66c84e7df38a2edda147f939bd80.ascii | 7 + .../2c398b492aadc90eb4e4853fc20b23e9.ascii | 7 + .../53e67a29f134bd561aca550a2091a196.ascii | 7 + .../55e16ef652d30face0f6586b675a6c7b.ascii | 5 + .../a6acf08f43aa1f48c08a40e76bdd2a31.ascii | 8 + .../c4858be225d004441b2aefedacda89a3.ascii | 6 + .../d1c65d927825f20c3c358d1ff96ce881.ascii | 17 + .../d31432533bd7940545d4a269eefbabf2.ascii | 6 + .../2dbf3071d74e2ba37ab888aaa3c1a17c.ascii | 10 + .../75fae2d0a94eae4addf074c294855fc7.ascii | 15 + .../a283e01df17f3d763ec89621f2af6c5c.ascii | 4 + .../be9e409d619ecd735b0fbc219bec6d07.ascii | 9 + .../d7d564126099bc0740058a7cdd744772.ascii | 7 + .../e50243eaa99b5acc08533dd2e9b71a74.ascii | 5 + .../ed68dcfb203517ca080fe48914769fb0.ascii | 3 + .../f9f2258e59b038659087a5e87ba2e0af.ascii | 10 + .../1a64ed455c6dd2f8cacca5e5e12bdcc1.ascii | 6 + .../1bae50fefa43210b3a6259d1984f6cbc.ascii | 8 + .../67a5ea33d6c6558f7d954b18226f4956.ascii | 10 + .../87cfac83cb8a4b0bee68ef006effc611.ascii | 4 + .../8ecff6b8a37d60385d287ea2b26876db.ascii | 6 + .../9a9a55f5b0323d9ea88f82fc6be58ad3.ascii | 5 + .../b32cae2dfc47d5f36df0bc3defb7dfa8.ascii | 10 + .../b9527f7d5a0f5d2d737eac118d69243e.ascii | 6 + .../cdd88611833f3b178df91278359a4193.ascii | 10 + .../ec118f296511c6e9ac8727be3703a7ce.ascii | 10 + .../11505e0215ef026f2e49383ebb4a1abb.ascii | 12 + .../17e308aa6d459b1d06d3160cc8e2e786.ascii | 9 + .../1bae50fefa43210b3a6259d1984f6cbc.ascii | 8 + .../3b5e41808b6c3bc66f3da2f40651410e.ascii | 8 + .../4764868f43815e471bb1ea95a81e1633.ascii | 8 + .../480ebd0234e2fe1adc94926e8ed4339c.ascii | 9 + .../4ce218bc968cbd98da0ca6ab66d415ed.ascii | 8 + .../55b45214ba90c96978cdc9cdfee24fef.ascii | 8 + .../598739d23cf8dbcdebe033e4c7f1d28a.ascii | 8 + .../5e008143622c66bb5e9cc4d5d6a8ea62.ascii | 7 + .../63d1337d275abf7b296d500b9b5821fd.ascii | 8 + .../6a22184e6ca869d28f4a252b64f23eff.ascii | 8 + .../7a1e792cd3fa6f3482459e154abf2e7d.ascii | 8 + .../9a4899b69e03cd4ad02c5eedffaa6a2f.ascii | 9 + .../a899891096d82b7fdb23a90e6106b6df.ascii | 12 + .../baedd4067516584d425b93331b7ce04f.ascii | 8 + .../c32007be095224e0d157a8f71c62c90e.ascii | 8 + .../c341532f693c2c1adfd298597bbfb5b5.ascii | 7 + .../d9d04b9b6c66788d18832a383d6f7ea0.ascii | 8 + .../dceed84990aaf6878bcc67ddbaa8d8d9.ascii | 8 + .../e079f44b56e07c8d7f83c17c8ebf1ecf.ascii | 8 + .../e2622175dadafecc015f15c79ddf3002.ascii | 8 + .../e58196b82b78f584779208cce88137f5.ascii | 9 + .../ebf8d72c6056476172deeb89726b75c8.ascii | 10 + .../f565e66677138927335535d009409c3d.ascii | 8 + .../f63067c2c3042c374a58dfa7f692309e.ascii | 8 + .../f690ff0502d9fd7d4697cc43d98afd5d.ascii | 10 + .../6f12fcc00f4106bbc920d7451398d3b2.ascii | 6 + .../70262c533569a7da06cc1b950e932d6f.ascii | 4 + .../3c80407cfd0bd8c8ebea239272aeabe5.ascii | 3 + .../57e62f3f2f7526b2cf7c1b276c17e472.ascii | 5 + .../af4b584bb280cc941603255f62c9cc1a.ascii | 6 + .../cf8e602eb0595cf4d9b851c6bda741af.ascii | 6 + .../de8cdb128273beff2d98534b9f090b85.ascii | 3 + .../4fe687c8a65265a2a755ba5841d0e31d.ascii | 4 + .../8ffdd4a58cbd0fc24caef781f23a7950.ascii | 6 + .../a5cd63b54be6b554290c38787cfbbabd.ascii | 4 + .../f8182445c1cd7ae9f368b88fa7090e53.ascii | 11 + .../1df6c055ae8e41a46bfdebc55a4f17c0.ascii | 4 + .../58b19accb8a68c665ff5cbed610eea4e.ascii | 9 + .../8b15a314beca97071b0ccb22c969355d.ascii | 7 + .../b60cdba673c2c9fc84c800f07fd18145.ascii | 16 + .../f02e359a5e47667919738fff69d2625b.ascii | 4 + .../a37252ff55837b918d9d64078ae92ae7.ascii | 4 + .../ec93d3c42f0ae52a05d0aff9739675e5.ascii | 6 + .../056e25c397c524d80f378ce3823c7e78.ascii | 21 + .../0f5698b31598b2390e966fc5e43ab53e.ascii | 14 + .../1f5b60d190a1c7099b3411e4cc477291.ascii | 4 + .../46e64dc07502e14217ec83d755f736ee.ascii | 16 + .../4ff41e183d60d5fd10a5d3d30dd63358.ascii | 17 + .../56130afc4cb313e0e74cf670d34590f6.ascii | 6 + .../8090b63b005bf3edb916b97bda317a0e.ascii | 5 + .../ab7c087f7c070d43a42f3f03010a7427.ascii | 14 + .../e9fc9c715bb55a702db68b2bb6da0a68.ascii | 9 + .../ff224ded6bbbc94b43130f5f8eeb5d29.ascii | 3 + .../2ec04091c55fe31bf85ac28c5b6d95cb.ascii | 9 + .../85d526fb17f9e859dcd7d40d22192e37.ascii | 5 + .../06bbc5c11ad3fd88ff93eb2c06177b66.ascii | 11 + .../c3f06301f5ce610df1217bc633257297.ascii | 11 + .../316e7fae61e10014000d770209779ab6.ascii | 3 + .../4d23ee228c5b1cbc40e380496c2184d1.ascii | 3 + .../699459d89ca6622c90c1e42e4aa03f32.ascii | 3 + docs/index.html | 2310 ++++++++++++++++- docs/ja-JP/index.html | 2296 +++++++++++++++- docs/news/00-draft.md | 28 +- docs/news/2020-09-18.html | 15 +- docs/news/index.html | 2 +- docs/news/rss.xml | 15 +- docs/zh-CN/index.html | 2310 ++++++++++++++++- package.json | 14 +- .../markdown/processors/latex/latex-to-svg.js | 145 +- src/project-paths.js | 2 + src/tex2utf/README.md | 1 + src/tex2utf/tex2utf.pl | 2264 ++++++++++++++++ test.js | 21 + 314 files changed, 11182 insertions(+), 266 deletions(-) create mode 100644 docs/images/chapters/aligning/00480d8ea1d0b86eb66939bced85e14b.svg delete mode 100644 docs/images/chapters/aligning/041c2f2d5c115e27f059595775732dfa.svg delete mode 100644 docs/images/chapters/aligning/17282cb081f862dec197e591718c5f41.svg delete mode 100644 docs/images/chapters/aligning/203a75eeab5295c3ace2725e12893672.svg create mode 100644 docs/images/chapters/aligning/6acf1a1e496f47c11e079a1d13f0a368.svg delete mode 100644 docs/images/chapters/aligning/72ab12864982fd8d9ee757689be93f2c.svg create mode 100644 docs/images/chapters/aligning/a75137c250be63877a30f4bda8d801f8.svg create mode 100644 docs/images/chapters/aligning/f6767b16ff8e04646f45fb9a1f3e4024.svg rename docs/images/chapters/arclength/{261454d5d35a6dcefe97f3e4cfe5a142.svg => f251e86158649c0e57f7a772ebff83b4.svg} (100%) rename docs/images/chapters/bsplines/{f0e96cf0de35d55c20e131e904ef2cc5.svg => 20e910bbea2e6eff511cb13cef18ef3b.svg} (100%) rename docs/images/chapters/bsplines/{392b7cadd922c5e46fa89ab09716aa7e.svg => a88566be442b67fb71f727de6bdb66df.svg} (100%) rename docs/images/chapters/circles/{a0fd085fa6191c9c5e026028074c6c51.svg => 1829e42ea956ee4df0e45d9ac5334ef7.svg} (100%) rename docs/images/chapters/circles/{c6b179d2a85b51c1a422f769197947fa.svg => 7ab3da0922477af4cc09f5852100976b.svg} (100%) rename docs/images/chapters/circles/{e33aefe157f12d688fcecc8a81eee83a.svg => 8b4e1d0a62380ed011f27c645ed13b28.svg} (100%) rename docs/images/chapters/circles/{6b4eb46b5f772fafcf8cfe390da8402c.svg => 942c90bc8311e49d94059b3127fc78d5.svg} (100%) rename docs/images/chapters/circles/{ae08c8a734426e4c6dd0373f7ced2d41.svg => d4bfb47b623c968e3231566c9705c6c4.svg} (100%) rename docs/images/chapters/circles_cubic/{80f6807fcb4f81fdda5b77071a1a67b2.svg => 2d9df7ddd2aa223a951016b93d9620c2.svg} (100%) rename docs/images/chapters/circles_cubic/{909b5f634b8a5efa61742e2d4f94af5d.svg => 329dc34299d2fdb3c5f17828e3a23da0.svg} (100%) rename docs/images/chapters/circles_cubic/{24675851ca7ce917a00a02084b456447.svg => 38b58b3c759b9bf340a3cf3de8bc599e.svg} (100%) rename docs/images/chapters/circles_cubic/{aa4d4d4175699c2feb561cf04e107477.svg => 459c037fb92685566d624f81a298e9c8.svg} (100%) rename docs/images/chapters/circles_cubic/{5ef95ecfcf09a88a58f9bcafa659ed90.svg => 6a14e5a71dd9e0cefe158640eabb8696.svg} (100%) rename docs/images/chapters/circles_cubic/{e33aefe157f12d688fcecc8a81eee83a.svg => 8b4e1d0a62380ed011f27c645ed13b28.svg} (100%) rename docs/images/chapters/circles_cubic/{7a863b956c3d87df5289b36e29555001.svg => bc884416145a846cebddc8c5d13f147f.svg} (100%) rename docs/images/chapters/circles_cubic/{fb21bf8b5cd13b3149885dd426bf79b4.svg => eeff3b36af960053cb4eb692abe36cd8.svg} (100%) rename docs/images/chapters/control/{1cb112753c51e98aa328484f12b4a4f1.svg => b58fb122c5c8159938182c185f287142.svg} (100%) rename docs/images/chapters/derivatives/{7040219e3888bf6cf2f6750259da327f.svg => 2d733684f81b65a42c4cdb3f1e589c8b.svg} (100%) rename docs/images/chapters/derivatives/{43eea1ddd3646dc387511e16d2508db2.svg => 2fc50617b6886534d1ab4638ed8a24ac.svg} (100%) rename docs/images/chapters/derivatives/{d51bf2f64f109da5a4138b24321597d1.svg => 50616f9c922967c0c9c179af9b091947.svg} (100%) rename docs/images/chapters/derivatives/{f81cd6166665abcc4aa433f31c20eac4.svg => 6a3672344bb571eadb72669f60a93ff4.svg} (100%) rename docs/images/chapters/derivatives/{977ff6fb1c7bff664e844f33ff23f420.svg => a7c61e0e8b42010df6dab641c92ef13d.svg} (100%) rename docs/images/chapters/derivatives/{1cb112753c51e98aa328484f12b4a4f1.svg => b58fb122c5c8159938182c185f287142.svg} (100%) rename docs/images/chapters/derivatives/{0c8a8fb27762b2f16a154937de35a764.svg => f29a9d52897d2060a0c8a37073ed04fc.svg} (100%) rename docs/images/chapters/explanation/{95dfdee360469d4b4be64bb43c96b53e.svg => f79dd2f2d992e22b8d057fdc641290b0.svg} (100%) rename docs/images/chapters/extremities/{e010384d41b8efd3b430071884656b79.svg => 2c398b492aadc90eb4e4853fc20b23e9.svg} (100%) rename docs/images/chapters/extremities/{99f05b09492d54d669831881026b11fa.svg => c4858be225d004441b2aefedacda89a3.svg} (100%) rename docs/images/chapters/inflections/{750893530458a4796d3afddcc901ec91.svg => 2dbf3071d74e2ba37ab888aaa3c1a17c.svg} (100%) rename docs/images/chapters/inflections/{590588aede098d00dd493123c4a632cc.svg => d7d564126099bc0740058a7cdd744772.svg} (100%) rename docs/images/chapters/inflections/{c68722c9f3f8cd3d1e7a1616a37bc4e3.svg => f9f2258e59b038659087a5e87ba2e0af.svg} (100%) rename docs/images/chapters/matrixsplit/{e32979a306a4cae24808a3abc0c91387.svg => 55b45214ba90c96978cdc9cdfee24fef.svg} (100%) rename docs/images/chapters/matrixsplit/{631a35d9c34fb375232a45af50e66602.svg => 598739d23cf8dbcdebe033e4c7f1d28a.svg} (100%) rename docs/images/chapters/matrixsplit/{4a448a31f707975f7eba3516262a6cd6.svg => 7a1e792cd3fa6f3482459e154abf2e7d.svg} (100%) rename docs/images/chapters/pointvectors/{349ae68c5a68247857960032eb76b8de.svg => 58b19accb8a68c665ff5cbed610eea4e.svg} (100%) rename docs/images/chapters/reordering/{dc6b93062b74a7162cd98edd7b95cd24.svg => e9fc9c715bb55a702db68b2bb6da0a68.svg} (100%) delete mode 100644 docs/images/chapters/weightcontrol/02165788eb08947243196b24b10c19c0.svg create mode 100644 docs/images/chapters/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.svg rename docs/images/chapters/whatis/{175a7fedac4f14c374bc861bfc2900dc.svg => c3f06301f5ce610df1217bc633257297.svg} (100%) create mode 100644 docs/images/snippets/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.ascii create mode 100644 docs/images/snippets/abc/50543216f39c1b10af7cf4823844dd31.ascii create mode 100644 docs/images/snippets/abc/6a65a8327c06bc6f14cc4e0751d8e49e.ascii create mode 100644 docs/images/snippets/abc/b9854fbcb1096f736607d292dbe48371.ascii create mode 100644 docs/images/snippets/abc/bb8674f5f36b054b7734e34b91ed924f.ascii create mode 100644 docs/images/snippets/abc/c018aab3952ea9193848564aab12b241.ascii create mode 100644 docs/images/snippets/abc/c10cf18edeffed67dc94d250310db475.ascii create mode 100644 docs/images/snippets/abc/c14d8ce6eccca2c8063af40e5ac0bfd4.ascii create mode 100644 docs/images/snippets/abc/eccc1bdb9423bbfe2d42418fc8a7dd24.ascii create mode 100644 docs/images/snippets/abc/f78ce50f725f208f25090abc7fd741b7.ascii create mode 100644 docs/images/snippets/aligning/00480d8ea1d0b86eb66939bced85e14b.ascii create mode 100644 docs/images/snippets/aligning/6acf1a1e496f47c11e079a1d13f0a368.ascii create mode 100644 docs/images/snippets/aligning/a75137c250be63877a30f4bda8d801f8.ascii create mode 100644 docs/images/snippets/aligning/f6767b16ff8e04646f45fb9a1f3e4024.ascii create mode 100644 docs/images/snippets/arclength/046bbb52e8c8ed617fdf3a4fd18d62e1.ascii create mode 100644 docs/images/snippets/arclength/0748ad25185548150b6c1c4c7039207e.ascii create mode 100644 docs/images/snippets/arclength/2f80643c66d8f1448b13537a7b24eb45.ascii create mode 100644 docs/images/snippets/arclength/59ebc3a7c3547a50998d1ea3664fb688.ascii create mode 100644 docs/images/snippets/arclength/a91fbfb7abc38ff712ef660d85679f2e.ascii create mode 100644 docs/images/snippets/arclength/f251e86158649c0e57f7a772ebff83b4.ascii create mode 100644 docs/images/snippets/bsplines/20e910bbea2e6eff511cb13cef18ef3b.ascii create mode 100644 docs/images/snippets/bsplines/89f8e37237d066fa70ccf6d37b3a4922.ascii create mode 100644 docs/images/snippets/bsplines/a88566be442b67fb71f727de6bdb66df.ascii create mode 100644 docs/images/snippets/bsplines/c7af721e5e201fc3742bce67ff6cd560.ascii create mode 100644 docs/images/snippets/bsplines/cbdf5a61de10eeb6f23be077cf047ab5.ascii create mode 100644 docs/images/snippets/bsplines/ee203de6e554936588eb93adead0a3e5.ascii create mode 100644 docs/images/snippets/bsplines/f0bf7d0f1931060cd801ff707f482c16.ascii create mode 100644 docs/images/snippets/canonical/2b6478075f2f9f5e5973e01b3b3a0c8b.ascii create mode 100644 docs/images/snippets/canonical/464b4ec0b67f248459792752be86d46d.ascii create mode 100644 docs/images/snippets/canonical/5f174bc5019245f467ca63ae84b90a4b.ascii create mode 100644 docs/images/snippets/canonical/674d251590411398d06fb99cba7920f7.ascii create mode 100644 docs/images/snippets/canonical/6959a552f2c90a2bcaa787c23e19f488.ascii create mode 100644 docs/images/snippets/canonical/7ed8b53100737cbf7d87aa6267395d2b.ascii create mode 100644 docs/images/snippets/canonical/88e3fae7aeef6d7614290587422542c9.ascii create mode 100644 docs/images/snippets/canonical/8e39a9e0c7469b4b45a260dd23bd4c6a.ascii create mode 100644 docs/images/snippets/canonical/9420fd9d7a8de30714e23b8f31b3aa6d.ascii create mode 100644 docs/images/snippets/canonical/ccbfd22cbccf633d182f7f451dee5164.ascii create mode 100644 docs/images/snippets/canonical/e61fd49e554a0ffc7d64893c75cd376d.ascii create mode 100644 docs/images/snippets/canonical/f855cbf1d73e4bb7bccbbd4721d95f41.ascii create mode 100644 docs/images/snippets/catmullconv/00357d2a2168fe313cd0b38d95a1a681.ascii create mode 100644 docs/images/snippets/catmullconv/157b287d6b74109d8c8b634990ea6549.ascii create mode 100644 docs/images/snippets/catmullconv/1cef6bbf7b3d10e8c0aaecfac816cc86.ascii create mode 100644 docs/images/snippets/catmullconv/1f9fc156aeed9eb092573cd7446593d9.ascii create mode 100644 docs/images/snippets/catmullconv/211dadbb9d0f6b2e381f18ea3c4d12fb.ascii create mode 100644 docs/images/snippets/catmullconv/4c8684109149b0dc79f5583a5912fcd9.ascii create mode 100644 docs/images/snippets/catmullconv/4e0da16710a7339f04dd844c7705423e.ascii create mode 100644 docs/images/snippets/catmullconv/53f216327c0bbcf02b2a331fbf44d389.ascii create mode 100644 docs/images/snippets/catmullconv/574bed6665be06b309b8da722c616a41.ascii create mode 100644 docs/images/snippets/catmullconv/65e589eafae8ff2f39392d8143d2845c.ascii create mode 100644 docs/images/snippets/catmullconv/7bab9dd3da654b05fa065076894e2d82.ascii create mode 100644 docs/images/snippets/catmullconv/8a2a00812363fe1a6cfa7f81b48d31d1.ascii create mode 100644 docs/images/snippets/catmullconv/8d3a5ca7188f53b914229133b3dbe5fe.ascii create mode 100644 docs/images/snippets/catmullconv/8de53f207d68b25854a5f0b924ac6010.ascii create mode 100644 docs/images/snippets/catmullconv/917b176a45959b026c56f81999505dc7.ascii create mode 100644 docs/images/snippets/catmullconv/9593c057c84ebf9beb70fd57a11c7e12.ascii create mode 100644 docs/images/snippets/catmullconv/a55773fdcdfd99947acc4f86ad2d4a3d.ascii create mode 100644 docs/images/snippets/catmullconv/a8158b35ec221cccff51a53cdc7f440b.ascii create mode 100644 docs/images/snippets/catmullconv/b59ff8d654e65df4c874901983208893.ascii create mode 100644 docs/images/snippets/catmullconv/b94a4dafc12ba7e4fbf3aff924f55464.ascii create mode 100644 docs/images/snippets/catmullconv/c0e30b49fbfce6f6b3c81eaa6ca5154f.ascii create mode 100644 docs/images/snippets/catmullconv/c1f8861583b4176a9b607aa6a05f9356.ascii create mode 100644 docs/images/snippets/catmullconv/d09e7466c267614c89ead28d6a900ba1.ascii create mode 100644 docs/images/snippets/catmullconv/defc6fa4b51fa3c1945d15449f0f392d.ascii create mode 100644 docs/images/snippets/catmullconv/fe2e6fd487df224b2f55a601898ce333.ascii create mode 100644 docs/images/snippets/circles/06369b00338310df0a810c592485aa0a.ascii create mode 100644 docs/images/snippets/circles/1829e42ea956ee4df0e45d9ac5334ef7.ascii create mode 100644 docs/images/snippets/circles/5a23f3bc298c85540c6dd18e304d9224.ascii create mode 100644 docs/images/snippets/circles/7ab3da0922477af4cc09f5852100976b.ascii create mode 100644 docs/images/snippets/circles/8237af1396bb567d70c8b5e4dd7f8115.ascii create mode 100644 docs/images/snippets/circles/8b4e1d0a62380ed011f27c645ed13b28.ascii create mode 100644 docs/images/snippets/circles/942c90bc8311e49d94059b3127fc78d5.ascii create mode 100644 docs/images/snippets/circles/986ae9104e0bc52e95689ae7ae4504db.ascii create mode 100644 docs/images/snippets/circles/a04bd1558a76e60b8ca6e1fe4fa38c00.ascii create mode 100644 docs/images/snippets/circles/d4bfb47b623c968e3231566c9705c6c4.ascii create mode 100644 docs/images/snippets/circles/f9d15462df31186feef8c3d53c0f6163.ascii create mode 100644 docs/images/snippets/circles_cubic/046e0bec7cc3d8a502b2f76b4722be2d.ascii create mode 100644 docs/images/snippets/circles_cubic/0b4c1e8f1f7a9c1292787f127ddb1624.ascii create mode 100644 docs/images/snippets/circles_cubic/2ba4e0e2dbbdf3ea7dbd9cff3e049d0d.ascii create mode 100644 docs/images/snippets/circles_cubic/2d9df7ddd2aa223a951016b93d9620c2.ascii create mode 100644 docs/images/snippets/circles_cubic/329dc34299d2fdb3c5f17828e3a23da0.ascii create mode 100644 docs/images/snippets/circles_cubic/38b58b3c759b9bf340a3cf3de8bc599e.ascii create mode 100644 docs/images/snippets/circles_cubic/459c037fb92685566d624f81a298e9c8.ascii create mode 100644 docs/images/snippets/circles_cubic/6a14e5a71dd9e0cefe158640eabb8696.ascii create mode 100644 docs/images/snippets/circles_cubic/750e2c874fb58237608ebade1589fccc.ascii create mode 100644 docs/images/snippets/circles_cubic/8b4e1d0a62380ed011f27c645ed13b28.ascii create mode 100644 docs/images/snippets/circles_cubic/bc884416145a846cebddc8c5d13f147f.ascii create mode 100644 docs/images/snippets/circles_cubic/d28eb43a1b34befb7659dcdfb3a9e718.ascii create mode 100644 docs/images/snippets/circles_cubic/eeff3b36af960053cb4eb692abe36cd8.ascii create mode 100644 docs/images/snippets/circles_cubic/fa5d308b0b50400fbae1411f390bc7ce.ascii create mode 100644 docs/images/snippets/control/20b0be6397fbd726298de6ec70a8544b.ascii create mode 100644 docs/images/snippets/control/9df7dc66b51db8e3046e1f359874c38e.ascii create mode 100644 docs/images/snippets/control/b58fb122c5c8159938182c185f287142.ascii create mode 100644 docs/images/snippets/curvature/060acd6ff0a050fe4d98a7802a2b3a3f.ascii create mode 100644 docs/images/snippets/curvature/561ab3a938d655550de0abf458ac2494.ascii create mode 100644 docs/images/snippets/curvature/afd8cb8b0fe291ff703752c1c9cc33d4.ascii create mode 100644 docs/images/snippets/curvefitting/06605e008956609e8844ef95697c9096.ascii create mode 100644 docs/images/snippets/curvefitting/2f82371abb7835f9b9d440dc5dd151a8.ascii create mode 100644 docs/images/snippets/curvefitting/31d659cbc72bf304abf4c9a75b6b81de.ascii create mode 100644 docs/images/snippets/curvefitting/38bb81bdd3eaa72c2336514187aa374b.ascii create mode 100644 docs/images/snippets/curvefitting/409d10c3005b0c93489d72a5dba692d7.ascii create mode 100644 docs/images/snippets/curvefitting/464dbfb5adb6233108053dfac6fa4fe5.ascii create mode 100644 docs/images/snippets/curvefitting/4dd55c228a26bb50da912a45e8721024.ascii create mode 100644 docs/images/snippets/curvefitting/505ab1ada6a187e9ba392d19739ac2c5.ascii create mode 100644 docs/images/snippets/curvefitting/6f734d319a1cfe0de76574a65abb07e1.ascii create mode 100644 docs/images/snippets/curvefitting/7b0199bb515d2754c03d8f796b29febf.ascii create mode 100644 docs/images/snippets/curvefitting/7c6b50cee5dc685515943a199d7a65fc.ascii create mode 100644 docs/images/snippets/curvefitting/8068231b915832938136d5833f74751d.ascii create mode 100644 docs/images/snippets/curvefitting/940455f4016ab1be6d46c6f176fd2f76.ascii create mode 100644 docs/images/snippets/curvefitting/9651a687e1522b00bcba063881230902.ascii create mode 100644 docs/images/snippets/curvefitting/989f2ad06ae308f71cef527a5594129a.ascii create mode 100644 docs/images/snippets/curvefitting/9dec10b81a61b456ca1550cd9b7ba513.ascii create mode 100644 docs/images/snippets/curvefitting/a6faaf6083c818431988fef49421cc47.ascii create mode 100644 docs/images/snippets/curvefitting/b017da988c9a778a4ce6a6f4ea4790d4.ascii create mode 100644 docs/images/snippets/curvefitting/ea24b0e42f0a89464bda275ac8f9bacf.ascii create mode 100644 docs/images/snippets/derivatives/12fa7f83f055ef2078cc9f04e1468663.ascii create mode 100644 docs/images/snippets/derivatives/18c6e782012234a2c7425204505c8888.ascii create mode 100644 docs/images/snippets/derivatives/2d733684f81b65a42c4cdb3f1e589c8b.ascii create mode 100644 docs/images/snippets/derivatives/2fc50617b6886534d1ab4638ed8a24ac.ascii create mode 100644 docs/images/snippets/derivatives/50616f9c922967c0c9c179af9b091947.ascii create mode 100644 docs/images/snippets/derivatives/64c06c61727d0912a67c0f287a395e47.ascii create mode 100644 docs/images/snippets/derivatives/67ca2710769505572e097ffb40de099f.ascii create mode 100644 docs/images/snippets/derivatives/6a3672344bb571eadb72669f60a93ff4.ascii create mode 100644 docs/images/snippets/derivatives/897cfd8648720dc21463a9358cc65ab4.ascii create mode 100644 docs/images/snippets/derivatives/a7c61e0e8b42010df6dab641c92ef13d.ascii create mode 100644 docs/images/snippets/derivatives/a992185a346518b5ca159484019b6917.ascii create mode 100644 docs/images/snippets/derivatives/b58fb122c5c8159938182c185f287142.ascii create mode 100644 docs/images/snippets/derivatives/c3ac18fe4ba0606a15bc111e52b17a9a.ascii create mode 100644 docs/images/snippets/derivatives/f29a9d52897d2060a0c8a37073ed04fc.ascii create mode 100644 docs/images/snippets/derivatives/f67d2d379ba6dfaa7f7686a7d1eae367.ascii create mode 100644 docs/images/snippets/explanation/0cc876c56200446c60114c1b0eeeb2cc.ascii create mode 100644 docs/images/snippets/explanation/2493468e73b73f43eba8f66f0c189d1a.ascii create mode 100644 docs/images/snippets/explanation/2c47081c2a9c20d2110f13daa482a3ab.ascii create mode 100644 docs/images/snippets/explanation/6914ba615733c387251682db7a3db045.ascii create mode 100644 docs/images/snippets/explanation/6aa5d4e20e83be1c95eaad792517dde9.ascii create mode 100644 docs/images/snippets/explanation/7acc94ec70f053fd10dab69d424b02a6.ascii create mode 100644 docs/images/snippets/explanation/855a34c7f72733be6529c3fb33fa1a23.ascii create mode 100644 docs/images/snippets/explanation/8986c536df8153b30197c3a5407d233a.ascii create mode 100644 docs/images/snippets/explanation/9229934d71b0b02921bc92594ef11a98.ascii create mode 100644 docs/images/snippets/explanation/a2891980850ddbb27d308ac112d69f74.ascii create mode 100644 docs/images/snippets/explanation/adc7729f7872d71f3fbb1a79741ce10f.ascii create mode 100644 docs/images/snippets/explanation/b5977078d36d847fb299cbe3e7e2c3ba.ascii create mode 100644 docs/images/snippets/explanation/f79dd2f2d992e22b8d057fdc641290b0.ascii create mode 100644 docs/images/snippets/extended/b0eb0b24e7fa29c545ab1479d2df0554.ascii create mode 100644 docs/images/snippets/extended/e2e71b397009b51af8a3ee848bc727b4.ascii create mode 100644 docs/images/snippets/extended/f56f59f3c0b057c8ec79a477e4e38bec.ascii create mode 100644 docs/images/snippets/extended/fd520a6e2c7f39e90496e5cf494cce2e.ascii create mode 100644 docs/images/snippets/extremities/1fab66c84e7df38a2edda147f939bd80.ascii create mode 100644 docs/images/snippets/extremities/2c398b492aadc90eb4e4853fc20b23e9.ascii create mode 100644 docs/images/snippets/extremities/53e67a29f134bd561aca550a2091a196.ascii create mode 100644 docs/images/snippets/extremities/55e16ef652d30face0f6586b675a6c7b.ascii create mode 100644 docs/images/snippets/extremities/a6acf08f43aa1f48c08a40e76bdd2a31.ascii create mode 100644 docs/images/snippets/extremities/c4858be225d004441b2aefedacda89a3.ascii create mode 100644 docs/images/snippets/extremities/d1c65d927825f20c3c358d1ff96ce881.ascii create mode 100644 docs/images/snippets/extremities/d31432533bd7940545d4a269eefbabf2.ascii create mode 100644 docs/images/snippets/inflections/2dbf3071d74e2ba37ab888aaa3c1a17c.ascii create mode 100644 docs/images/snippets/inflections/75fae2d0a94eae4addf074c294855fc7.ascii create mode 100644 docs/images/snippets/inflections/a283e01df17f3d763ec89621f2af6c5c.ascii create mode 100644 docs/images/snippets/inflections/be9e409d619ecd735b0fbc219bec6d07.ascii create mode 100644 docs/images/snippets/inflections/d7d564126099bc0740058a7cdd744772.ascii create mode 100644 docs/images/snippets/inflections/e50243eaa99b5acc08533dd2e9b71a74.ascii create mode 100644 docs/images/snippets/inflections/ed68dcfb203517ca080fe48914769fb0.ascii create mode 100644 docs/images/snippets/inflections/f9f2258e59b038659087a5e87ba2e0af.ascii create mode 100644 docs/images/snippets/matrix/1a64ed455c6dd2f8cacca5e5e12bdcc1.ascii create mode 100644 docs/images/snippets/matrix/1bae50fefa43210b3a6259d1984f6cbc.ascii create mode 100644 docs/images/snippets/matrix/67a5ea33d6c6558f7d954b18226f4956.ascii create mode 100644 docs/images/snippets/matrix/87cfac83cb8a4b0bee68ef006effc611.ascii create mode 100644 docs/images/snippets/matrix/8ecff6b8a37d60385d287ea2b26876db.ascii create mode 100644 docs/images/snippets/matrix/9a9a55f5b0323d9ea88f82fc6be58ad3.ascii create mode 100644 docs/images/snippets/matrix/b32cae2dfc47d5f36df0bc3defb7dfa8.ascii create mode 100644 docs/images/snippets/matrix/b9527f7d5a0f5d2d737eac118d69243e.ascii create mode 100644 docs/images/snippets/matrix/cdd88611833f3b178df91278359a4193.ascii create mode 100644 docs/images/snippets/matrix/ec118f296511c6e9ac8727be3703a7ce.ascii create mode 100644 docs/images/snippets/matrixsplit/11505e0215ef026f2e49383ebb4a1abb.ascii create mode 100644 docs/images/snippets/matrixsplit/17e308aa6d459b1d06d3160cc8e2e786.ascii create mode 100644 docs/images/snippets/matrixsplit/1bae50fefa43210b3a6259d1984f6cbc.ascii create mode 100644 docs/images/snippets/matrixsplit/3b5e41808b6c3bc66f3da2f40651410e.ascii create mode 100644 docs/images/snippets/matrixsplit/4764868f43815e471bb1ea95a81e1633.ascii create mode 100644 docs/images/snippets/matrixsplit/480ebd0234e2fe1adc94926e8ed4339c.ascii create mode 100644 docs/images/snippets/matrixsplit/4ce218bc968cbd98da0ca6ab66d415ed.ascii create mode 100644 docs/images/snippets/matrixsplit/55b45214ba90c96978cdc9cdfee24fef.ascii create mode 100644 docs/images/snippets/matrixsplit/598739d23cf8dbcdebe033e4c7f1d28a.ascii create mode 100644 docs/images/snippets/matrixsplit/5e008143622c66bb5e9cc4d5d6a8ea62.ascii create mode 100644 docs/images/snippets/matrixsplit/63d1337d275abf7b296d500b9b5821fd.ascii create mode 100644 docs/images/snippets/matrixsplit/6a22184e6ca869d28f4a252b64f23eff.ascii create mode 100644 docs/images/snippets/matrixsplit/7a1e792cd3fa6f3482459e154abf2e7d.ascii create mode 100644 docs/images/snippets/matrixsplit/9a4899b69e03cd4ad02c5eedffaa6a2f.ascii create mode 100644 docs/images/snippets/matrixsplit/a899891096d82b7fdb23a90e6106b6df.ascii create mode 100644 docs/images/snippets/matrixsplit/baedd4067516584d425b93331b7ce04f.ascii create mode 100644 docs/images/snippets/matrixsplit/c32007be095224e0d157a8f71c62c90e.ascii create mode 100644 docs/images/snippets/matrixsplit/c341532f693c2c1adfd298597bbfb5b5.ascii create mode 100644 docs/images/snippets/matrixsplit/d9d04b9b6c66788d18832a383d6f7ea0.ascii create mode 100644 docs/images/snippets/matrixsplit/dceed84990aaf6878bcc67ddbaa8d8d9.ascii create mode 100644 docs/images/snippets/matrixsplit/e079f44b56e07c8d7f83c17c8ebf1ecf.ascii create mode 100644 docs/images/snippets/matrixsplit/e2622175dadafecc015f15c79ddf3002.ascii create mode 100644 docs/images/snippets/matrixsplit/e58196b82b78f584779208cce88137f5.ascii create mode 100644 docs/images/snippets/matrixsplit/ebf8d72c6056476172deeb89726b75c8.ascii create mode 100644 docs/images/snippets/matrixsplit/f565e66677138927335535d009409c3d.ascii create mode 100644 docs/images/snippets/matrixsplit/f63067c2c3042c374a58dfa7f692309e.ascii create mode 100644 docs/images/snippets/matrixsplit/f690ff0502d9fd7d4697cc43d98afd5d.ascii create mode 100644 docs/images/snippets/molding/6f12fcc00f4106bbc920d7451398d3b2.ascii create mode 100644 docs/images/snippets/molding/70262c533569a7da06cc1b950e932d6f.ascii create mode 100644 docs/images/snippets/offsetting/3c80407cfd0bd8c8ebea239272aeabe5.ascii create mode 100644 docs/images/snippets/offsetting/57e62f3f2f7526b2cf7c1b276c17e472.ascii create mode 100644 docs/images/snippets/offsetting/af4b584bb280cc941603255f62c9cc1a.ascii create mode 100644 docs/images/snippets/offsetting/cf8e602eb0595cf4d9b851c6bda741af.ascii create mode 100644 docs/images/snippets/offsetting/de8cdb128273beff2d98534b9f090b85.ascii create mode 100644 docs/images/snippets/pointcurves/4fe687c8a65265a2a755ba5841d0e31d.ascii create mode 100644 docs/images/snippets/pointcurves/8ffdd4a58cbd0fc24caef781f23a7950.ascii create mode 100644 docs/images/snippets/pointcurves/a5cd63b54be6b554290c38787cfbbabd.ascii create mode 100644 docs/images/snippets/pointcurves/f8182445c1cd7ae9f368b88fa7090e53.ascii create mode 100644 docs/images/snippets/pointvectors/1df6c055ae8e41a46bfdebc55a4f17c0.ascii create mode 100644 docs/images/snippets/pointvectors/58b19accb8a68c665ff5cbed610eea4e.ascii create mode 100644 docs/images/snippets/pointvectors/8b15a314beca97071b0ccb22c969355d.ascii create mode 100644 docs/images/snippets/pointvectors/b60cdba673c2c9fc84c800f07fd18145.ascii create mode 100644 docs/images/snippets/pointvectors/f02e359a5e47667919738fff69d2625b.ascii create mode 100644 docs/images/snippets/polybezier/a37252ff55837b918d9d64078ae92ae7.ascii create mode 100644 docs/images/snippets/polybezier/ec93d3c42f0ae52a05d0aff9739675e5.ascii create mode 100644 docs/images/snippets/reordering/056e25c397c524d80f378ce3823c7e78.ascii create mode 100644 docs/images/snippets/reordering/0f5698b31598b2390e966fc5e43ab53e.ascii create mode 100644 docs/images/snippets/reordering/1f5b60d190a1c7099b3411e4cc477291.ascii create mode 100644 docs/images/snippets/reordering/46e64dc07502e14217ec83d755f736ee.ascii create mode 100644 docs/images/snippets/reordering/4ff41e183d60d5fd10a5d3d30dd63358.ascii create mode 100644 docs/images/snippets/reordering/56130afc4cb313e0e74cf670d34590f6.ascii create mode 100644 docs/images/snippets/reordering/8090b63b005bf3edb916b97bda317a0e.ascii create mode 100644 docs/images/snippets/reordering/ab7c087f7c070d43a42f3f03010a7427.ascii create mode 100644 docs/images/snippets/reordering/e9fc9c715bb55a702db68b2bb6da0a68.ascii create mode 100644 docs/images/snippets/reordering/ff224ded6bbbc94b43130f5f8eeb5d29.ascii create mode 100644 docs/images/snippets/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.ascii create mode 100644 docs/images/snippets/weightcontrol/85d526fb17f9e859dcd7d40d22192e37.ascii create mode 100644 docs/images/snippets/whatis/06bbc5c11ad3fd88ff93eb2c06177b66.ascii create mode 100644 docs/images/snippets/whatis/c3f06301f5ce610df1217bc633257297.ascii create mode 100644 docs/images/snippets/yforx/316e7fae61e10014000d770209779ab6.ascii create mode 100644 docs/images/snippets/yforx/4d23ee228c5b1cbc40e380496c2184d1.ascii create mode 100644 docs/images/snippets/yforx/699459d89ca6622c90c1e42e4aa03f32.ascii create mode 100644 src/tex2utf/README.md create mode 100644 src/tex2utf/tex2utf.pl create mode 100644 test.js diff --git a/docs/chapters/arclength/content.en-GB.md b/docs/chapters/arclength/content.en-GB.md index 8ca6dca4..37a67ee9 100644 --- a/docs/chapters/arclength/content.en-GB.md +++ b/docs/chapters/arclength/content.en-GB.md @@ -24,12 +24,12 @@ So we turn to numerical approaches again. The method we'll look at here is the [ \int_{-1}^{1}f(t) dt \simeq \left [ - \underset{strip\ 1}{ \underbrace{ C_1 \cdot f\left(t_1\right) }} - \ +\ ... - \ +\ \underset{strip\ n}{ \underbrace{ C_n \cdot f\left(t_n\right) }} + \underset{strip~1}{ \underbrace{ C_1 \cdot f\left(t_1\right) }} + ~+~... + ~+~\underset{strip~n}{ \underbrace{ C_n \cdot f\left(t_n\right) }} \right ] = - \underset{strips\ 1\ through\ n}{ + \underset{strips~1~through~n}{ \underbrace{ \sum_{i=1}^{n}{ C_i \cdot f\left(t_i\right) diff --git a/docs/chapters/bsplines/content.en-GB.md b/docs/chapters/bsplines/content.en-GB.md index c808e0ee..26c3ed73 100644 --- a/docs/chapters/bsplines/content.en-GB.md +++ b/docs/chapters/bsplines/content.en-GB.md @@ -76,7 +76,7 @@ That looks complicated, but it's not. Computing alpha is just a fraction involvi Of course, the recursion does need a stop condition: \[ - d^k_0(t) = 0, \ d^0_i(t) = N_{i,1}(t) = + d^k_0(t) = 0, ~d^0_i(t) = N_{i,1}(t) = \left\{\begin{matrix} 1& \text{if } t \in [knot_i,knot_{i+1}) \\ 0& \text{otherwise} @@ -90,39 +90,39 @@ Thanks to Cox and de Boor, we can compute points on a B-Spline pretty easily usi \[ d^3_3 = \left \{ \begin{aligned} - \alpha^3_3 \times d^2_3, & \ \textit{ with } d^2_3 = \left \{ + \alpha^3_3 \times d^2_3, & ~\textit{ with } d^2_3 = \left \{ \begin{aligned} - \alpha^2_3 \times d^1_3, & \ \textit{ with } d^1_3 = + \alpha^2_3 \times d^1_3, & ~\textit{ with } d^1_3 = \left \{ \begin{aligned} - \alpha^1_3 \times d^0_3, & \ \textit{ with } d^0_3 \textit{ either 0 or 1} \\ + \alpha^1_3 \times d^0_3, & ~\textit{ with } d^0_3 \textit{ either 0 or 1} \\ + & \\ - \left ( 1 - \alpha^1_3 \right ) \times d^0_2, & \ \textit{ with } d^0_2 \textit{ either 0 or 1} \\ + \left ( 1 - \alpha^1_3 \right ) \times d^0_2, & ~\textit{ with } d^0_2 \textit{ either 0 or 1} \\ \end{aligned} \right . \\ + & \\ - \left ( 1 - \alpha^2_3 \right ) \times d^1_2, & \ \textit{ with } d^1_2 = + \left ( 1 - \alpha^2_3 \right ) \times d^1_2, & ~\textit{ with } d^1_2 = \left \{ \begin{aligned} \alpha^1_2 \times d^0_2 & \\ + & \\ - \left ( 1 - \alpha^1_2 \right ) \times d^0_1, & \ \textit{ with } d^0_1 \textit{ either 0 or 1} \\ + \left ( 1 - \alpha^1_2 \right ) \times d^0_1, & ~\textit{ with } d^0_1 \textit{ either 0 or 1} \\ \end{aligned} \right . \\ \end{aligned} \right . \\ + & \\ - \left ( 1 - \alpha^3_3 \right ) \times d^2_2, & \ \textit{ with } d^2_2 = \left \{ + \left ( 1 - \alpha^3_3 \right ) \times d^2_2, & ~\textit{ with } d^2_2 = \left \{ \begin{aligned} \alpha^2_2 \times d^1_2 & \\ & \\ + & \\ - \left ( 1 - \alpha^2_2 \right ) \times d^1_1, & \ \textit{ with } d^1_1 = + \left ( 1 - \alpha^2_2 \right ) \times d^1_1, & ~\textit{ with } d^1_1 = \left \{ \begin{aligned} \alpha^1_1 \times d^0_1 \\ + & \\ - \left ( 1 - \alpha^1_1 \right ) \times d^0_0, & \ \textit{ with } d^0_0 \textit{ either 0 or 1} \\ + \left ( 1 - \alpha^1_1 \right ) \times d^0_0, & ~\textit{ with } d^0_0 \textit{ either 0 or 1} \\ \end{aligned} \right . \\ \end{aligned} diff --git a/docs/chapters/circles/content.en-GB.md b/docs/chapters/circles/content.en-GB.md index 3ddfd5d5..6fae14f0 100644 --- a/docs/chapters/circles/content.en-GB.md +++ b/docs/chapters/circles/content.en-GB.md @@ -19,13 +19,13 @@ As you can see, things go horribly wrong quite quickly; even trying to approxima We start out with our start and end point, and for convenience we will place them on a unit circle (a circle around 0,0 with radius 1), at some angle *φ*: \[ - S = \begin{pmatrix} 1 \\ 0 \end{pmatrix} \ , \ \ E = \begin{pmatrix} cos(φ) \\ sin(φ) \end{pmatrix} + S = \begin{pmatrix} 1 \\ 0 \end{pmatrix} ~, ~\ E = \begin{pmatrix} cos(φ) \\ sin(φ) \end{pmatrix} \] What we want to find is the intersection of the tangents, so we want a point C such that: \[ - C = S + a \cdot \begin{pmatrix} 0 \\ 1 \end{pmatrix} \ , \ \ C = E + b \cdot \begin{pmatrix} -sin(φ) \\ cos(φ) \end{pmatrix} + C = S + a \cdot \begin{pmatrix} 0 \\ 1 \end{pmatrix} ~, ~\ C = E + b \cdot \begin{pmatrix} -sin(φ) \\ cos(φ) \end{pmatrix} \] i.e. we want a point that lies on the vertical line through S (at some distance *a* from S) and also lies on the tangent line through E (at some distance *b* from E). Solving this gives us: @@ -41,8 +41,8 @@ First we solve for *b*: \[ \begin{array}{l} - 1 = cos(φ) + b \cdot -sin(φ) \ → \ - 1 - cos(φ) = -b \cdot sin(φ) \ → \ + 1 = cos(φ) + b \cdot -sin(φ) ~→ \ + 1 - cos(φ) = -b \cdot sin(φ) ~→ \ -1 + cos(φ) = b \cdot sin(φ) \end{array} \] @@ -68,7 +68,7 @@ which we can then substitute in the expression for *a*: A quick check shows that plugging these values for *a* and *b* into the expressions for Cx and Cy give the same x/y coordinates for both "*a* away from A" and "*b* away from B", so let's continue: now that we know the coordinate values for C, we know where our on-curve point T for *t=0.5* (or angle φ/2) is, because we can just evaluate the Bézier polynomial, and we know where the circle arc's actual point P is for angle φ/2: \[ - P_x = cos(\frac{φ}{2}) \ , \ \ P_y = sin(\frac{φ}{2}) + P_x = cos(\frac{φ}{2}) ~, ~\ P_y = sin(\frac{φ}{2}) \] We compute T, observing that if *t=0.5*, the polynomial values (1-t)², 2(1-t)t, and t² are 0.25, 0.5, and 0.25 respectively: @@ -93,10 +93,10 @@ And the distance between these two is the standard Euclidean distance: \[ \begin{aligned} - d_x(φ) &= T_x - P_x = \frac{1}{4}(3 + cos(φ)) - cos(\frac{φ}{2}) = 2sin^4\left(\frac{φ}{4}\right) \ , \\ - d_y(φ) &= T_y - P_y = \frac{1}{4}\left(2tan\left(\frac{φ}{2}\right) + sin(φ)\right) - sin(\frac{φ}{2}) \ , \\ + d_x(φ) &= T_x - P_x = \frac{1}{4}(3 + cos(φ)) - cos(\frac{φ}{2}) = 2sin^4\left(\frac{φ}{4}\right) ~, \\ + d_y(φ) &= T_y - P_y = \frac{1}{4}\left(2tan\left(\frac{φ}{2}\right) + sin(φ)\right) - sin(\frac{φ}{2}) ~, \\ &⇓\\ - d(φ) &= \sqrt{d^2_x + d^2_y} = \ ... \ = 2sin^4(\frac{φ}{4})\sqrt{\frac{1}{cos^2(\frac{φ}{2})}} + d(φ) &= \sqrt{d^2_x + d^2_y} = ~... ~ = 2sin^4(\frac{φ}{4})\sqrt{\frac{1}{cos^2(\frac{φ}{2})}} \end{aligned} \] diff --git a/docs/chapters/circles_cubic/content.en-GB.md b/docs/chapters/circles_cubic/content.en-GB.md index de372d2f..e3f18b0f 100644 --- a/docs/chapters/circles_cubic/content.en-GB.md +++ b/docs/chapters/circles_cubic/content.en-GB.md @@ -39,7 +39,7 @@ In fact, the precision of a cubic curve at a quarter circle is considered "good So with the error analysis out of the way, how do we actually compute the coordinates needed to get that "true fit" cubic curve? The first observation is that we already know the start and end points, because they're the same as for the quadratic attempt: -\[ S = \begin{pmatrix} 1 \\ 0 \end{pmatrix} \ , \ \ E = \begin{pmatrix} cos(φ) \\ sin(φ) \end{pmatrix} \] +\[ S = \begin{pmatrix} 1 \\ 0 \end{pmatrix} ~, ~\ E = \begin{pmatrix} cos(φ) \\ sin(φ) \end{pmatrix} \] But we now need to find two control points, rather than one. If we want the derivatives at the start and end point to match the circle, then the first control point can only lie somewhere on the vertical line through S, and the second control point can only lie somewhere on the line tangent to point E, which means: @@ -74,17 +74,17 @@ The distance from our guessed point to the start point is exactly the same as th So that just leaves us to find the distance from t=0.5 to the baseline for an arbitrary angle φ, which is the distance from the centre of the circle to our t=0.5 point, minus the distance from the centre to the line that runs from start point to end point. The first is the same as the point P we found for the quadratic curve: \[ - P_x = cos(\frac{φ}{2}) \ , \ \ P_y = sin(\frac{φ}{2}) + P_x = cos(\frac{φ}{2}) ~, ~\ P_y = sin(\frac{φ}{2}) \] And the distance from the origin to the line start/end is another application of angles, since the triangle {origin,start,C} has known angles, and two known sides. We can find the length of the line {origin,C}, which lets us trivially compute the coordinate for C: \[ \begin{array}{l} - l = cos(\frac{φ}{2}) \ , \\ + l = cos(\frac{φ}{2}) ~, \\ \left\{\begin{array}{l} - C_x = l \cdot cos\left(\frac{φ}{2}\right) = cos^2\left(\frac{φ}{2}\right)\ , \\ - C_y = l \cdot sin\left(\frac{φ}{2}\right) = cos(\frac{φ}{2}) \cdot sin\left(\frac{φ}{2}\right)\ , \\ + C_x = l \cdot cos\left(\frac{φ}{2}\right) = cos^2\left(\frac{φ}{2}\right)~, \\ + C_y = l \cdot sin\left(\frac{φ}{2}\right) = cos(\frac{φ}{2}) \cdot sin\left(\frac{φ}{2}\right)~, \\ \end{array}\right. \end{array} \] @@ -121,9 +121,9 @@ And after this tedious detour to find the coordinate for C1, we can f \[ \begin{array}{l} - E'_x = -sin(φ) \ ,\\ - E'_y = cos(φ) \ , \\ - ||E'|| = \sqrt{ (-sin(φ))^2 + cos^2(φ)} = 1 \ , \\ + E'_x = -sin(φ) ~,\\ + E'_y = cos(φ) ~, \\ + ||E'|| = \sqrt{ (-sin(φ))^2 + cos^2(φ)} = 1 ~, \\ \\ \left\{\begin{array}{l} C_2x = E_x - C_{1y} \cdot \frac{E_x'}{||E'||} @@ -146,7 +146,7 @@ So, to recap, given an angle φ, the new control coordinates are: C_1 = \left [ \begin{matrix} 1 \\ f - \end{matrix} \right ],\ with\ f = \frac{4}{3} tan \left( \frac{φ}{4} \right) + \end{matrix} \right ],~with~f = \frac{4}{3} tan \left( \frac{φ}{4} \right) \] and @@ -155,16 +155,16 @@ and C_2 = \left [ \begin{matrix} cos(φ) + f \cdot sin(φ) \\ sin(φ) - f \cdot cos(φ) - \end{matrix} \right ],\ with\ f = \frac{4}{3} tan \left( \frac{φ}{4} \right) + \end{matrix} \right ],~with~f = \frac{4}{3} tan \left( \frac{φ}{4} \right) \] And, because the "quarter curve" special case comes up so incredibly often, let's look at what these new control points mean for the curve coordinates of a quarter curve, by simply filling in φ = π/2: \[ \begin{array}{l} - S = (1, 0) \ , \ - C_1 = \left ( 1, 4 \frac{\sqrt{2}-1}{3} \right ) \ , \ - C_2 = \left ( 4 \frac{\sqrt{2}-1}{3} , 1 \right ) \ , \ + S = (1, 0) ~, \ + C_1 = \left ( 1, 4 \frac{\sqrt{2}-1}{3} \right ) ~, \ + C_2 = \left ( 4 \frac{\sqrt{2}-1}{3} , 1 \right ) ~, \ E = (0, 1) \end{array} \] @@ -173,9 +173,9 @@ Which, in decimal values, rounded to six significant digits, is: \[ \begin{array}{l} - S = (1, 0) \ , \ - C_1 = (1, 0.55228) \ , \ - C_2 = (0.55228 , 1) \ , \ + S = (1, 0) ~, \ + C_1 = (1, 0.55228) ~, \ + C_2 = (0.55228 , 1) ~, \ E = (0, 1) \end{array} \] diff --git a/docs/chapters/control/content.en-GB.md b/docs/chapters/control/content.en-GB.md index 07bca9e7..88f23919 100644 --- a/docs/chapters/control/content.en-GB.md +++ b/docs/chapters/control/content.en-GB.md @@ -22,9 +22,9 @@ If we want to change the curve, we need to change the weights of each point, eff \[ Bézier(n,t) = \sum_{i=0}^{n} - \underset{binomial\ term}{\underbrace{\binom{n}{i}}} + \underset{binomial~term}{\underbrace{\binom{n}{i}}} \cdot\ - \underset{polynomial\ term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} + \underset{polynomial~term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} \cdot\ \underset{weight}{\underbrace{w_i}} \] diff --git a/docs/chapters/control/content.zh-CN.md b/docs/chapters/control/content.zh-CN.md index 9f00f5f2..b5d58dac 100644 --- a/docs/chapters/control/content.zh-CN.md +++ b/docs/chapters/control/content.zh-CN.md @@ -22,9 +22,9 @@ \[ Bézier(n,t) = \sum_{i=0}^{n} - \underset{binomial\ term}{\underbrace{\binom{n}{i}}} + \underset{binomial~term}{\underbrace{\binom{n}{i}}} \cdot\ - \underset{polynomial\ term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} + \underset{polynomial~term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} \cdot\ \underset{weight}{\underbrace{w_i}} \] diff --git a/docs/chapters/derivatives/content.en-GB.md b/docs/chapters/derivatives/content.en-GB.md index a9bf0c35..d51bb3ef 100644 --- a/docs/chapters/derivatives/content.en-GB.md +++ b/docs/chapters/derivatives/content.en-GB.md @@ -66,7 +66,7 @@ And that's the first part done: the two components inside the parentheses are ac ... = n \left ( \frac{x!}{y!(x-y)!} t^{y} (1-t)^{x-y} - \frac{x!}{k!(x-k)!} t^k (1-t)^{x-k} \right ) - \ ,\ with\ x=n-1,\ y=k-1 + ~,~with~x=n-1,~y=k-1 \\ ... = n \left ( B_{(n-1),(k-1)}(t) - B_{(n-1),k}(t) \right ) \end{array} @@ -98,7 +98,7 @@ Two of these terms fall way: the first term falls away because there is no -1a and b", progr \[ Bézier(n,t) = \sum_{i=0}^{n} - \underset{binomial\ term}{\underbrace{\binom{n}{i}}} + \underset{binomial~term}{\underbrace{\binom{n}{i}}} \cdot\ - \underset{polynomial\ term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} + \underset{polynomial~term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} \] And that's the full description for Bézier curves. Σ in this function indicates that this is a series of additions (using the variable listed below the Σ, starting at ...=<value> and ending at the value listed on top of the Σ). diff --git a/docs/chapters/explanation/content.zh-CN.md b/docs/chapters/explanation/content.zh-CN.md index 5a416feb..093d2c62 100644 --- a/docs/chapters/explanation/content.zh-CN.md +++ b/docs/chapters/explanation/content.zh-CN.md @@ -90,9 +90,9 @@ \[ Bézier(n,t) = \sum_{i=0}^{n} - \underset{binomial\ term}{\underbrace{\binom{n}{i}}} + \underset{binomial~term}{\underbrace{\binom{n}{i}}} \cdot\ - \underset{polynomial\ term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} + \underset{polynomial~term}{\underbrace{(1-t)^{n-i} \cdot t^{i}}} \] 这就是贝塞尔曲线完整的描述。在这个函数中的Σ表示了这是一系列的加法(用Σ下面的变量,从...=<值>开始,直到Σ上面的数字结束)。 diff --git a/docs/chapters/extremities/content.en-GB.md b/docs/chapters/extremities/content.en-GB.md index b76d6add..0a617ff2 100644 --- a/docs/chapters/extremities/content.en-GB.md +++ b/docs/chapters/extremities/content.en-GB.md @@ -33,7 +33,7 @@ Although with the [caveat](https://en.wikipedia.org/wiki/Caveat_emptor#Caveat_le The derivative of a cubic Bézier curve is a quadratic Bézier curve, and finding the roots for a quadratic polynomial means we can apply the [Quadratic formula](https://en.wikipedia.org/wiki/Quadratic_formula). If you've seen it before, you'll remember it, and if you haven't, it looks like this: \[ - Given\ f(t) = at^2 + bt + c,\ f(t)=0\ when\ t = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} + Given~f(t) = at^2 + bt + c,~f(t)=0~when~t = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a} \] So, if we can rewrite the Bézier component function as a plain polynomial, we're done: we just plug in the values into the quadratic formula, check if that square root is negative or not (if it is, there are no roots) and then just compute the two values that come out (because of that plus/minus sign we get two). Any value between 0 and 1 is a root that matters for Bézier curves, anything below or above that is irrelevant (because Bézier curves are only defined over the interval [0,1]). So, how do we convert? @@ -42,8 +42,8 @@ First we turn our cubic Bézier function into a quadratic one, by following the \[ \begin{array}{l} - B(t)\ uses\ \{ p_1,p_2,p_3,p_4 \} \\ - B'(t)\ uses\ \{ v_1,v_2,v_3 \},\ where\ v_1 = 3(p_2-p_1),\ v_2 = 3(p_3-p_2),\ v_3 = 3(p_4-p_3) + B(t)~uses~\{ p_1,p_2,p_3,p_4 \} \\ + B'(t)~uses~\{ v_1,v_2,v_3 \},~where~v_1 = 3(p_2-p_1),~v_2 = 3(p_3-p_2),~v_3 = 3(p_4-p_3) \end{array} \] diff --git a/docs/chapters/inflections/content.en-GB.md b/docs/chapters/inflections/content.en-GB.md index c3cc057b..d58c9314 100644 --- a/docs/chapters/inflections/content.en-GB.md +++ b/docs/chapters/inflections/content.en-GB.md @@ -29,8 +29,8 @@ Of course, before we do our aligned check, let's see what happens if we compute \[ \begin{aligned} & Bézier(t) = x_1(1-t)^3 + 3x_2(1-t)^2t + 3x_3(1-t)t^2 + x_4t^3 \\ - & Bézier^\prime(t) = a(1-t)^2 + 2b(1-t)t + ct^2\ \left\{ a=3(x_2-x_1),b=3(x_3-x_2),c=3(x_4-x_3) \right\} \\ - & Bézier^{\prime\prime}(t) = u(1-t) + vt\ \left\{ u=2(b-a),v=2(c-b) \right\}\ + & Bézier^\prime(t) = a(1-t)^2 + 2b(1-t)t + ct^2~ \left\{ a=3(x_2-x_1),b=3(x_3-x_2),c=3(x_4-x_3) \right\} \\ + & Bézier^{\prime\prime}(t) = u(1-t) + vt~\left\{ u=2(b-a),v=2(c-b) \right\}\ \end{aligned} \] @@ -75,7 +75,7 @@ That's a lot easier to work with: we see a fair number of terms that we can comp c = x_2 \cdot y_3 \\ d = x_4 \cdot y_3 \end{matrix}\right\} - \ C(t) = (-3a + 2b + 3c - d)t^2 + (3a - b - 3c)t + (c - a) + ~C(t) = (-3a + 2b + 3c - d)t^2 + (3a - b - 3c)t + (c - a) \] This is a plain quadratic curve, and we know how to solve *C(t) = 0*; we use the quadratic formula: @@ -86,7 +86,7 @@ This is a plain quadratic curve, and we know how to solve *C(t) = 0*; we use the y =& 3a - b - 3c \\ z =& c - a \end{matrix}\right\} - \ C(t) = 0 \ \Rightarrow\ t = \frac{-y \pm \sqrt{y^2 - 4 x z}}{2x} + ~C(t) = 0 ~\Rightarrow~t = \frac{-y \pm \sqrt{y^2 - 4 x z}}{2x} \] We can easily compute this value *if* the discriminator isn't a negative number (because we only want real roots, not complex roots), and *if* *x* is not zero, because divisions by zero are rather useless. diff --git a/docs/chapters/matrixsplit/content.en-GB.md b/docs/chapters/matrixsplit/content.en-GB.md index 90ee3e8d..8a26d45c 100644 --- a/docs/chapters/matrixsplit/content.en-GB.md +++ b/docs/chapters/matrixsplit/content.en-GB.md @@ -155,7 +155,7 @@ Deriving the two segments upon splitting a curve takes a few steps, and the high 1 & t & t^2 \end{bmatrix} \cdot - \underset{we\ turn\ this...}{\underbrace{\kern 2.25em Z \cdot M \kern 2.25em}} + \underset{we~turn~this...}{\underbrace{\kern 2.25em Z \cdot M \kern 2.25em}} \cdot \begin{bmatrix} P_1 \\ P_2 \\ P_3 @@ -168,7 +168,7 @@ Deriving the two segments upon splitting a curve takes a few steps, and the high 1 & t & t^2 \end{bmatrix} \cdot - \underset{...into\ this...}{\underbrace{ M \cdot M^{-1} \cdot Z \cdot M }} + \underset{...into~this...}{\underbrace{ M \cdot M^{-1} \cdot Z \cdot M }} \cdot \begin{bmatrix} P_1 \\ P_2 \\ P_3 @@ -182,7 +182,7 @@ Deriving the two segments upon splitting a curve takes a few steps, and the high \end{bmatrix} \cdot M - \underset{...to\ get\ this!}{\underbrace{ \kern 1.25em \cdot \kern 1.25em Q \kern 1.25em \cdot \kern 1.25em}} + \underset{...to~get~this!}{\underbrace{ \kern 1.25em \cdot \kern 1.25em Q \kern 1.25em \cdot \kern 1.25em}} \begin{bmatrix} P_1 \\ P_2 \\ P_3 \end{bmatrix} diff --git a/docs/chapters/pointvectors/content.en-GB.md b/docs/chapters/pointvectors/content.en-GB.md index c0be12fc..236eafb5 100644 --- a/docs/chapters/pointvectors/content.en-GB.md +++ b/docs/chapters/pointvectors/content.en-GB.md @@ -32,7 +32,7 @@ The tangent is very useful for moving along a line, but what if we want to move \begin{array}{l} normal_x(t) = \hat{x}(t) \cdot \cos{\frac{\pi}{2}} - \hat{y}(t) \cdot \sin{\frac{\pi}{2}} = - \hat{y}(t) \\ \\ - normal_y(t) = \underset{quarter\ circle\ rotation} {\underbrace{ \hat{x}(t) \cdot \sin{\frac{\pi}{2}} + \hat{y}(t) \cdot \cos{\frac{\pi}{2}} }} = \hat{x}(t) + normal_y(t) = \underset{quarter~circle~rotation} {\underbrace{ \hat{x}(t) \cdot \sin{\frac{\pi}{2}} + \hat{y}(t) \cdot \cos{\frac{\pi}{2}} }} = \hat{x}(t) \end{array} \] diff --git a/docs/chapters/reordering/content.en-GB.md b/docs/chapters/reordering/content.en-GB.md index f60e207d..cdb0e264 100644 --- a/docs/chapters/reordering/content.en-GB.md +++ b/docs/chapters/reordering/content.en-GB.md @@ -8,12 +8,12 @@ The general rule for raising an *nth* order curve to an *(n+1)th \[ Bézier(k,t) = \sum_{i=0}^{k} - \underset{binomial\ term}{\underbrace{\binom{k}{i}}} + \underset{binomial~term}{\underbrace{\binom{k}{i}}} \cdot\ - \underset{polynomial\ term}{\underbrace{(1-t)^{k-i} \cdot t^{i}}} - \ \cdot \ - \underset{new\ weights}{\underbrace{\left ( \frac{(k-i) \cdot w_i + i \cdot w_{i-1}}{k} \right )}} - \ ,\ with\ k = n+1\ and\ w_{i-1}=0\ when\ i = 0 + \underset{polynomial~term}{\underbrace{(1-t)^{k-i} \cdot t^{i}}} + ~\cdot \ + \underset{new~weights}{\underbrace{\left ( \frac{(k-i) \cdot w_i + i \cdot w_{i-1}}{k} \right )}} + ~,~with~k = n+1~and~w_{i-1}=0~when~i = 0 \] However, this rule also has as direct consequence that you **cannot** generally safely lower a curve from *nth* order to *(n-1)th* order, because the control points cannot be "pulled apart" cleanly. We can try to, but the resulting curve will not be identical to the original, and may in fact look completely different. diff --git a/docs/chapters/weightcontrol/content.en-GB.md b/docs/chapters/weightcontrol/content.en-GB.md index f7c41dd5..998a61af 100644 --- a/docs/chapters/weightcontrol/content.en-GB.md +++ b/docs/chapters/weightcontrol/content.en-GB.md @@ -11,7 +11,7 @@ Adding these ratio values to the regular Bézier curve function is fairly easy. The function for rational Bézier curves has two more terms: \[ - Rational\ Bézier(n,t) = \frac{ \sum_{i=0}^{n} \binom{n}{i} \cdot (1-t)^{n-i} \cdot t^{i} \cdot w_i \cdot BLUE[ratio_i] }{ BLUE[ \sum_{i=0}^{n} \binom{n}{i} \cdot (1-t)^{n-i} \cdot t^{i} \cdot ratio_i ] } + Rational~Bézier(n,t) = \frac{ \sum_{i=0}^{n} \binom{n}{i} \cdot (1-t)^{n-i} \cdot t^{i} \cdot w_i \cdot BLUE[ratio_i] }{ BLUE[ \sum_{i=0}^{n} \binom{n}{i} \cdot (1-t)^{n-i} \cdot t^{i} \cdot ratio_i ] } \] In this, the first new term represents an additional weight for each coordinate. For example, if our ratio values are [1, 0.5, 0.5, 1] then ratio0 = 1, ratio1 = 0.5, and so on, and is effectively identical as if we were just using different weight. So far, nothing too special. diff --git a/docs/chapters/whatis/content.en-GB.md b/docs/chapters/whatis/content.en-GB.md index 60f4b918..61ba77ef 100644 --- a/docs/chapters/whatis/content.en-GB.md +++ b/docs/chapters/whatis/content.en-GB.md @@ -9,12 +9,12 @@ If we know the distance between those two points, and we want a new point that i \[ Given \left ( \begin{aligned} - p_1 &= some\ point \\ - p_2 &= some\ other\ point \\ + p_1 &= some~point \\ + p_2 &= some~other~point \\ distance &= (p_2 - p_1) \\ ratio &= \frac{percentage}{100} \\ \end{aligned} -\right ),\ our\ new\ point = p_1 + distance \cdot ratio +\right ),~our~new~point = p_1 + distance \cdot ratio \] So let's look at that in action: the following graphic is interactive in that you can use your up and down arrow keys to increase or decrease the interpolation ratio, to see what happens. We start with three points, which gives us two lines. Linear interpolation over those lines gives us two points, between which we can again perform linear interpolation, yielding a single point. And that point —and all points we can form in this way for all ratios taken together— form our Bézier curve: diff --git a/docs/chapters/whatis/content.zh-CN.md b/docs/chapters/whatis/content.zh-CN.md index 8f49c56c..5f618bf8 100644 --- a/docs/chapters/whatis/content.zh-CN.md +++ b/docs/chapters/whatis/content.zh-CN.md @@ -9,12 +9,12 @@ \[ Given \left ( \begin{aligned} - p_1 &= some\ point \\ - p_2 &= some\ other\ point \\ + p_1 &= some~point \\ + p_2 &= some~other~point \\ distance &= (p_2 - p_1) \\ ratio &= \frac{percentage}{100} \\ \end{aligned} -\right ),\ our\ new\ point = p_1 + distance \cdot ratio +\right ),~our~new~point = p_1 + distance \cdot ratio \] 让我们来通过实际操作看一下:下面的图形都是可交互的,因此你可以通过上下键来增加或减少插值距离,来观察图形的变化。我们从三个点构成的两条线段开始。通过对各条线段进行线性插值得到两个点,对点之间的线段再进行线性插值,产生一个新的点。最终这些点——所有的点都可以通过选取不同的距离插值产生——构成了贝塞尔曲线 diff --git a/docs/images/chapters/aligning/00480d8ea1d0b86eb66939bced85e14b.svg b/docs/images/chapters/aligning/00480d8ea1d0b86eb66939bced85e14b.svg new file mode 100644 index 00000000..01665af8 --- /dev/null +++ b/docs/images/chapters/aligning/00480d8ea1d0b86eb66939bced85e14b.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/images/chapters/aligning/041c2f2d5c115e27f059595775732dfa.svg b/docs/images/chapters/aligning/041c2f2d5c115e27f059595775732dfa.svg deleted file mode 100644 index b69dd310..00000000 --- a/docs/images/chapters/aligning/041c2f2d5c115e27f059595775732dfa.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/images/chapters/aligning/17282cb081f862dec197e591718c5f41.svg b/docs/images/chapters/aligning/17282cb081f862dec197e591718c5f41.svg deleted file mode 100644 index 7470d0d6..00000000 --- a/docs/images/chapters/aligning/17282cb081f862dec197e591718c5f41.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/images/chapters/aligning/203a75eeab5295c3ace2725e12893672.svg b/docs/images/chapters/aligning/203a75eeab5295c3ace2725e12893672.svg deleted file mode 100644 index 58ddd04c..00000000 --- a/docs/images/chapters/aligning/203a75eeab5295c3ace2725e12893672.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/images/chapters/aligning/6acf1a1e496f47c11e079a1d13f0a368.svg b/docs/images/chapters/aligning/6acf1a1e496f47c11e079a1d13f0a368.svg new file mode 100644 index 00000000..444acf5d --- /dev/null +++ b/docs/images/chapters/aligning/6acf1a1e496f47c11e079a1d13f0a368.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/images/chapters/aligning/72ab12864982fd8d9ee757689be93f2c.svg b/docs/images/chapters/aligning/72ab12864982fd8d9ee757689be93f2c.svg deleted file mode 100644 index 8cdd1f86..00000000 --- a/docs/images/chapters/aligning/72ab12864982fd8d9ee757689be93f2c.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/images/chapters/aligning/a75137c250be63877a30f4bda8d801f8.svg b/docs/images/chapters/aligning/a75137c250be63877a30f4bda8d801f8.svg new file mode 100644 index 00000000..10c64d1b --- /dev/null +++ b/docs/images/chapters/aligning/a75137c250be63877a30f4bda8d801f8.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/images/chapters/aligning/f6767b16ff8e04646f45fb9a1f3e4024.svg b/docs/images/chapters/aligning/f6767b16ff8e04646f45fb9a1f3e4024.svg new file mode 100644 index 00000000..05faa6bc --- /dev/null +++ b/docs/images/chapters/aligning/f6767b16ff8e04646f45fb9a1f3e4024.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/images/chapters/arclength/56533f47e73ad9fea08fa9bb3f597d49.png b/docs/images/chapters/arclength/56533f47e73ad9fea08fa9bb3f597d49.png index adf3923b0666c82980b30543564830b4a54d1f00..4cc00cf30583321c5e1b05ac5cc05a87f03396f9 100644 GIT binary patch literal 11031 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 MDJ97=aidTF3%?UWfdBvi literal 11513 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 n3r3bgiB2=o|2K?t{Q+T{{`{P(Um7k0mZ}P~= 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 H@z?(a%b1Oz literal 12354 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 M5{lyGqDG(p2MTSq7ytkO diff --git a/docs/images/chapters/bsplines/f0e96cf0de35d55c20e131e904ef2cc5.svg b/docs/images/chapters/bsplines/20e910bbea2e6eff511cb13cef18ef3b.svg similarity index 100% rename from docs/images/chapters/bsplines/f0e96cf0de35d55c20e131e904ef2cc5.svg rename to docs/images/chapters/bsplines/20e910bbea2e6eff511cb13cef18ef3b.svg diff --git a/docs/images/chapters/bsplines/392b7cadd922c5e46fa89ab09716aa7e.svg b/docs/images/chapters/bsplines/a88566be442b67fb71f727de6bdb66df.svg similarity index 100% rename from docs/images/chapters/bsplines/392b7cadd922c5e46fa89ab09716aa7e.svg rename to docs/images/chapters/bsplines/a88566be442b67fb71f727de6bdb66df.svg diff --git a/docs/images/chapters/circles/a0fd085fa6191c9c5e026028074c6c51.svg b/docs/images/chapters/circles/1829e42ea956ee4df0e45d9ac5334ef7.svg similarity index 100% rename from docs/images/chapters/circles/a0fd085fa6191c9c5e026028074c6c51.svg rename to docs/images/chapters/circles/1829e42ea956ee4df0e45d9ac5334ef7.svg diff --git a/docs/images/chapters/circles/c6b179d2a85b51c1a422f769197947fa.svg b/docs/images/chapters/circles/7ab3da0922477af4cc09f5852100976b.svg similarity index 100% rename from docs/images/chapters/circles/c6b179d2a85b51c1a422f769197947fa.svg rename to docs/images/chapters/circles/7ab3da0922477af4cc09f5852100976b.svg diff --git a/docs/images/chapters/circles/e33aefe157f12d688fcecc8a81eee83a.svg b/docs/images/chapters/circles/8b4e1d0a62380ed011f27c645ed13b28.svg similarity index 100% rename from docs/images/chapters/circles/e33aefe157f12d688fcecc8a81eee83a.svg rename to docs/images/chapters/circles/8b4e1d0a62380ed011f27c645ed13b28.svg diff --git a/docs/images/chapters/circles/6b4eb46b5f772fafcf8cfe390da8402c.svg b/docs/images/chapters/circles/942c90bc8311e49d94059b3127fc78d5.svg similarity index 100% rename from docs/images/chapters/circles/6b4eb46b5f772fafcf8cfe390da8402c.svg rename to docs/images/chapters/circles/942c90bc8311e49d94059b3127fc78d5.svg diff --git a/docs/images/chapters/circles/ae08c8a734426e4c6dd0373f7ced2d41.svg b/docs/images/chapters/circles/d4bfb47b623c968e3231566c9705c6c4.svg similarity index 100% rename from docs/images/chapters/circles/ae08c8a734426e4c6dd0373f7ced2d41.svg rename to docs/images/chapters/circles/d4bfb47b623c968e3231566c9705c6c4.svg diff --git a/docs/images/chapters/circles_cubic/80f6807fcb4f81fdda5b77071a1a67b2.svg b/docs/images/chapters/circles_cubic/2d9df7ddd2aa223a951016b93d9620c2.svg similarity index 100% rename from docs/images/chapters/circles_cubic/80f6807fcb4f81fdda5b77071a1a67b2.svg rename to docs/images/chapters/circles_cubic/2d9df7ddd2aa223a951016b93d9620c2.svg diff --git a/docs/images/chapters/circles_cubic/909b5f634b8a5efa61742e2d4f94af5d.svg b/docs/images/chapters/circles_cubic/329dc34299d2fdb3c5f17828e3a23da0.svg similarity index 100% rename from docs/images/chapters/circles_cubic/909b5f634b8a5efa61742e2d4f94af5d.svg rename to docs/images/chapters/circles_cubic/329dc34299d2fdb3c5f17828e3a23da0.svg diff --git a/docs/images/chapters/circles_cubic/24675851ca7ce917a00a02084b456447.svg b/docs/images/chapters/circles_cubic/38b58b3c759b9bf340a3cf3de8bc599e.svg similarity index 100% rename from docs/images/chapters/circles_cubic/24675851ca7ce917a00a02084b456447.svg rename to docs/images/chapters/circles_cubic/38b58b3c759b9bf340a3cf3de8bc599e.svg diff --git a/docs/images/chapters/circles_cubic/aa4d4d4175699c2feb561cf04e107477.svg b/docs/images/chapters/circles_cubic/459c037fb92685566d624f81a298e9c8.svg similarity index 100% rename from docs/images/chapters/circles_cubic/aa4d4d4175699c2feb561cf04e107477.svg rename to docs/images/chapters/circles_cubic/459c037fb92685566d624f81a298e9c8.svg diff --git a/docs/images/chapters/circles_cubic/5ef95ecfcf09a88a58f9bcafa659ed90.svg b/docs/images/chapters/circles_cubic/6a14e5a71dd9e0cefe158640eabb8696.svg similarity index 100% rename from docs/images/chapters/circles_cubic/5ef95ecfcf09a88a58f9bcafa659ed90.svg rename to docs/images/chapters/circles_cubic/6a14e5a71dd9e0cefe158640eabb8696.svg diff --git a/docs/images/chapters/circles_cubic/e33aefe157f12d688fcecc8a81eee83a.svg b/docs/images/chapters/circles_cubic/8b4e1d0a62380ed011f27c645ed13b28.svg similarity index 100% rename from docs/images/chapters/circles_cubic/e33aefe157f12d688fcecc8a81eee83a.svg rename to docs/images/chapters/circles_cubic/8b4e1d0a62380ed011f27c645ed13b28.svg diff --git a/docs/images/chapters/circles_cubic/7a863b956c3d87df5289b36e29555001.svg b/docs/images/chapters/circles_cubic/bc884416145a846cebddc8c5d13f147f.svg similarity index 100% rename from docs/images/chapters/circles_cubic/7a863b956c3d87df5289b36e29555001.svg rename to docs/images/chapters/circles_cubic/bc884416145a846cebddc8c5d13f147f.svg diff --git a/docs/images/chapters/circles_cubic/fb21bf8b5cd13b3149885dd426bf79b4.svg b/docs/images/chapters/circles_cubic/eeff3b36af960053cb4eb692abe36cd8.svg similarity index 100% rename from docs/images/chapters/circles_cubic/fb21bf8b5cd13b3149885dd426bf79b4.svg rename to docs/images/chapters/circles_cubic/eeff3b36af960053cb4eb692abe36cd8.svg diff --git a/docs/images/chapters/control/1cb112753c51e98aa328484f12b4a4f1.svg b/docs/images/chapters/control/b58fb122c5c8159938182c185f287142.svg similarity index 100% rename from docs/images/chapters/control/1cb112753c51e98aa328484f12b4a4f1.svg rename to docs/images/chapters/control/b58fb122c5c8159938182c185f287142.svg diff --git a/docs/images/chapters/derivatives/7040219e3888bf6cf2f6750259da327f.svg b/docs/images/chapters/derivatives/2d733684f81b65a42c4cdb3f1e589c8b.svg similarity index 100% rename from docs/images/chapters/derivatives/7040219e3888bf6cf2f6750259da327f.svg rename to docs/images/chapters/derivatives/2d733684f81b65a42c4cdb3f1e589c8b.svg diff --git a/docs/images/chapters/derivatives/43eea1ddd3646dc387511e16d2508db2.svg b/docs/images/chapters/derivatives/2fc50617b6886534d1ab4638ed8a24ac.svg similarity index 100% rename from docs/images/chapters/derivatives/43eea1ddd3646dc387511e16d2508db2.svg rename to docs/images/chapters/derivatives/2fc50617b6886534d1ab4638ed8a24ac.svg diff --git a/docs/images/chapters/derivatives/d51bf2f64f109da5a4138b24321597d1.svg b/docs/images/chapters/derivatives/50616f9c922967c0c9c179af9b091947.svg similarity index 100% rename from docs/images/chapters/derivatives/d51bf2f64f109da5a4138b24321597d1.svg rename to docs/images/chapters/derivatives/50616f9c922967c0c9c179af9b091947.svg diff --git a/docs/images/chapters/derivatives/f81cd6166665abcc4aa433f31c20eac4.svg b/docs/images/chapters/derivatives/6a3672344bb571eadb72669f60a93ff4.svg similarity index 100% rename from docs/images/chapters/derivatives/f81cd6166665abcc4aa433f31c20eac4.svg rename to docs/images/chapters/derivatives/6a3672344bb571eadb72669f60a93ff4.svg diff --git a/docs/images/chapters/derivatives/977ff6fb1c7bff664e844f33ff23f420.svg b/docs/images/chapters/derivatives/a7c61e0e8b42010df6dab641c92ef13d.svg similarity index 100% rename from docs/images/chapters/derivatives/977ff6fb1c7bff664e844f33ff23f420.svg rename to docs/images/chapters/derivatives/a7c61e0e8b42010df6dab641c92ef13d.svg diff --git a/docs/images/chapters/derivatives/1cb112753c51e98aa328484f12b4a4f1.svg b/docs/images/chapters/derivatives/b58fb122c5c8159938182c185f287142.svg similarity index 100% rename from docs/images/chapters/derivatives/1cb112753c51e98aa328484f12b4a4f1.svg rename to docs/images/chapters/derivatives/b58fb122c5c8159938182c185f287142.svg diff --git a/docs/images/chapters/derivatives/0c8a8fb27762b2f16a154937de35a764.svg b/docs/images/chapters/derivatives/f29a9d52897d2060a0c8a37073ed04fc.svg similarity index 100% rename from docs/images/chapters/derivatives/0c8a8fb27762b2f16a154937de35a764.svg rename to docs/images/chapters/derivatives/f29a9d52897d2060a0c8a37073ed04fc.svg diff --git a/docs/images/chapters/explanation/95dfdee360469d4b4be64bb43c96b53e.svg b/docs/images/chapters/explanation/f79dd2f2d992e22b8d057fdc641290b0.svg similarity index 100% rename from docs/images/chapters/explanation/95dfdee360469d4b4be64bb43c96b53e.svg rename to docs/images/chapters/explanation/f79dd2f2d992e22b8d057fdc641290b0.svg diff --git a/docs/images/chapters/extremities/e010384d41b8efd3b430071884656b79.svg b/docs/images/chapters/extremities/2c398b492aadc90eb4e4853fc20b23e9.svg similarity index 100% rename from docs/images/chapters/extremities/e010384d41b8efd3b430071884656b79.svg rename to docs/images/chapters/extremities/2c398b492aadc90eb4e4853fc20b23e9.svg diff --git a/docs/images/chapters/extremities/99f05b09492d54d669831881026b11fa.svg b/docs/images/chapters/extremities/c4858be225d004441b2aefedacda89a3.svg similarity index 100% rename from docs/images/chapters/extremities/99f05b09492d54d669831881026b11fa.svg rename to docs/images/chapters/extremities/c4858be225d004441b2aefedacda89a3.svg diff --git a/docs/images/chapters/inflections/750893530458a4796d3afddcc901ec91.svg b/docs/images/chapters/inflections/2dbf3071d74e2ba37ab888aaa3c1a17c.svg similarity index 100% rename from docs/images/chapters/inflections/750893530458a4796d3afddcc901ec91.svg rename to docs/images/chapters/inflections/2dbf3071d74e2ba37ab888aaa3c1a17c.svg diff --git a/docs/images/chapters/inflections/590588aede098d00dd493123c4a632cc.svg b/docs/images/chapters/inflections/d7d564126099bc0740058a7cdd744772.svg similarity index 100% rename from docs/images/chapters/inflections/590588aede098d00dd493123c4a632cc.svg rename to docs/images/chapters/inflections/d7d564126099bc0740058a7cdd744772.svg diff --git a/docs/images/chapters/inflections/c68722c9f3f8cd3d1e7a1616a37bc4e3.svg b/docs/images/chapters/inflections/f9f2258e59b038659087a5e87ba2e0af.svg similarity index 100% rename from docs/images/chapters/inflections/c68722c9f3f8cd3d1e7a1616a37bc4e3.svg rename to docs/images/chapters/inflections/f9f2258e59b038659087a5e87ba2e0af.svg diff --git a/docs/images/chapters/matrixsplit/e32979a306a4cae24808a3abc0c91387.svg b/docs/images/chapters/matrixsplit/55b45214ba90c96978cdc9cdfee24fef.svg similarity index 100% rename from docs/images/chapters/matrixsplit/e32979a306a4cae24808a3abc0c91387.svg rename to docs/images/chapters/matrixsplit/55b45214ba90c96978cdc9cdfee24fef.svg diff --git a/docs/images/chapters/matrixsplit/631a35d9c34fb375232a45af50e66602.svg b/docs/images/chapters/matrixsplit/598739d23cf8dbcdebe033e4c7f1d28a.svg similarity index 100% rename from docs/images/chapters/matrixsplit/631a35d9c34fb375232a45af50e66602.svg rename to docs/images/chapters/matrixsplit/598739d23cf8dbcdebe033e4c7f1d28a.svg diff --git a/docs/images/chapters/matrixsplit/4a448a31f707975f7eba3516262a6cd6.svg b/docs/images/chapters/matrixsplit/7a1e792cd3fa6f3482459e154abf2e7d.svg similarity index 100% rename from docs/images/chapters/matrixsplit/4a448a31f707975f7eba3516262a6cd6.svg rename to docs/images/chapters/matrixsplit/7a1e792cd3fa6f3482459e154abf2e7d.svg diff --git a/docs/images/chapters/pointvectors/349ae68c5a68247857960032eb76b8de.svg b/docs/images/chapters/pointvectors/58b19accb8a68c665ff5cbed610eea4e.svg similarity index 100% rename from docs/images/chapters/pointvectors/349ae68c5a68247857960032eb76b8de.svg rename to docs/images/chapters/pointvectors/58b19accb8a68c665ff5cbed610eea4e.svg diff --git a/docs/images/chapters/reordering/c4874e1205aabe624e5504abe154eae9.png b/docs/images/chapters/reordering/c4874e1205aabe624e5504abe154eae9.png index 92f4f36ce83fcbac830500895ed10c511167f06e..46170a67bd409488adf0f86edf3cd42efd4b204c 100644 GIT binary patch literal 11933 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 literal 11653 zcmb_?cQ}^+-?!|U8A5iFWF;$`kR&8Y)@847*?Y@gNrbEjUxbh?dqi2;MfRTA^M0S- z-(UB0JjZh!&wbn_n3{~C!>o#E@r=d`0itx@Z*nf%(ALXKHb!=nzsIS84K$U zakouR&)@TD|A)Hjj0-+y3kTIapCacQeA%}4e9{*6e~CoT_F*b~Aa|&)yPiJI`jfFj zab5J8XVzPv(k_#kA~LI(@eli{#r4!71S~l;+5S`YMS}! z(`7gv>WE-Y&GKVF}tI}@nrCVa;Jn-g<&*^fO2c(>-m-6wXTYrll7M{Hosm- z);KK>>|RuU9~2O&LQ&=7yt%lvY+Izo#|K21vvxQ*RmoHy#I>EEZv#LKC6~ui!yEsLsWK>%9C@{C7fpMbJu48X? zgq(>fro3FR)8wa>c zO6Jnsc0aeic}3$+!G@vXVOe&HCL1BS;t}B!+77gc$1dlj=cWYJl`AqF@hp6NWOvMZ z8aw0I)_1?*2Zv$Zymc$E$3(`WK&dxT%$LG|KI!7$qeo`>ZM+ z9e8AGAILBqwl=WtFn zF(IY@Em)F%afn8KHhGt~(^B81v9U1`hdKP6zkm5(jtlOtj*uQ59rdm5ZSC%w=w%Il z;3MZtP!2vm_NXbhWGU5-yf`ktu-b2kzIHFGq=YOkF3$D6f!v{-v6=rrd3n+=U*3*V z(&_5x!1MR_=j7z{8?rLhi+%!EVXn|2d9NB08j7!T)E(&OhvDYw`2ntQJ5}pGpX%#^JWNLEVRB~HbSa_xSUaZNGFXQv) z*UqAsw2_fYxxq`b(Dsgwfw{Ri<{U(! zT>P1y_J{3dWoK{YVXJIcY#%8$2+`!4cUBa5ChOTa9@cLWr0~ICHq*YwlYM@EzRGQz zl}ESA@AT9Q0x>f$4?j3K*xuFEPOLk3d)-#XijUTik5=u;6Rdjun3)+P*k~k_AX?${ zLc_vjY;3rVjE%`DDO*mI|GavItEs6eovGG0zsQy$VYuF>4~H5a9-g7e<$i)=xaV=3 zn&|WA&-RB~sMDQpUJ>7OabjF7kNvf1j1is-?;Ldv$enjMW^`vugVK z(E|e-r{^b|5EG5_-HCB2DG^YCSj5EW!otFoR8(61E@6?;(2UHS>2K_LSX*1GYiR8B z6+{M~{xvU#ev}&p*(dbAd@;|{>Q@ySOX~cPO+Y}vex{WGHktUU0Ct(#_vYlg)?`<& zx_68$In`+45ZM3qQBYFCmz9+zyK-e{Eo8(*faTsj`rOCq?dNAF+duAYHrfaouZ@-} zJ$NAF;2_}T?afrv`{LPEMFoX{@bwUB)WEBi)m2zZz}D8*$G{?n`?j_`4aY0D*2c>4 z=%R2bIaC@S^415fPgD}kqy?yOSkom4)_Cl3!O}`B2RZ5vXCjscb4fWKr$s)9=V+Rm z`r7sq4;ve9i^RTi&g;uptyw&h2NjUpXlsYUxr_CLW?Kk(SqX z8x7~}+ikB%==pq3-DI%4>Ra2}jhX^*Ml0=@G`X%&-_{8-?ucgL;v#%3dBomuw*P{b z_!V`<{g_B5#^49^7R0ZSw3(PlaTYyjLo*26xx;Vzjf$O}{m-|ATiT^YID~|RB}Q$8 z?ANc0&NY-dR5RSXd2_VE`yL$qR?nT@KM}kQ(h%csxu5Se#%3tCllE@=C}aPCM9j-m z+LAF6q$~9~^FS`x>wA7jA&M?ID~r|UR~7kV@$Dcv+|GJPc;n;U<<8E|#_ib-^=HpQ zva{J$-U;C3s=lvT9Qj@IO*?mRtkkGuPF#u~6A4*0HNTP)z9w9V_|}!70`eAB%6=Nt?0fP&U!rjl1a9C^!85iSH}K9*4mt{-m+^TW+B4j9S^JdE8>iG)?P&hy z?b`vaS-cFs>98h4X&)a+Svk4s+1Zww)O(QY@CjVK8mFdAxscejv}m}9@myydk9%PM z$OugY_3dT|Sbp;#40RCiwERZcK1cJ3_arOP6xWIb8l(s*8Gnhfy1(g&d-)RD)Y5Pf z{r=`u41fR@35jcG$9u+lZ<#~oS&=8D;ni=2eGCaX%TawzNl5S7mq*_@pa zslWzj(3dHP*M##xON$zplrhqE%A00&xTs~a-ZL&Xwy}m=h9XQ}>ES~;Rn^Pw(bpnS zEw51Lr$+!ctd1FUOuc-mIEoAf-o>V;$Hc~x$w&wk6&H7`7JrTAH*Pmv=y})q?OQXn z6Ya!#GH8m_+}eGD0?XqSw}f7f|J+4;n0VPyal~{&n(*?HHZ?VE{rzjKry37C!p6dK z2`VzO@A_`jIJq7I#=MsaDe zw^)kXe#xoA*jyw-K}ObC!+_Da@I8g!W7mTF`DbjvD>T0z8Jbhj(1aNH9O1wb$w8*Y zB_s^(c8(gAmhi-g>MV`Ol8}&e_Vy}DOZzbgv>NjL8G2^WR$)D|HDULag_}Fl`2mj% zH}$NY?+LwzhDPk$x33_>QQI?Zd4+{R>FMbYiv>Q$Js<*1Ha9;Hna>1x!daA)ho}8; zdln^>f`$T0NP&BNuo(l-{s$_G8zeakMVRh+9Di^ZmLP5zT!lGcZl)~)0d5>BNq*Pv zxs-eKlI<)(Nwfdccu8JCVP-iu{Z*HV!?I#K6~{q8Eqg;l13n?4k=|vWkDl&D%7o}D6ZQfghi`8f4=-VCeo60)U#yFCND3~FC-*{nIrpbtA+Hi z+u%H)xZ#-a!Gi~d-7Kzg@7{%(cE3eIG~yEwpu>XWzuVu|)YJPt@YwlqpPQN}F(sut zUz2Nc+~$$@#Fv+|u*9mhH5>i$T6(LP^nIU;Ggn(UU|km%p=SmLQ!D$2Mlt)k=K{Hz znU}6!y*gTg!ct8WCny*Sud5S>t|_B(e7rmOxYVSJ;`H=y@6u2K&8kBu7NiZ3Pojo-gNB6~9Dy74P4M(UgvkCahf zMTL0PL5V0hBxH8e_u}3c+uz}T7kg`a{=JCQ+4AEgQAZBdbjhekDMBcK-O$KJtI%w# z1NK{gWO~x2m`?WB<)B}}O60<$quZNc9i4TiJ{gNhr(4BI9p7Hkxh@{v&c3 z`fzObyxVF~CGzo)74Idz=>~HjcYM;Twdlscqb4W!Umnbr%T$xj(LfqgfmTs7RCqN_ z&DI+6$!ePk^5DR>{oF#3v=~ zptq~@52L(+z_P{Obj7beXC*Hugofw0znSI^dU|+dy{NQ>^uS~EJw*ov1;Or+82Fyu z#U-I@&Hni9n=<>28?$EzQyqXG-~E(6bcOgzmGGpV@;f(kK{Btw~b?-$RD z>~#hS4=O<0$S%U$rswB_ZGYEfx^7O2c-9)aoC{xLB(N16u~F0rBRHD6sZ6|P&i zGSxVfa35G&-ZcA>8uoJH3xUyVhUuxT=@z7GI&Dr~%g@ixD=27rEOizXMK3J*^J=H; z;^#zBSgc2V+L5g#Z~ZPsn&*ZnF}+Zv<+bdW^(Py(qqVNQfVB86`j}Itd>N5Oz53a0 z{xe%VZ2#fO$(`ReN8P+%4;iKo^dS_M?Qge=`IghkJkiH| zsQQdeI9uR6*=M?8gN`eFmb!f%4!xmJ2Kt2}Td#{aCza^;~@AhhZ^uZ%_kO88P$j>{b+A0j+GVH zART_`ja;JmfRHflaNJ!{OPeX!BMn(poh{#w65ALmr zf=vSDA?fy#wbR-tzZhOf6+faZS--`wNW8n!D`IC7%Ci9hQa|eiIl4ATw z6`j>I@1z)@P^ILEvbNVw>%+qUx{+60oV$)2+KmpEFf7u#1=v%}X{k|MC7MArAmP?C zquw+Ll~v}}Np=vd?#I^#)!oQZ&Iy1FElw1P(J@e02L*;=<4}j?;!NH1CnM9k=&5Nm z1gBO(a7+y8DhP4a)zzUfG3I)>EG~;%sH}dAKkMtalUlwO>(#dJN;}DFqnG%|n*$mq zt^nNuNKx3$+`7RarUG@Lf5206A3B@t9fPok4*z-E3t$eI7=Z1sK9dbS6SYagN6AdB z2T|JwjmEdUB3Pw7-uU?OqXOUK1pHFr5Mrcq6bx}yb%%|Q>og6?ht`XjBmrlV;a;lM z)6;vO!BY#T5JE)xuk6AcisM~brc*=~(FV&1B7oP2Z|suGZm7}@Dli$sW_0%S1ObUR zj*)n^nC2Pn{2(ZH0{=Yy0Dib^_w`Juxw#ospi1Ba&4Ce3Wb-TRij^q&Wb7 z2cEjMvm+aF`5J(sKU4Lo zbwHlzy_Kg}>>Dm5Uad3l^Nw+|y?Vrb@!t!Ku?oL7Qyh^P(M$14t@Gn82Lv$}bB z7%l#Izjbi1m_rJ2jR9z04(<$U33f&C1K=v9?tjgYTdP3)cpPj*>D9U*K-H*}R$X1a z?i1Q^lwD9~1@d%}Oit!8(Z2O-0->4j_>K`ZDhcvdX532(&40M!J9 z1~o0M_8KaTMqoDxGKR;Z0pKSJKquo#uBwas%rX@U^OtU^wICf%X&;Y}5H&PZP*%+K z2+`^Q^^wqQZfWVye{!RCcUcfM142_@pBga7X0tN>V$;@8a>!&89Xzxi60`#Y1F^BO zhLw`!FMNsG*9ydIwkPbPH=$Ae2bVWsTNGh#q2XdU@Hh(&s&w3I;Q% zThPaQ(l-!ovm=HnMBxJpu6q0F)2D8;QNn!gJ0_rL)b6i4p$0^T8bAtQ=-@ACnV6st z#3OA7ywO^SJL7>+w{r8(@MF;b5o) z7`zu!0qqb3^(57bgPon`Cyyn9i@%;HKPPEDda9+xdiyrXl-FMpFE6j8^_aDC6lR8H zUdIl{66`>UX*adm8RcR-n!&6$EvhU21{)`5=(5X4)oZZSgf@t83kwUwfs0rcIcAEm zEdV{xibX09COt_(&`c7xV;rxvBXxCkHLIw)N{kyl?~UV`m!I!HW@GkcvkNN9HXzm6 zsf%;r`13Hw@p@0;w>)~`utAtrqPGL)6;OaN($fjOW4cc&I?xQ~hqI*EczBg=o0O8P zciyRh;3wjB$Y+;JCbn}BIBxCjDJm*TE9$@w%$?N0z<`q~{KTh0V#V>eo8iyG?mnV+ z78Vj~6%1{hb(;wEq>57B(kd+RoN7IS#8*ibAy4<(A$X&FU7nS^SY|sQ$Jv+$a98($R>WWR_3uTA@U;%2GJ_{Gk6LB zrd&2B06rm{d1t1>Ii%dG-8A53T~uHUEI zUmFVqg{)=6o3f)4I*V?#0}kjR(sFWGPGZ;oW!*!qInCHr?p0MFY{uuqj#hT~UL5!u z19NfNOcD9=v_K1mbg#}%i*bBzIK4`_j-x*gkVE3F4-1CC78tMJOf>Mh3f)@7X({&i z2}krz5IkUC8aIB|_J7j5_w(n^MyrY}P(lhHTDMPf;<+`D}Hc?3mx+D}C&`FKIoG+M)o0Q<>+0ipFtHw^aYiuK#^FK)2S;n1ZvnbW_U^H&kS)^sAQy5u@*ita!uSiaFnI)S3Jsl? z^-9Wt^(A?{#0Cs)^k}WDcWb4fcm_}^5XYa_n0R@46>DAAvCELNJx}W@g6a)`Hw^Z% zR;nXWIcN0COL~N)?ru&oA>yIl$&LL=kjlLFhMqwUmUnX6y~ZR=OAG};1_*uN3L|5b zitQi>XG>0E9JS+6_pbuiZG)9WbSLso)cYDSL4{AcV}5yHa1e-TSS>CA#+!r$7KldH zIOEe~F@*#dcIt?f;f<1{3x1VOYHH8XSVlRBEC%+Ad0hvU)KT zK8f6%nYoc=BSCOlC$FZaCMSJ`Y8_etI+5340hB=AbqQr}yM`kUXi;BleTw=n&hzRQ zd=97acpy|xKzL^weXE=^WBaSB>6s-%$JpZDfawnj(08zLaQNR@O)UkIN=kzUz-QJ& z`*V0$pde6OEam$vkZ`6Gp6SbYc!)t|_MYk$ey0K!RKV!q9!fpw7pPqrz^AneOto4- zaRtrM56nV=qCj!+D1|`uZ2L4M91wMGhz`cXyIcu`AOZ%A@8;!z+{P>@NX3;9KE|RC z_6?$1Hu_`n+l=x-o#M+66iMl!G&aWPedUQ2FJ{+vOwGqWh>F3;?X>=jSS< zOsIb2jPbL~RP%Ap1@ z0c{{w1emns*RDl@`eO(yaPf6IMNHHP8s2tjHTL^!&ujM|F|M^o(bEcAkUe|F66V_L&%&9y2t2A)8S@(6+@dPX7Ys-;`UYvn$nRFgyG1U9q69W-X%O2`GIL zNY4Q4;ebpzd%J0f!6cGszM-t6Y#dKmzVg#Oa!k3ZeZrny6C`xoYJ~pwL>sH zXo14^f222#_f}(mDgd9#)yPk-f1Fo*;IrP}3ClKUhy-8-{SJ{z!7dC94fRV*qzR9R zc=wZvo<8D^`48#bK@^zW;KmqggcJz8Q$dJ3C_zCtpL{d~ZV?(8>9ynn7)mFaFh3;aQO*gC&FN*OPpg2-F_K2But) zcBpxDL#JCpW~&#|5D6SneL_-q*_|LMI;@N9UjcMJg=lC5nyF>Ckg`j|? zKcXBVdfLzYCy2%r6okFI@tYo+sp)6ewcm(MF=F6*-`<|jV|U3P5FHRRRk?y8BM@)_ z^2=*zP{8r`tuUAB6mjzM(yXcejR|PZ4o>q}xe0o%Opb<3?%?!njFdtmk6wmGJ~kyM zL@+1@pZsaxrxSgP1F~w3xvP?ufqD0st=Z zuJv%amAM;aXpH1BzT-kqlOmIM(CgO}GS|d@;1R}aQCMYwut4vvmU6+k5F{Mmqq)KRgbaci0I_Cl#W--yLnsaWmILfS6!0+Y0sDi#g|ofAUAJdk zHimRQBp(s4JYN(4^5u3Y@%EsFOdgYCf`#Mm<|du5nN?n{S@Ja-5?&SxBx0K*+8}sp zAQE?g_OG32Mg!vpNV0&Fg-j42ZK1Qfy9JNQ3t>u=CzN6G;1xE4PU#QR3Y=7gP*5@e z&w;vDchEr*OwbE_g_V^R_zFj!Cuikq{|7uFyUEDZREERjW24iLD-xIHv$=cfsz<9H)j%}+m#IF zQBRKwVsS#WD59l0edure z*I&sR6FdUT0rE2ws0?(f4y*~sH|dEAR2(mV=^JOj2Jh5Fcjy;CD;}9W+5Fl8z0DqO zO&g^E9GePp5C20gc|p^hsE~~B3WDoQA58gnNlcrqj ziPQJc7oysAaLSOy_{79Edjdq6=i*bv5;`e^?I79%Gk`{Y3Dk^`7a_m}!(dP*J16H- zl{?m7C{Rd+M9K!De?T2YvU6r;28nLi&zA0PB8cJ`@yOz$qF@*_fQk&HVwNsS2!XXcOu%;FO?@ldnk#^Ewbw9{|FGjPTXCRqe%#2pBYi zfve2VpD94f)X1lTNspzU`IM||Y~*xw;gH6xJUo|S9LsvoJ7)O&3^bR_x;h4c1c(=C zVL{e<5NPTNYoUbe=V*ih)Wxu`BL7wo*aes>GfWUbv9a;+oh40C&4t(k+1g*>L-p$A z6Ud=Qc7(y0guye>cW-%J2#9mR;1l3RFxi0U3rY}V%@a~_xD2^<&D!`oNP!q42c-fg z7oH~$aG8}|1^E(2g&_N>5el7Y|! zNDkR$&~2f$k%R^LJkkj`e@kmc{HEQLlZtcA{z4R2t4OP5aF7zlR(Q^m4%F3>_!c%c zCf7c4Ot%vYTpa ztrmiS##_wF`i=D&)syh?ag-;lQg4CiJH5Uh1q8;Ur<)Cie=?<~r-~f!V`5^GQB%JH zd6SSL4c<A$lI`JK?}B75sPX zEk5DDfPX6b59orR1PZ`Lm9Ay#E!H?C_#d`%yuv^bau7eUva(Wcqib9T3_k78CIm1% zhk=0%YTVnb!x9!22E0CMBLveZ6-Vcv<|K6-msG9QJV|?PgdCq0>(9e3<2*NbQQ^As z^Cpj=;2WT@wB}`FRdC`PV0$ir2vY?*kferztWSOPIOFX=C*~-6ZrJ?HhK4j}QJ236 zT7=Hl0kYnIChxWY#IZpK0nbcuS%n$q;#6jJ(vp*tYd3TjxB0=vwd*qyS@vNQa`4uJ&#>l$H6huBp@a~%az>I0$I{-hSraheX$UUCaY*A36^=knF7H3(`&CsUYrku05SSExLs)*^q0*>;jTkb642y8OW# zK!|u-1dWuv_qV_eYeD@iFtRR#utEJj&I~>PB9=cu0pQKxL^q{Edxv#0GN*LGJ!8>!qU>xjn{ zqCzUe?>lH&LuC#Ge#CB|9!r \ No newline at end of file diff --git a/docs/images/chapters/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.svg b/docs/images/chapters/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.svg new file mode 100644 index 00000000..bfcda18d --- /dev/null +++ b/docs/images/chapters/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/images/chapters/whatis/175a7fedac4f14c374bc861bfc2900dc.svg b/docs/images/chapters/whatis/c3f06301f5ce610df1217bc633257297.svg similarity index 100% rename from docs/images/chapters/whatis/175a7fedac4f14c374bc861bfc2900dc.svg rename to docs/images/chapters/whatis/c3f06301f5ce610df1217bc633257297.svg diff --git a/docs/images/snippets/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.ascii b/docs/images/snippets/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.ascii new file mode 100644 index 00000000..c67e57c7 --- /dev/null +++ b/docs/images/snippets/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n=3 n-k k + B(t) = ❯ \ P \binomnk(1-t) t + cubic ‾‾ k=0 + k + + 3 2 2 3 + = P (1-t) + 3 P (1-t) t + 3P (1-t)t + P t + + 0 1 2 3 diff --git a/docs/images/snippets/abc/50543216f39c1b10af7cf4823844dd31.ascii b/docs/images/snippets/abc/50543216f39c1b10af7cf4823844dd31.ascii new file mode 100644 index 00000000..436869ab --- /dev/null +++ b/docs/images/snippets/abc/50543216f39c1b10af7cf4823844dd31.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 + (1-t) + u(t) = ─────────── + cubic 3 3 + t + (1-t) diff --git a/docs/images/snippets/abc/6a65a8327c06bc6f14cc4e0751d8e49e.ascii b/docs/images/snippets/abc/6a65a8327c06bc6f14cc4e0751d8e49e.ascii new file mode 100644 index 00000000..a17a8573 --- /dev/null +++ b/docs/images/snippets/abc/6a65a8327c06bc6f14cc4e0751d8e49e.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C = u(t) · P + (1-u(t)) · P + start end diff --git a/docs/images/snippets/abc/b9854fbcb1096f736607d292dbe48371.ascii b/docs/images/snippets/abc/b9854fbcb1096f736607d292dbe48371.ascii new file mode 100644 index 00000000..9fbc90c9 --- /dev/null +++ b/docs/images/snippets/abc/b9854fbcb1096f736607d292dbe48371.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + distance(B,C) + ratio(t) = ───────────── = Constant + distance(A,B) diff --git a/docs/images/snippets/abc/bb8674f5f36b054b7734e34b91ed924f.ascii b/docs/images/snippets/abc/bb8674f5f36b054b7734e34b91ed924f.ascii new file mode 100644 index 00000000..c9a30bb5 --- /dev/null +++ b/docs/images/snippets/abc/bb8674f5f36b054b7734e34b91ed924f.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C - B B - C + A = B - ──────── = B + ──────── + ratio(t) ratio(t) diff --git a/docs/images/snippets/abc/c018aab3952ea9193848564aab12b241.ascii b/docs/images/snippets/abc/c018aab3952ea9193848564aab12b241.ascii new file mode 100644 index 00000000..2b5de371 --- /dev/null +++ b/docs/images/snippets/abc/c018aab3952ea9193848564aab12b241.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 3 + t + (1-t) - 1 + ratio(t) = |───────────────| + cubic 3 3 + t + (1-t) diff --git a/docs/images/snippets/abc/c10cf18edeffed67dc94d250310db475.ascii b/docs/images/snippets/abc/c10cf18edeffed67dc94d250310db475.ascii new file mode 100644 index 00000000..2cd83fa9 --- /dev/null +++ b/docs/images/snippets/abc/c10cf18edeffed67dc94d250310db475.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 + (1-t) + u(t) = ─────────── + quadratic 2 2 + t + (1-t) diff --git a/docs/images/snippets/abc/c14d8ce6eccca2c8063af40e5ac0bfd4.ascii b/docs/images/snippets/abc/c14d8ce6eccca2c8063af40e5ac0bfd4.ascii new file mode 100644 index 00000000..6c9a5942 --- /dev/null +++ b/docs/images/snippets/abc/c14d8ce6eccca2c8063af40e5ac0bfd4.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ v - start + │ 1 + │ C '= start + ────────── + ╡ 1 t + │ v - end + │ 2 + │ C '= end + ──────── + ╰ 2 1 - t diff --git a/docs/images/snippets/abc/eccc1bdb9423bbfe2d42418fc8a7dd24.ascii b/docs/images/snippets/abc/eccc1bdb9423bbfe2d42418fc8a7dd24.ascii new file mode 100644 index 00000000..762736aa --- /dev/null +++ b/docs/images/snippets/abc/eccc1bdb9423bbfe2d42418fc8a7dd24.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ A' - e + │ 1 + │ v = A' - ─────── + ╡ 1 1 - t + │ A' - e + │ 2 + │ v = A' - ─────── + ╰ 2 t diff --git a/docs/images/snippets/abc/f78ce50f725f208f25090abc7fd741b7.ascii b/docs/images/snippets/abc/f78ce50f725f208f25090abc7fd741b7.ascii new file mode 100644 index 00000000..e54a5937 --- /dev/null +++ b/docs/images/snippets/abc/f78ce50f725f208f25090abc7fd741b7.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 2 + t + (1-t) - 1 + ratio(t) = |───────────────| + quadratic 2 2 + t + (1-t) diff --git a/docs/images/snippets/aligning/00480d8ea1d0b86eb66939bced85e14b.ascii b/docs/images/snippets/aligning/00480d8ea1d0b86eb66939bced85e14b.ascii new file mode 100644 index 00000000..256a97aa --- /dev/null +++ b/docs/images/snippets/aligning/00480d8ea1d0b86eb66939bced85e14b.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 3 2 2 3 + ╡ x = \colorblue120 · (1-t) \colorblue + 35 · 3 · (1-t) · t \colorblue + 220 · 3 · (1-t) · t \colorblue + 220 · t + │ 3 2 2 3 + ╰ y = \colorblue160 · (1-t) \colorblue + 200 · 3 · (1-t) · t \colorblue + 260 · 3 · (1-t) · t \colorblue + 40 · t diff --git a/docs/images/snippets/aligning/6acf1a1e496f47c11e079a1d13f0a368.ascii b/docs/images/snippets/aligning/6acf1a1e496f47c11e079a1d13f0a368.ascii new file mode 100644 index 00000000..22433e00 --- /dev/null +++ b/docs/images/snippets/aligning/6acf1a1e496f47c11e079a1d13f0a368.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 3 2 2 3 + ╡ x = \colorblue0 · (1-t) \colorblue - 85 · 3 · (1-t) · t \colorblue + 100 · 3 · (1-t) · t \colorblue + 100 · t + │ 3 2 2 3 + ╰ y = \colorblue0 · (1-t) \colorblue + 40 · 3 · (1-t) · t \colorblue + 100 · 3 · (1-t) · t \colorblue - 120 · t diff --git a/docs/images/snippets/aligning/a75137c250be63877a30f4bda8d801f8.ascii b/docs/images/snippets/aligning/a75137c250be63877a30f4bda8d801f8.ascii new file mode 100644 index 00000000..e5d247ae --- /dev/null +++ b/docs/images/snippets/aligning/a75137c250be63877a30f4bda8d801f8.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 2 2 3 + ╡ x = \colorblue - 85 · 3 · (1-t) · t \colorblue - 12 · 3 · (1-t) · t \colorblue + 156 · t + │ 2 2 + ╰ y = \colorblue - 40 · 3 · (1-t) · t \colorblue + 140 · 3 · (1-t) · t diff --git a/docs/images/snippets/aligning/f6767b16ff8e04646f45fb9a1f3e4024.ascii b/docs/images/snippets/aligning/f6767b16ff8e04646f45fb9a1f3e4024.ascii new file mode 100644 index 00000000..a9a2facb --- /dev/null +++ b/docs/images/snippets/aligning/f6767b16ff8e04646f45fb9a1f3e4024.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 3 2 2 3 + ╡ x = \colorblue0 · (1-t) \colorblue - 85 · 3 · (1-t) · t \colorblue - 12 · 3 · (1-t) · t \colorblue + 156 · t + │ 3 2 2 3 + ╰ y = \colorblue0 · (1-t) \colorblue - 40 · 3 · (1-t) · t \colorblue + 140 · 3 · (1-t) · t \colorblue + 0 · t diff --git a/docs/images/snippets/arclength/046bbb52e8c8ed617fdf3a4fd18d62e1.ascii b/docs/images/snippets/arclength/046bbb52e8c8ed617fdf3a4fd18d62e1.ascii new file mode 100644 index 00000000..6f4b03da --- /dev/null +++ b/docs/images/snippets/arclength/046bbb52e8c8ed617fdf3a4fd18d62e1.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌─────────────────┐ + ╭ z │ 2 2 z ┌ ╭ z -1 z ╮ ╭ z 1 z ╮ ┐ + | ⟍│(dx/dt) +(dy/dt) dt ≃ ─ · │ f│ ─ · ──── + ─ │ + f│ ─ · ──── + ─ │ │ + ╯ 0 2 │ │ 2 ┌─┐ 2 │ │ 2 ┌─┐ 2 │ │ + └ ╰ ⟍│3 ╯ ╰ ⟍│3 ╯ ┘ diff --git a/docs/images/snippets/arclength/0748ad25185548150b6c1c4c7039207e.ascii b/docs/images/snippets/arclength/0748ad25185548150b6c1c4c7039207e.ascii new file mode 100644 index 00000000..ffc62b78 --- /dev/null +++ b/docs/images/snippets/arclength/0748ad25185548150b6c1c4c7039207e.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌─────────────────┐ + ╭ z │ 2 2 + | ⟍│(dx/dt) +(dy/dt) dt + ╯ 0 + z ┌ ╭ z z ╮ ╭ z z ╮ ┐ + ≃ \ ─ · │ C · f│ ─ · t + ─ │ + ... + C · f│ ─ · t + ─ │ │ + 2 └ 1 ╰ 2 1 2 ╯ n ╰ 2 n 2 ╯ ┘ + z __ n ╭ z z ╮ + = \ ─ · ❯ C · f│ ─ · t + ─ │ + 2 ‾‾ i=1 i ╰ 2 i 2 ╯ diff --git a/docs/images/snippets/arclength/2f80643c66d8f1448b13537a7b24eb45.ascii b/docs/images/snippets/arclength/2f80643c66d8f1448b13537a7b24eb45.ascii new file mode 100644 index 00000000..714299cc --- /dev/null +++ b/docs/images/snippets/arclength/2f80643c66d8f1448b13537a7b24eb45.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌─────────────────┐ + ╭ z │ 2 2 + length = | ⟍│(dx/dt) +(dy/dt) dt + ╯ 0 diff --git a/docs/images/snippets/arclength/59ebc3a7c3547a50998d1ea3664fb688.ascii b/docs/images/snippets/arclength/59ebc3a7c3547a50998d1ea3664fb688.ascii new file mode 100644 index 00000000..c0556eee --- /dev/null +++ b/docs/images/snippets/arclength/59ebc3a7c3547a50998d1ea3664fb688.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌───────────────┐ + ╭ z │ 2 2 + | │f '(t) +f '(t) dt + ╯ 0⟍│ x y diff --git a/docs/images/snippets/arclength/a91fbfb7abc38ff712ef660d85679f2e.ascii b/docs/images/snippets/arclength/a91fbfb7abc38ff712ef660d85679f2e.ascii new file mode 100644 index 00000000..bfce7dba --- /dev/null +++ b/docs/images/snippets/arclength/a91fbfb7abc38ff712ef660d85679f2e.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C = 1 + 1 + C = 1 + 2 + 1 + t = - ──── + 1 ┌─┐ + ⟍│3 + 1 + t = + ──── + 2 ┌─┐ + ⟍│3 diff --git a/docs/images/snippets/arclength/f251e86158649c0e57f7a772ebff83b4.ascii b/docs/images/snippets/arclength/f251e86158649c0e57f7a772ebff83b4.ascii new file mode 100644 index 00000000..c221a164 --- /dev/null +++ b/docs/images/snippets/arclength/f251e86158649c0e57f7a772ebff83b4.ascii @@ -0,0 +1,9 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌─────────────────┐ +╭ 1 │ 2 2 ╭ 1 +| ⟍│(dx/dt) +(dy/dt) dt = | f(t) dt ≃ ┌ \undersetstrip 1 \underbrace C · f(t ) + ... + \undersetstrip n \underbrace C · f(t ) ┐ = +╯ -1 ╯ -1 └ 1 1 n n ┘ + __ n + \undersetstrips 1 through n \underbrace ❯ C · f(t ) + ‾‾ i=1 i i diff --git a/docs/images/snippets/bsplines/20e910bbea2e6eff511cb13cef18ef3b.ascii b/docs/images/snippets/bsplines/20e910bbea2e6eff511cb13cef18ef3b.ascii new file mode 100644 index 00000000..926fb0f9 --- /dev/null +++ b/docs/images/snippets/bsplines/20e910bbea2e6eff511cb13cef18ef3b.ascii @@ -0,0 +1,30 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ ╭ ╭ 1 0 0 + │ │ │ α × d , with d either 0 or 1 + │ │ 2 1 1 │ 3 3 3 + │ │ α × d , with d = ╡ + + │ │ 3 3 3 │ ╭ 1 ╮ 0 0 + │ │ │ │ 1 - α │ × d , with d either 0 or 1 + │ 3 2 2 │ ╰ ╰ 3 ╯ 2 2 + │ α × d , with d = ╡ + + │ 3 3 3 │ ╭ 1 0 + │ │ │ α × d + │ │ ╭ 2 ╮ 1 1 │ 2 2 + │ │ │ 1 - α │ × d , with d = ╡ + + 3 │ │ ╰ 3 ╯ 2 2 │ ╭ 1 ╮ 0 0 + d = ╡ │ │ │ 1 - α │ × d , with d either 0 or 1 + 3 │ ╰ ╰ ╰ 2 ╯ 1 1 + │ + + │ ╭ 2 1 + │ │ α × d + │ │ 2 2 + │ │ + │ ╭ 3 ╮ 2 2 │ + + │ │ 1 - α │ × d , with d = ╡ ╭ 1 0 + │ ╰ 3 ╯ 2 2 │ │ α × d + │ │ ╭ 2 ╮ 1 1 │ 1 1 + │ │ │ 1 - α │ × d , with d = ╡ + + │ │ ╰ 2 ╯ 1 1 │ ╭ 1 ╮ 0 0 + │ │ │ │ 1 - α │ × d , with d either 0 or 1 + ╰ ╰ ╰ ╰ 1 ╯ 0 0 diff --git a/docs/images/snippets/bsplines/89f8e37237d066fa70ccf6d37b3a4922.ascii b/docs/images/snippets/bsplines/89f8e37237d066fa70ccf6d37b3a4922.ascii new file mode 100644 index 00000000..2e97737a --- /dev/null +++ b/docs/images/snippets/bsplines/89f8e37237d066fa70ccf6d37b3a4922.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n + Point(t) = ❯ P · N (t) + ‾‾ i=0 i i,k diff --git a/docs/images/snippets/bsplines/a88566be442b67fb71f727de6bdb66df.ascii b/docs/images/snippets/bsplines/a88566be442b67fb71f727de6bdb66df.ascii new file mode 100644 index 00000000..270d3194 --- /dev/null +++ b/docs/images/snippets/bsplines/a88566be442b67fb71f727de6bdb66df.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + k 0 ╭ 1 if t ∈[knot ,knot ) + d (t) = 0, d (t) = N (t) = ╡ i i+1 + 0 i i,1 ╰ 0 otherwise diff --git a/docs/images/snippets/bsplines/c7af721e5e201fc3742bce67ff6cd560.ascii b/docs/images/snippets/bsplines/c7af721e5e201fc3742bce67ff6cd560.ascii new file mode 100644 index 00000000..cbbf5e80 --- /dev/null +++ b/docs/images/snippets/bsplines/c7af721e5e201fc3742bce67ff6cd560.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + t - knots[i] + α = ───────────────────────── + i,k knots[i+1+n-k] - knots[i] diff --git a/docs/images/snippets/bsplines/cbdf5a61de10eeb6f23be077cf047ab5.ascii b/docs/images/snippets/bsplines/cbdf5a61de10eeb6f23be077cf047ab5.ascii new file mode 100644 index 00000000..19782167 --- /dev/null +++ b/docs/images/snippets/bsplines/cbdf5a61de10eeb6f23be077cf047ab5.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ t-knot ╮ ╭ knot -t ╮ + │ i │ │ (i+k) │ + N (t) = │ ─────────────────── │ · N (t) + │ ───────────────────── │ · N (t) + i,k │ knot - knot │ i,k-1 │ knot - knot │ i+1,k-1 + ╰ (i+k-1) i ╯ ╰ (i+k) (i+1) ╯ diff --git a/docs/images/snippets/bsplines/ee203de6e554936588eb93adead0a3e5.ascii b/docs/images/snippets/bsplines/ee203de6e554936588eb93adead0a3e5.ascii new file mode 100644 index 00000000..7a9f5f2c --- /dev/null +++ b/docs/images/snippets/bsplines/ee203de6e554936588eb93adead0a3e5.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 1 if t ∈[knot ,knot ) + N (t) = ╡ i i+1 + i,1 ╰ 0 otherwise diff --git a/docs/images/snippets/bsplines/f0bf7d0f1931060cd801ff707f482c16.ascii b/docs/images/snippets/bsplines/f0bf7d0f1931060cd801ff707f482c16.ascii new file mode 100644 index 00000000..e45573bf --- /dev/null +++ b/docs/images/snippets/bsplines/f0bf7d0f1931060cd801ff707f482c16.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + k k-1 k-1 + d (t) = α · d (t) + (1-α ) · d (t) + i i,k i i,k i-1 diff --git a/docs/images/snippets/canonical/2b6478075f2f9f5e5973e01b3b3a0c8b.ascii b/docs/images/snippets/canonical/2b6478075f2f9f5e5973e01b3b3a0c8b.ascii new file mode 100644 index 00000000..71b8dc0a --- /dev/null +++ b/docs/images/snippets/canonical/2b6478075f2f9f5e5973e01b3b3a0c8b.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 S 0 ┐ ┌ x ┐ ┌ x + S · y ┐ + │ 0 1 0 │ · │ y │ = │ y │ + └ 0 0 1 ┘ └ 1 ┘ └ 1 ┘ diff --git a/docs/images/snippets/canonical/464b4ec0b67f248459792752be86d46d.ascii b/docs/images/snippets/canonical/464b4ec0b67f248459792752be86d46d.ascii new file mode 100644 index 00000000..ba69aeb7 --- /dev/null +++ b/docs/images/snippets/canonical/464b4ec0b67f248459792752be86d46d.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 + -x + 3x + y = ────────, { x ≤0 } + 3 diff --git a/docs/images/snippets/canonical/5f174bc5019245f467ca63ae84b90a4b.ascii b/docs/images/snippets/canonical/5f174bc5019245f467ca63ae84b90a4b.ascii new file mode 100644 index 00000000..de7d596d --- /dev/null +++ b/docs/images/snippets/canonical/5f174bc5019245f467ca63ae84b90a4b.ascii @@ -0,0 +1,13 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ x · y x · y ╮ + │ 2 4 2 3 │ + │ x - ──────── / x -──────── │ ╭ x ╮ + │ 4 y 3 y │ │ 43 │ ╭ x · y x · y ╮ + │ 2 2 │ │ │ │ 2 4 2 3 │ +... = │ │ = │ y ╭ y ╮ │, where x = │ x - ──────── \middle / x -──────── │ + │ y ╭ y ╮ ╭ x · y x · y ╮ │ │ 4 │ 3 │ │ 43 │ 4 y 3 y │ + │ 4 │ 3 │ │ 2 4 2 3 │ │ │ ── + x │ 1 - ── │ │ ╰ 2 2 ╯ + │ ── + │ 1 - ── │ · │ x - ──────── / x -──────── │ │ │ y 43 │ y │ │ + │ y │ y │ │ 4 y 3 y │ │ ╰ 2 ╰ 2 ╯ ╯ + ╰ 2 ╰ 2 ╯ ╰ 2 2 ╯ ╯ diff --git a/docs/images/snippets/canonical/674d251590411398d06fb99cba7920f7.ascii b/docs/images/snippets/canonical/674d251590411398d06fb99cba7920f7.ascii new file mode 100644 index 00000000..83453eff --- /dev/null +++ b/docs/images/snippets/canonical/674d251590411398d06fb99cba7920f7.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 + -x + 2x + 3 + y = ────────────, { x ≤1 } + 4 diff --git a/docs/images/snippets/canonical/6959a552f2c90a2bcaa787c23e19f488.ascii b/docs/images/snippets/canonical/6959a552f2c90a2bcaa787c23e19f488.ascii new file mode 100644 index 00000000..04359123 --- /dev/null +++ b/docs/images/snippets/canonical/6959a552f2c90a2bcaa787c23e19f488.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌──────────┐ + │ 2 + ⟍│3(4x - x ) - x + y = ─────────────────, { 0 ≤x ≤1 } + 2 diff --git a/docs/images/snippets/canonical/7ed8b53100737cbf7d87aa6267395d2b.ascii b/docs/images/snippets/canonical/7ed8b53100737cbf7d87aa6267395d2b.ascii new file mode 100644 index 00000000..903d8cc6 --- /dev/null +++ b/docs/images/snippets/canonical/7ed8b53100737cbf7d87aa6267395d2b.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 a ┐ ┌ x ┐ ┌ 1 · x + 0 · y + a · z ┐ ┌ x + a · 1 ┐ ┌ x + a ┐ + │ 0 1 b │ · │ y │ = │ 0 · x + 1 · y + b · z │ = │ y + b · 1 │ = │ y + b │ + └ 0 0 1 ┘ └ z=1 ┘ └ 0 · x + 0 · y + 1 · z ┘ └ 1 · z ┘ └ z=1 ┘ diff --git a/docs/images/snippets/canonical/88e3fae7aeef6d7614290587422542c9.ascii b/docs/images/snippets/canonical/88e3fae7aeef6d7614290587422542c9.ascii new file mode 100644 index 00000000..9b093744 --- /dev/null +++ b/docs/images/snippets/canonical/88e3fae7aeef6d7614290587422542c9.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ x ╮ ╭ x - x · y ╮ y y + │ 43 │ │ 4 2 42 │ 4 3 + ... = │ │, where x = │ ────────────── │, y = ──, and y = ── + │ y + x (1 - y ) │ 43 │ x - x · y │ 42 y 32 y + ╰ 42 43 32 ╯ ╰ 3 2 32 ╯ 2 2 diff --git a/docs/images/snippets/canonical/8e39a9e0c7469b4b45a260dd23bd4c6a.ascii b/docs/images/snippets/canonical/8e39a9e0c7469b4b45a260dd23bd4c6a.ascii new file mode 100644 index 00000000..8a0335a8 --- /dev/null +++ b/docs/images/snippets/canonical/8e39a9e0c7469b4b45a260dd23bd4c6a.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 ┐ + │ ─── 0 0 │ + │ V │ + │ 3x │ + T = │ 1 │ + 3 │ 0 ─── 0 │ + │ V │ + │ 2y │ + └ 0 0 1 ┘ diff --git a/docs/images/snippets/canonical/9420fd9d7a8de30714e23b8f31b3aa6d.ascii b/docs/images/snippets/canonical/9420fd9d7a8de30714e23b8f31b3aa6d.ascii new file mode 100644 index 00000000..90cad65a --- /dev/null +++ b/docs/images/snippets/canonical/9420fd9d7a8de30714e23b8f31b3aa6d.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 0 ┐ + │ 1 - W │ + │ 3y │ + T = │ ─────── 1 0 │ + 4 │ W │ + │ 3x │ + └ 0 0 1 ┘ diff --git a/docs/images/snippets/canonical/ccbfd22cbccf633d182f7f451dee5164.ascii b/docs/images/snippets/canonical/ccbfd22cbccf633d182f7f451dee5164.ascii new file mode 100644 index 00000000..3ff4fb6f --- /dev/null +++ b/docs/images/snippets/canonical/ccbfd22cbccf633d182f7f451dee5164.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ U ┐ + │ 2x │ + │ 1 -─── 0 │ + T = │ U │ + 2 │ 2y │ + │ 0 1 0 │ + └ 0 0 1 ┘ diff --git a/docs/images/snippets/canonical/e61fd49e554a0ffc7d64893c75cd376d.ascii b/docs/images/snippets/canonical/e61fd49e554a0ffc7d64893c75cd376d.ascii new file mode 100644 index 00000000..e6d576a7 --- /dev/null +++ b/docs/images/snippets/canonical/e61fd49e554a0ffc7d64893c75cd376d.ascii @@ -0,0 +1,24 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ (-x +x )(-y +y ) ╮ + │ 1 2 1 4 │ + │ -x + x - ──────────────── │ + │ 1 4 -y +y │ + │ 1 2 │ + │ ─────────────────────────── │ + │ (-x +x )(-y +y ) │ + │ 1 2 1 3 │ + │ -x +x -──────────────── │ + │ 1 3 -y +y │ + mapped = (x) = │ 1 2 │ + 4 y │ ╭ -y +y ╮ ╭ (-x +x )(-y +y ) ╮ │ + │ │ 1 3 │ │ 1 2 1 4 │ │ + │ │ 1 - ────── │ │ -x + x - ──────────────── │ │ + │ (-y +y ) │ -y +y │ │ 1 4 -y +y │ │ + │ 1 4 ╰ 1 2 ╯ ╰ 1 2 ╯ │ + │ ──────── + ────────────────────────────────────────────── │ + │ -y +y (-x +x )(-y +y ) │ + │ 1 2 1 2 1 3 │ + │ -x +x -──────────────── │ + │ 1 3 -y +y │ + ╰ 1 2 ╯ diff --git a/docs/images/snippets/canonical/f855cbf1d73e4bb7bccbbd4721d95f41.ascii b/docs/images/snippets/canonical/f855cbf1d73e4bb7bccbbd4721d95f41.ascii new file mode 100644 index 00000000..91cf90e7 --- /dev/null +++ b/docs/images/snippets/canonical/f855cbf1d73e4bb7bccbbd4721d95f41.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 -P ┐ ┌ 1 · x + 0 · y - P · 1 ┐ ┌ x - P ┐ + │ 1x │ ┌ x ┐ │ 1x │ │ 1x │ + T = │ 0 1 -P │ · │ y │ = │ 0 · x + 1 · y - P · 1 │ = │ y - P │ + 1 │ 1y │ └ 1 ┘ │ 1y │ │ 1y │ + └ 0 0 1 ┘ └ 0 · x + 0 · y + 1 · 1 ┘ └ 1 ┘ diff --git a/docs/images/snippets/catmullconv/00357d2a2168fe313cd0b38d95a1a681.ascii b/docs/images/snippets/catmullconv/00357d2a2168fe313cd0b38d95a1a681.ascii new file mode 100644 index 00000000..cc82ede4 --- /dev/null +++ b/docs/images/snippets/catmullconv/00357d2a2168fe313cd0b38d95a1a681.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ V = P ┐ + │ 1 2 │ + ┌ P ┐ │ V = P │ + │ 1 │ │ 2 3 │ + │ P │ │ P - P │ + │ 2 │ = │ 3 1 │ + │ P │points │ V' = ─────── │point-tangent + │ 3 │ │ 1 2 │ + │ P │ │ P - P │ + └ 4 ┘ │ 4 2 │ + │ V' = ─────── │ + └ 2 2 ┘ diff --git a/docs/images/snippets/catmullconv/157b287d6b74109d8c8b634990ea6549.ascii b/docs/images/snippets/catmullconv/157b287d6b74109d8c8b634990ea6549.ascii new file mode 100644 index 00000000..1653a4a2 --- /dev/null +++ b/docs/images/snippets/catmullconv/157b287d6b74109d8c8b634990ea6549.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 2 │ + │ P -P │ + │ 3 1 │ + ┌ 1 0 0 0 ┐ │ P + ────── │ + = ┌ 2 3 ┐ · │ -3 3 0 0 │ · │ 2 6 · τ │ + └ 1 t t t ┘ │ 3 -6 3 0 │ │ P -P │ + └ -1 3 -3 1 ┘ │ 4 2 │ + │ P - ────── │ + │ 3 6 · τ │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/catmullconv/1cef6bbf7b3d10e8c0aaecfac816cc86.ascii b/docs/images/snippets/catmullconv/1cef6bbf7b3d10e8c0aaecfac816cc86.ascii new file mode 100644 index 00000000..f7b87005 --- /dev/null +++ b/docs/images/snippets/catmullconv/1cef6bbf7b3d10e8c0aaecfac816cc86.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ + │ ── 1 ── 0 │ + │ 6τ 6τ │ = V + │ 1 -1 │ + │ 0 ── 1 ── │ + │ 6τ 6τ │ + └ 0 0 1 0 ┘ diff --git a/docs/images/snippets/catmullconv/1f9fc156aeed9eb092573cd7446593d9.ascii b/docs/images/snippets/catmullconv/1f9fc156aeed9eb092573cd7446593d9.ascii new file mode 100644 index 00000000..11de3347 --- /dev/null +++ b/docs/images/snippets/catmullconv/1f9fc156aeed9eb092573cd7446593d9.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ V ┐ + │ 1 │ + ┌ 1 0 0 0 ┐ │ V │ + CatmullRom(t) = ┌ 2 3 ┐ · │ 0 0 1 0 │ · │ 2 │ + └ 1 t t t ┘ │ -3 3 -2 -1 │ │ V' │ + └ 2 -2 1 1 ┘ │ 1 │ + │ V' │ + └ 2 ┘ diff --git a/docs/images/snippets/catmullconv/211dadbb9d0f6b2e381f18ea3c4d12fb.ascii b/docs/images/snippets/catmullconv/211dadbb9d0f6b2e381f18ea3c4d12fb.ascii new file mode 100644 index 00000000..413c8fed --- /dev/null +++ b/docs/images/snippets/catmullconv/211dadbb9d0f6b2e381f18ea3c4d12fb.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 2 │ + │ P │ + │ 3 │ + ┌ 1 0 0 0 ┐ │ P - P │ + = ┌ 2 3 ┐ · │ 0 0 1 0 │ · │ 3 1 │ + └ 1 t t t ┘ │ -3 3 -2 -1 │ │ ─────── │ + └ 2 -2 1 1 ┘ │ 2τ │ + │ P - P │ + │ 4 2 │ + │ ─────── │ + └ 2τ ┘ diff --git a/docs/images/snippets/catmullconv/4c8684109149b0dc79f5583a5912fcd9.ascii b/docs/images/snippets/catmullconv/4c8684109149b0dc79f5583a5912fcd9.ascii new file mode 100644 index 00000000..e7697682 --- /dev/null +++ b/docs/images/snippets/catmullconv/4c8684109149b0dc79f5583a5912fcd9.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ ┌ P ┐ + │ -1 1 │ │ 1 │ + ┌ 1 0 0 0 ┐ │ ── 1 ── 0 │ │ P │ + = ┌ 2 3 ┐ · │ -3 3 0 0 │ · │ 6τ 6τ │ · │ 2 │ + └ 1 t t t ┘ │ 3 -6 3 0 │ │ 1 -1 │ │ P │ + └ -1 3 -3 1 ┘ │ 0 ── 1 ── │ │ 3 │ + │ 6τ 6τ │ │ P │ + └ 0 0 1 0 ┘ └ 4 ┘ diff --git a/docs/images/snippets/catmullconv/4e0da16710a7339f04dd844c7705423e.ascii b/docs/images/snippets/catmullconv/4e0da16710a7339f04dd844c7705423e.ascii new file mode 100644 index 00000000..94fc8cad --- /dev/null +++ b/docs/images/snippets/catmullconv/4e0da16710a7339f04dd844c7705423e.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ + │ ── 0 ── 0 │ + ┌ 1 0 0 0 ┐ -1 │ 2τ 2τ │ + │ -3 3 0 0 │ · │ 1 1 1 -1 │ = V + │ 3 -6 3 0 │ │ ─ ── - 3 3 - ─ ── │ + └ -1 3 -3 1 ┘ │ τ 2t t 2t │ + │ -1 1 1 1 │ + │ ── 2 - ── ── - 2 ── │ + └ 2t 2τ 2τ 2t ┘ diff --git a/docs/images/snippets/catmullconv/53f216327c0bbcf02b2a331fbf44d389.ascii b/docs/images/snippets/catmullconv/53f216327c0bbcf02b2a331fbf44d389.ascii new file mode 100644 index 00000000..3919d9f2 --- /dev/null +++ b/docs/images/snippets/catmullconv/53f216327c0bbcf02b2a331fbf44d389.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ ┌ P ┐ + │ ── 0 ── 0 │ │ 1 │ + │ 2τ 2τ │ │ P │ + = ┌ 2 3 ┐ · │ 1 1 1 -1 │ · │ 2 │ + └ 1 t t t ┘ │ ─ ── - 3 3 - ─ ── │ │ P │ + │ τ 2t t 2t │ │ 3 │ + │ -1 1 1 1 │ │ P │ + │ ── 2 - ── ── - 2 ── │ └ 4 ┘ + └ 2t 2τ 2τ 2t ┘ diff --git a/docs/images/snippets/catmullconv/574bed6665be06b309b8da722c616a41.ascii b/docs/images/snippets/catmullconv/574bed6665be06b309b8da722c616a41.ascii new file mode 100644 index 00000000..cb112bdd --- /dev/null +++ b/docs/images/snippets/catmullconv/574bed6665be06b309b8da722c616a41.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ ┌ P ┐ + │ ── 0 ── 0 │ │ 1 │ + │ 2τ 2τ │ │ P │ + │ 1 1 1 -1 │ · │ 2 │ + │ ─ ── - 3 3 - ─ ── │ │ P │ + │ τ 2t t 2t │ │ 3 │ + │ -1 1 1 1 │ │ P │ + │ ── 2 - ── ── - 2 ── │ └ 4 ┘ + └ 2t 2τ 2τ 2t ┘ diff --git a/docs/images/snippets/catmullconv/65e589eafae8ff2f39392d8143d2845c.ascii b/docs/images/snippets/catmullconv/65e589eafae8ff2f39392d8143d2845c.ascii new file mode 100644 index 00000000..da62f3a7 --- /dev/null +++ b/docs/images/snippets/catmullconv/65e589eafae8ff2f39392d8143d2845c.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ + │ ── 0 ── 0 │ + │ 2τ 2τ │ ┌ 1 0 0 0 ┐ + │ 1 1 1 -1 │ = │ -3 3 0 0 │ · V + │ ─ ── - 3 3 - ─ ── │ │ 3 -6 3 0 │ + │ τ 2t t 2t │ └ -1 3 -3 1 ┘ + │ -1 1 1 1 │ + │ ── 2 - ── ── - 2 ── │ + └ 2t 2τ 2τ 2t ┘ diff --git a/docs/images/snippets/catmullconv/7bab9dd3da654b05fa065076894e2d82.ascii b/docs/images/snippets/catmullconv/7bab9dd3da654b05fa065076894e2d82.ascii new file mode 100644 index 00000000..b35d0216 --- /dev/null +++ b/docs/images/snippets/catmullconv/7bab9dd3da654b05fa065076894e2d82.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ 0 0 1 0 │ + │ -1 1 │ + T = │ ── 0 ─ 0 │ + │ 2 2 │ + │ -1 1 │ + │ 0 ── 0 ─ │ + └ 2 2 ┘ diff --git a/docs/images/snippets/catmullconv/8a2a00812363fe1a6cfa7f81b48d31d1.ascii b/docs/images/snippets/catmullconv/8a2a00812363fe1a6cfa7f81b48d31d1.ascii new file mode 100644 index 00000000..e4c8099d --- /dev/null +++ b/docs/images/snippets/catmullconv/8a2a00812363fe1a6cfa7f81b48d31d1.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ ┌ P ┐ + │ ── 0 ── 0 │ │ 1 │ + │ 2τ 2τ │ │ P │ + CatmullRom(t) = ┌ 2 3 ┐ · │ 1 1 1 -1 │ · │ 2 │ + └ 1 t t t ┘ │ ─ ── - 3 3 - ─ ── │ │ P │ + │ τ 2t t 2t │ │ 3 │ + │ -1 1 1 1 │ │ P │ + │ ── 2 - ── ── - 2 ── │ └ 4 ┘ + └ 2t 2τ 2τ 2t ┘ diff --git a/docs/images/snippets/catmullconv/8d3a5ca7188f53b914229133b3dbe5fe.ascii b/docs/images/snippets/catmullconv/8d3a5ca7188f53b914229133b3dbe5fe.ascii new file mode 100644 index 00000000..11de3347 --- /dev/null +++ b/docs/images/snippets/catmullconv/8d3a5ca7188f53b914229133b3dbe5fe.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ V ┐ + │ 1 │ + ┌ 1 0 0 0 ┐ │ V │ + CatmullRom(t) = ┌ 2 3 ┐ · │ 0 0 1 0 │ · │ 2 │ + └ 1 t t t ┘ │ -3 3 -2 -1 │ │ V' │ + └ 2 -2 1 1 ┘ │ 1 │ + │ V' │ + └ 2 ┘ diff --git a/docs/images/snippets/catmullconv/8de53f207d68b25854a5f0b924ac6010.ascii b/docs/images/snippets/catmullconv/8de53f207d68b25854a5f0b924ac6010.ascii new file mode 100644 index 00000000..4a82242c --- /dev/null +++ b/docs/images/snippets/catmullconv/8de53f207d68b25854a5f0b924ac6010.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 2 │ + ┌ V ┐ │ P │ ┌ 0 1 0 0 ┐ + │ 1 │ │ 3 │ │ 0 0 1 0 │ + │ V │ │ P - P │ │ -1 1 │ + │ 2 │ = │ 3 1 │ ,\ T = │ ── 0 ── 0 │ + │ V' │ │ ─────── │ │ 2τ 2τ │ + │ 1 │ │ 2τ │ │ -1 1 │ + │ V' │ │ P - P │ │ 0 ── 0 ── │ + └ 2 ┘ │ 4 2 │ └ 2τ 2τ ┘ + │ ─────── │ + └ 2τ ┘ diff --git a/docs/images/snippets/catmullconv/917b176a45959b026c56f81999505dc7.ascii b/docs/images/snippets/catmullconv/917b176a45959b026c56f81999505dc7.ascii new file mode 100644 index 00000000..d309e7a2 --- /dev/null +++ b/docs/images/snippets/catmullconv/917b176a45959b026c56f81999505dc7.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ + │ ── 0 ── 0 │ + ┌ 1 0 0 0 ┐ -1 │ 2τ 2τ │ ┌ 1 0 0 0 ┐ -1 ┌ 1 0 0 0 ┐ + │ -3 3 0 0 │ · │ 1 1 1 -1 │ = │ -3 3 0 0 │ · │ -3 3 0 0 │ · V + │ 3 -6 3 0 │ │ ─ ── - 3 3 - ─ ── │ │ 3 -6 3 0 │ │ 3 -6 3 0 │ + └ -1 3 -3 1 ┘ │ τ 2t t 2t │ └ -1 3 -3 1 ┘ └ -1 3 -3 1 ┘ + │ -1 1 1 1 │ + │ ── 2 - ── ── - 2 ── │ + └ 2t 2τ 2τ 2t ┘ diff --git a/docs/images/snippets/catmullconv/9593c057c84ebf9beb70fd57a11c7e12.ascii b/docs/images/snippets/catmullconv/9593c057c84ebf9beb70fd57a11c7e12.ascii new file mode 100644 index 00000000..c9d316c4 --- /dev/null +++ b/docs/images/snippets/catmullconv/9593c057c84ebf9beb70fd57a11c7e12.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ ┌ P + 6(P - P ) ┐ + │ 1 │ │ 4 1 2 │ + │ P │ │ P │ + │ 2 │ \Rightarrow │ 1 │ + │ P │ Bézier │ P │CatmullRom + │ 3 │ │ 4 │ + │ P │ │ P + 6(P - P ) │ + └ 4 ┘ └ 1 4 3 ┘ diff --git a/docs/images/snippets/catmullconv/a55773fdcdfd99947acc4f86ad2d4a3d.ascii b/docs/images/snippets/catmullconv/a55773fdcdfd99947acc4f86ad2d4a3d.ascii new file mode 100644 index 00000000..854a3b1d --- /dev/null +++ b/docs/images/snippets/catmullconv/a55773fdcdfd99947acc4f86ad2d4a3d.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 2 │ + ┌ P ┐ │ P │ ┌ 0 · P1 + 1 · P2 + 0 · P3 + 0 · P4 ┐ ┌ 0 1 0 0 ┐ ┌ P ┐ + │ 1 │ │ 3 │ │ 0 · P1 + 0 · P2 + 1 · P3 + 0 · P4 │ │ 0 0 1 0 │ │ 1 │ + │ P │ │ P - P │ │ -1 1 │ │ -1 1 │ │ P │ + T · │ 2 │ = │ 3 1 │ = │ ── · P1 + 0 · P2 + ─ · P3 + 0 · P4 │ = │ ── 0 ─ 0 │ · │ 2 │ + │ P │ │ ─────── │ │ 2 2 │ │ 2 2 │ │ P │ + │ 3 │ │ 2 │ │ -1 1 │ │ -1 1 │ │ 3 │ + │ P │ │ P - P │ │ 0 · P1 ── · P2 + 0 · P3 + ─ · P4 │ │ 0 ── 0 ─ │ │ P │ + └ 4 ┘ │ 4 2 │ └ 2 2 ┘ └ 2 2 ┘ └ 4 ┘ + │ ─────── │ + └ 2 ┘ diff --git a/docs/images/snippets/catmullconv/a8158b35ec221cccff51a53cdc7f440b.ascii b/docs/images/snippets/catmullconv/a8158b35ec221cccff51a53cdc7f440b.ascii new file mode 100644 index 00000000..68ecf8b9 --- /dev/null +++ b/docs/images/snippets/catmullconv/a8158b35ec221cccff51a53cdc7f440b.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ ┌ P ┐ + │ 0 0 1 0 │ │ 1 │ + ┌ 1 0 0 0 ┐ │ -1 1 │ │ P │ + = ┌ 2 3 ┐ · │ 0 0 1 0 │ · │ ── 0 ── 0 │ · │ 2 │ + └ 1 t t t ┘ │ -3 3 -2 -1 │ │ 2τ 2τ │ │ P │ + └ 2 -2 1 1 ┘ │ -1 1 │ │ 3 │ + │ 0 ── 0 ── │ │ P │ + └ 2τ 2τ ┘ └ 4 ┘ diff --git a/docs/images/snippets/catmullconv/b59ff8d654e65df4c874901983208893.ascii b/docs/images/snippets/catmullconv/b59ff8d654e65df4c874901983208893.ascii new file mode 100644 index 00000000..a2f1f45e --- /dev/null +++ b/docs/images/snippets/catmullconv/b59ff8d654e65df4c874901983208893.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ + │ -1 1 │ ┌ P ┐ ┌ P ┐ + │ ── 0 ── 0 │ │ 1 │ │ 1 │ + │ 2τ 2τ │ │ P │ ┌ 1 0 0 0 ┐ │ P │ + │ 1 1 1 -1 │ · │ 2 │ = │ -3 3 0 0 │ · V · │ 2 │ + │ ─ ── - 3 3 - ─ ── │ │ P │ │ 3 -6 3 0 │ │ P │ + │ τ 2t t 2t │ │ 3 │ └ -1 3 -3 1 ┘ │ 3 │ + │ -1 1 1 1 │ │ P │ │ P │ + │ ── 2 - ── ── - 2 ── │ └ 4 ┘ └ 4 ┘ + └ 2t 2τ 2τ 2t ┘ diff --git a/docs/images/snippets/catmullconv/b94a4dafc12ba7e4fbf3aff924f55464.ascii b/docs/images/snippets/catmullconv/b94a4dafc12ba7e4fbf3aff924f55464.ascii new file mode 100644 index 00000000..f9ff95ba --- /dev/null +++ b/docs/images/snippets/catmullconv/b94a4dafc12ba7e4fbf3aff924f55464.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 2 │ + ┌ V ┐ ┌ P ┐ │ P │ + │ 1 │ │ 1 │ │ 3 │ + │ V │ │ P │ │ P - P │ + │ 2 │ = T · │ 2 │ = │ 3 1 │ + │ V' │ │ P │ │ ─────── │ + │ 1 │ │ 3 │ │ 2 │ + │ V' │ │ P │ │ P - P │ + └ 2 ┘ └ 4 ┘ │ 4 2 │ + │ ─────── │ + └ 2 ┘ diff --git a/docs/images/snippets/catmullconv/c0e30b49fbfce6f6b3c81eaa6ca5154f.ascii b/docs/images/snippets/catmullconv/c0e30b49fbfce6f6b3c81eaa6ca5154f.ascii new file mode 100644 index 00000000..f1c2493f --- /dev/null +++ b/docs/images/snippets/catmullconv/c0e30b49fbfce6f6b3c81eaa6ca5154f.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 2 │ + ┌ P ┐ │ P -P │ + │ 1 │ │ 3 1 │ + │ P │ │ P + ────── │ + │ 2 │ \Rightarrow │ 2 6 · τ │ + │ P │CatmullRom │ P -P │ Bézier + │ 3 │ │ 4 2 │ + │ P │ │ P - ────── │ + └ 4 ┘ │ 3 6 · τ │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/catmullconv/c1f8861583b4176a9b607aa6a05f9356.ascii b/docs/images/snippets/catmullconv/c1f8861583b4176a9b607aa6a05f9356.ascii new file mode 100644 index 00000000..b1b40ccd --- /dev/null +++ b/docs/images/snippets/catmullconv/c1f8861583b4176a9b607aa6a05f9356.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 1 │ + ┌ 1 0 0 0 ┐ │ P │ + Bézier(t) = ┌ 2 3 ┐ · │ -3 3 0 0 │ · │ 2 │ + └ 1 t t t ┘ │ 3 -6 3 0 │ │ P │ + └ -1 3 -3 1 ┘ │ 3 │ + │ P │ + └ 4 ┘ diff --git a/docs/images/snippets/catmullconv/d09e7466c267614c89ead28d6a900ba1.ascii b/docs/images/snippets/catmullconv/d09e7466c267614c89ead28d6a900ba1.ascii new file mode 100644 index 00000000..ed131d68 --- /dev/null +++ b/docs/images/snippets/catmullconv/d09e7466c267614c89ead28d6a900ba1.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ ┌ P ┐ + │ 1 │ │ 1 │ + │ P │ │ P │ + │ 2 │ \Rightarrow │ 4 │ + │ P │ Bézier │ P + 3(P - P ) │CatmullRom + │ 3 │ │ 4 1 2 │ + │ P │ │ P + 3(P - P ) │ + └ 4 ┘ └ 1 4 3 ┘ diff --git a/docs/images/snippets/catmullconv/defc6fa4b51fa3c1945d15449f0f392d.ascii b/docs/images/snippets/catmullconv/defc6fa4b51fa3c1945d15449f0f392d.ascii new file mode 100644 index 00000000..5989deb7 --- /dev/null +++ b/docs/images/snippets/catmullconv/defc6fa4b51fa3c1945d15449f0f392d.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 0 0 ┐ ┌ P ┐ + │ 0 0 1 0 │ │ 1 │ + ┌ 1 0 0 0 ┐ │ -1 1 │ │ P │ + CatmullRom(t) = ┌ 2 3 ┐ · │ 0 0 1 0 │ · │ ── 0 ── 0 │ · │ 2 │ + └ 1 t t t ┘ │ -3 3 -2 -1 │ │ 2τ 2τ │ │ P │ + └ 2 -2 1 1 ┘ │ -1 1 │ │ 3 │ + │ 0 ── 0 ── │ │ P │ + └ 2τ 2τ ┘ └ 4 ┘ diff --git a/docs/images/snippets/catmullconv/fe2e6fd487df224b2f55a601898ce333.ascii b/docs/images/snippets/catmullconv/fe2e6fd487df224b2f55a601898ce333.ascii new file mode 100644 index 00000000..0594ba9a --- /dev/null +++ b/docs/images/snippets/catmullconv/fe2e6fd487df224b2f55a601898ce333.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 1 │ + ┌ 1 0 0 0 ┐ │ P │ + │ -3 3 0 0 │ · │ 2 │ + │ 3 -6 3 0 │ │ P │ + └ -1 3 -3 1 ┘ │ 3 │ + │ P │ + └ 4 ┘ diff --git a/docs/images/snippets/circles/06369b00338310df0a810c592485aa0a.ascii b/docs/images/snippets/circles/06369b00338310df0a810c592485aa0a.ascii new file mode 100644 index 00000000..c333eaa0 --- /dev/null +++ b/docs/images/snippets/circles/06369b00338310df0a810c592485aa0a.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + cos(φ)-1 + b = ──────── + sin(φ) diff --git a/docs/images/snippets/circles/1829e42ea956ee4df0e45d9ac5334ef7.ascii b/docs/images/snippets/circles/1829e42ea956ee4df0e45d9ac5334ef7.ascii new file mode 100644 index 00000000..2a326654 --- /dev/null +++ b/docs/images/snippets/circles/1829e42ea956ee4df0e45d9ac5334ef7.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 1 = cos(φ) + b · -sin(φ) → \ 1 - cos(φ) = -b · sin(φ) → \ -1 + cos(φ) = b · sin(φ) diff --git a/docs/images/snippets/circles/5a23f3bc298c85540c6dd18e304d9224.ascii b/docs/images/snippets/circles/5a23f3bc298c85540c6dd18e304d9224.ascii new file mode 100644 index 00000000..26ae6031 --- /dev/null +++ b/docs/images/snippets/circles/5a23f3bc298c85540c6dd18e304d9224.ascii @@ -0,0 +1,17 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + a= sin(φ) + b · cos(φ) + -1 + cos(φ) + ..= sin(φ) + ─────────── · cos(φ) + sin(φ) + 2 + -cos(φ) + cos (φ) + ..= sin(φ) + ───────────────── + sin(φ) + 2 2 + sin (φ) + cos (φ) - cos(φ) + ..= ────────────────────────── + sin(φ) + 1 - cos(φ) + a= ────────── + sin(φ) diff --git a/docs/images/snippets/circles/7ab3da0922477af4cc09f5852100976b.ascii b/docs/images/snippets/circles/7ab3da0922477af4cc09f5852100976b.ascii new file mode 100644 index 00000000..46a53bf1 --- /dev/null +++ b/docs/images/snippets/circles/7ab3da0922477af4cc09f5852100976b.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + S = \begin{pmatrix} 1 + 0 \end{pmatrix} , \ E = \begin{pmatrix} cos(φ) + sin(φ) \end{pmatrix} diff --git a/docs/images/snippets/circles/8237af1396bb567d70c8b5e4dd7f8115.ascii b/docs/images/snippets/circles/8237af1396bb567d70c8b5e4dd7f8115.ascii new file mode 100644 index 00000000..3a98c249 --- /dev/null +++ b/docs/images/snippets/circles/8237af1396bb567d70c8b5e4dd7f8115.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ C = 1 = cos(φ) + b · -sin(φ) + ╡ x + │ C = a = sin(φ) + b · cos(φ) + ╰ y diff --git a/docs/images/snippets/circles/8b4e1d0a62380ed011f27c645ed13b28.ascii b/docs/images/snippets/circles/8b4e1d0a62380ed011f27c645ed13b28.ascii new file mode 100644 index 00000000..32b2c66c --- /dev/null +++ b/docs/images/snippets/circles/8b4e1d0a62380ed011f27c645ed13b28.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + φ φ + P = cos(─) , \ P = sin(─) + x 2 y 2 diff --git a/docs/images/snippets/circles/942c90bc8311e49d94059b3127fc78d5.ascii b/docs/images/snippets/circles/942c90bc8311e49d94059b3127fc78d5.ascii new file mode 100644 index 00000000..d2d9edf9 --- /dev/null +++ b/docs/images/snippets/circles/942c90bc8311e49d94059b3127fc78d5.ascii @@ -0,0 +1,15 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 1 φ 4╭ φ ╮ + d (φ)= T - P = ─(3 + cos(φ)) - cos(─) = 2sin │ ─ │ , + x x x 4 2 ╰ 4 ╯ + 1╭ ╭ φ ╮ ╮ φ + d (φ)= T - P = ─│ 2tan│ ─ │ + sin(φ) │ - sin(─) , + y y y 4╰ ╰ 2 ╯ ╯ 2 + ⇓ + ┌───────┐ ┌───────┐ + │ 2 2 4 φ │ 1 + d(φ)= │d + d = ... = 2sin (─) │─────── + ⟍│ x y 4 │ 2 φ + │cos (─) + ⟍│ 2 diff --git a/docs/images/snippets/circles/986ae9104e0bc52e95689ae7ae4504db.ascii b/docs/images/snippets/circles/986ae9104e0bc52e95689ae7ae4504db.ascii new file mode 100644 index 00000000..6bbf31e1 --- /dev/null +++ b/docs/images/snippets/circles/986ae9104e0bc52e95689ae7ae4504db.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 1 + │ T = ─(3 + cos(φ)) + ╡ x 4 + │ 1╭ 2-2cos(φ) ╮ 1╭ ╭ φ ╮ ╮ + │ T = ─│ ───────── + sin(φ) │ = ─│ 2tan│ ─ │ + sin(φ) │ + ╰ y 4╰ sin(φ) ╯ 4╰ ╰ 2 ╯ ╯ diff --git a/docs/images/snippets/circles/a04bd1558a76e60b8ca6e1fe4fa38c00.ascii b/docs/images/snippets/circles/a04bd1558a76e60b8ca6e1fe4fa38c00.ascii new file mode 100644 index 00000000..b443cc9d --- /dev/null +++ b/docs/images/snippets/circles/a04bd1558a76e60b8ca6e1fe4fa38c00.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 1 2 1 1 + T = ─S + ─C + ─E = ─(S + 2C + E) + 4 4 4 4 diff --git a/docs/images/snippets/circles/d4bfb47b623c968e3231566c9705c6c4.ascii b/docs/images/snippets/circles/d4bfb47b623c968e3231566c9705c6c4.ascii new file mode 100644 index 00000000..dd503155 --- /dev/null +++ b/docs/images/snippets/circles/d4bfb47b623c968e3231566c9705c6c4.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C = S + a · \begin{pmatrix} 0 + 1 \end{pmatrix} , \ C = E + b · \begin{pmatrix} -sin(φ) + cos(φ) \end{pmatrix} diff --git a/docs/images/snippets/circles/f9d15462df31186feef8c3d53c0f6163.ascii b/docs/images/snippets/circles/f9d15462df31186feef8c3d53c0f6163.ascii new file mode 100644 index 00000000..5fef99cf --- /dev/null +++ b/docs/images/snippets/circles/f9d15462df31186feef8c3d53c0f6163.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ ┌─────────────┐ ╮ + │ │ ┌──────┐ │ + │ ⟍│2+ε-⟍│ε(2+ε) │ + φ = 4 · arccos │ ──────────────── │ + │ ┌─┐ │ + ╰ ⟍│2 ╯ diff --git a/docs/images/snippets/circles_cubic/046e0bec7cc3d8a502b2f76b4722be2d.ascii b/docs/images/snippets/circles_cubic/046e0bec7cc3d8a502b2f76b4722be2d.ascii new file mode 100644 index 00000000..d221682d --- /dev/null +++ b/docs/images/snippets/circles_cubic/046e0bec7cc3d8a502b2f76b4722be2d.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 4 + │ \vecv = {C,A} = ─ · (B - C ) + ╡ x x 3 x x + │ 4 + │ \vecv = {C,A} = ─ · (B - C ) + ╰ y y 3 y y diff --git a/docs/images/snippets/circles_cubic/0b4c1e8f1f7a9c1292787f127ddb1624.ascii b/docs/images/snippets/circles_cubic/0b4c1e8f1f7a9c1292787f127ddb1624.ascii new file mode 100644 index 00000000..7902bfe6 --- /dev/null +++ b/docs/images/snippets/circles_cubic/0b4c1e8f1f7a9c1292787f127ddb1624.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C = S + a · \begin{pmatrix} 0 + 1 + 1 \end{pmatrix} diff --git a/docs/images/snippets/circles_cubic/2ba4e0e2dbbdf3ea7dbd9cff3e049d0d.ascii b/docs/images/snippets/circles_cubic/2ba4e0e2dbbdf3ea7dbd9cff3e049d0d.ascii new file mode 100644 index 00000000..116616fe --- /dev/null +++ b/docs/images/snippets/circles_cubic/2ba4e0e2dbbdf3ea7dbd9cff3e049d0d.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ ╭ φ ╮ 2╭ φ ╮ + │ B - C = cos│ ─ │ - cos │ ─ │ + ╡ x x ╰ 2 ╯ ╰ 2 ╯ + │ ╭ φ ╮ φ ╭ φ ╮ ╭ φ ╮ sin(φ) + │ B - C = sin│ ─ │ - cos(─) · sin│ ─ │ = sin│ ─ │ - ────── + ╰ y y ╰ 2 ╯ 2 ╰ 2 ╯ ╰ 2 ╯ 2 diff --git a/docs/images/snippets/circles_cubic/2d9df7ddd2aa223a951016b93d9620c2.ascii b/docs/images/snippets/circles_cubic/2d9df7ddd2aa223a951016b93d9620c2.ascii new file mode 100644 index 00000000..f0e6296a --- /dev/null +++ b/docs/images/snippets/circles_cubic/2d9df7ddd2aa223a951016b93d9620c2.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + S = (1, 0) , \ C = (1, 0.55228) , \ C = (0.55228 , 1) , \ E = (0, 1) + 1 2 diff --git a/docs/images/snippets/circles_cubic/329dc34299d2fdb3c5f17828e3a23da0.ascii b/docs/images/snippets/circles_cubic/329dc34299d2fdb3c5f17828e3a23da0.ascii new file mode 100644 index 00000000..62d79a9f --- /dev/null +++ b/docs/images/snippets/circles_cubic/329dc34299d2fdb3c5f17828e3a23da0.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 4 ╭ φ ╮ + C = ┌ cos(φ) + f · sin(φ) ┐, with f = ─ tan │ ─ │ + 2 └ sin(φ) - f · cos(φ) ┘ 3 ╰ 4 ╯ diff --git a/docs/images/snippets/circles_cubic/38b58b3c759b9bf340a3cf3de8bc599e.ascii b/docs/images/snippets/circles_cubic/38b58b3c759b9bf340a3cf3de8bc599e.ascii new file mode 100644 index 00000000..f8b6ebea --- /dev/null +++ b/docs/images/snippets/circles_cubic/38b58b3c759b9bf340a3cf3de8bc599e.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 4 ╭ φ ╮ + C = ┌ 1 ┐, with f = ─ tan │ ─ │ + 1 └ f ┘ 3 ╰ 4 ╯ diff --git a/docs/images/snippets/circles_cubic/459c037fb92685566d624f81a298e9c8.ascii b/docs/images/snippets/circles_cubic/459c037fb92685566d624f81a298e9c8.ascii new file mode 100644 index 00000000..2c16d5aa --- /dev/null +++ b/docs/images/snippets/circles_cubic/459c037fb92685566d624f81a298e9c8.ascii @@ -0,0 +1,18 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + E' = -sin(φ) , + x + E' = cos(φ) , + y + ┌────────────────────┐ + │ 2 2 + ||E'|| = ⟍│(-sin(φ)) + cos (φ) = 1 , + + ╭ E ' + │ x 4 ╭ φ ╮ + │ C x = E - C · ────── = cos(φ) + C · sin(φ) = cos(φ) + ─ tan │ ─ │ · sin(φ) + ╡ 2 x 1y ||E'|| 1y 3 ╰ 4 ╯ + │ E ' + │ y 4 ╭ φ ╮ + │ C y = E - C · ────── = sin(φ) - C · cos(φ) = sin(φ) - ─ tan │ ─ │ · cos(φ) + ╰ 2 y 1y ||E'|| 1y 3 ╰ 4 ╯ diff --git a/docs/images/snippets/circles_cubic/6a14e5a71dd9e0cefe158640eabb8696.ascii b/docs/images/snippets/circles_cubic/6a14e5a71dd9e0cefe158640eabb8696.ascii new file mode 100644 index 00000000..c3569488 --- /dev/null +++ b/docs/images/snippets/circles_cubic/6a14e5a71dd9e0cefe158640eabb8696.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ ┌─┐ ╮ ╭ ┌─┐ ╮ + │ ⟍│2 -1 │ │ ⟍│2 -1 │ + S = (1, 0) , \ C = │ 1, 4 ────── │ , \ C = │ 4 ────── , 1 │ , \ E = (0, 1) + 1 ╰ 3 ╯ 2 ╰ 3 ╯ diff --git a/docs/images/snippets/circles_cubic/750e2c874fb58237608ebade1589fccc.ascii b/docs/images/snippets/circles_cubic/750e2c874fb58237608ebade1589fccc.ascii new file mode 100644 index 00000000..73dc9973 --- /dev/null +++ b/docs/images/snippets/circles_cubic/750e2c874fb58237608ebade1589fccc.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 1 ╮ 1 4 + ||A,C|| = d + d = d + d · ratio │ ─ │ = d + ─d = ─d + 2 1 2 2 3 ╰ 2 ╯ 2 3 2 3 2 diff --git a/docs/images/snippets/circles_cubic/8b4e1d0a62380ed011f27c645ed13b28.ascii b/docs/images/snippets/circles_cubic/8b4e1d0a62380ed011f27c645ed13b28.ascii new file mode 100644 index 00000000..32b2c66c --- /dev/null +++ b/docs/images/snippets/circles_cubic/8b4e1d0a62380ed011f27c645ed13b28.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + φ φ + P = cos(─) , \ P = sin(─) + x 2 y 2 diff --git a/docs/images/snippets/circles_cubic/bc884416145a846cebddc8c5d13f147f.ascii b/docs/images/snippets/circles_cubic/bc884416145a846cebddc8c5d13f147f.ascii new file mode 100644 index 00000000..6c2cd4ca --- /dev/null +++ b/docs/images/snippets/circles_cubic/bc884416145a846cebddc8c5d13f147f.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + φ + l = cos(─) , + 2 + ╭ ╭ φ ╮ 2╭ φ ╮ + │ C = l · cos│ ─ │ = cos │ ─ │ , + ╡ x ╰ 2 ╯ ╰ 2 ╯ + │ ╭ φ ╮ φ ╭ φ ╮ + │ C = l · sin│ ─ │ = cos(─) · sin│ ─ │ , + ╰ y ╰ 2 ╯ 2 ╰ 2 ╯ diff --git a/docs/images/snippets/circles_cubic/d28eb43a1b34befb7659dcdfb3a9e718.ascii b/docs/images/snippets/circles_cubic/d28eb43a1b34befb7659dcdfb3a9e718.ascii new file mode 100644 index 00000000..0ec63018 --- /dev/null +++ b/docs/images/snippets/circles_cubic/d28eb43a1b34befb7659dcdfb3a9e718.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C = E + a · \begin{pmatrix} sin(φ) + 2 + cos(φ) \end{pmatrix} diff --git a/docs/images/snippets/circles_cubic/eeff3b36af960053cb4eb692abe36cd8.ascii b/docs/images/snippets/circles_cubic/eeff3b36af960053cb4eb692abe36cd8.ascii new file mode 100644 index 00000000..46a53bf1 --- /dev/null +++ b/docs/images/snippets/circles_cubic/eeff3b36af960053cb4eb692abe36cd8.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + S = \begin{pmatrix} 1 + 0 \end{pmatrix} , \ E = \begin{pmatrix} cos(φ) + sin(φ) \end{pmatrix} diff --git a/docs/images/snippets/circles_cubic/fa5d308b0b50400fbae1411f390bc7ce.ascii b/docs/images/snippets/circles_cubic/fa5d308b0b50400fbae1411f390bc7ce.ascii new file mode 100644 index 00000000..1a851d76 --- /dev/null +++ b/docs/images/snippets/circles_cubic/fa5d308b0b50400fbae1411f390bc7ce.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ C = 1 + │ 1x + │ ┌───────────────┐ + │ │ 2 2 + ╡ │\vecv + \vecv + │ d ⟍│ x y 4 ╭ φ ╮ + │ C = ──────── = ────────────────── = ─ tan │ ─ │ + │ 1y ╭ φ ╮ ╭ φ ╮ 3 ╰ 4 ╯ + │ sin│ ─ │ sin│ ─ │ + ╰ ╰ 2 ╯ ╰ 2 ╯ diff --git a/docs/images/snippets/control/20b0be6397fbd726298de6ec70a8544b.ascii b/docs/images/snippets/control/20b0be6397fbd726298de6ec70a8544b.ascii new file mode 100644 index 00000000..ed26833c --- /dev/null +++ b/docs/images/snippets/control/20b0be6397fbd726298de6ec70a8544b.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ 3 2 2 3 + ╡ x = \colordarkred110 · (1-t) + \colordarkgreen25 · 3 · (1-t) · t + \colordarkblue210 · 3 · (1-t) · t + \coloramber210 · t + │ 3 2 2 3 + ╰ y = \colordarkred150 · (1-t) + \colordarkgreen190 · 3 · (1-t) · t + \colordarkblue250 · 3 · (1-t) · t + \coloramber30 · t diff --git a/docs/images/snippets/control/9df7dc66b51db8e3046e1f359874c38e.ascii b/docs/images/snippets/control/9df7dc66b51db8e3046e1f359874c38e.ascii new file mode 100644 index 00000000..bc0af7b5 --- /dev/null +++ b/docs/images/snippets/control/9df7dc66b51db8e3046e1f359874c38e.ascii @@ -0,0 +1,5 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + __ n n-i i + Bézier(n,t) = ❯ \underset二項係数部分の項\underbrace\binomni · \ \underset多項式部分の項\underbrace(1-t) · t · \ \underset重み\underbracew + ‾‾ i=0 i diff --git a/docs/images/snippets/control/b58fb122c5c8159938182c185f287142.ascii b/docs/images/snippets/control/b58fb122c5c8159938182c185f287142.ascii new file mode 100644 index 00000000..596ece8d --- /dev/null +++ b/docs/images/snippets/control/b58fb122c5c8159938182c185f287142.ascii @@ -0,0 +1,7 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n n-i i +Bézier(n,t) = ❯ \undersetbinomial term\underbrace\binomni · \ \undersetpolynomial term\underbrace(1-t) · t · \ + ‾‾ i=0 + \undersetweight\underbracew + i diff --git a/docs/images/snippets/curvature/060acd6ff0a050fe4d98a7802a2b3a3f.ascii b/docs/images/snippets/curvature/060acd6ff0a050fe4d98a7802a2b3a3f.ascii new file mode 100644 index 00000000..b2eb70f2 --- /dev/null +++ b/docs/images/snippets/curvature/060acd6ff0a050fe4d98a7802a2b3a3f.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + x'y'' - x''y' + \kappa = ───────────── + 3 + ─ + 2 2 2 + (x' +y' ) diff --git a/docs/images/snippets/curvature/561ab3a938d655550de0abf458ac2494.ascii b/docs/images/snippets/curvature/561ab3a938d655550de0abf458ac2494.ascii new file mode 100644 index 00000000..75180c28 --- /dev/null +++ b/docs/images/snippets/curvature/561ab3a938d655550de0abf458ac2494.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 1 + R(t) = ───────── + \kappa(t) diff --git a/docs/images/snippets/curvature/afd8cb8b0fe291ff703752c1c9cc33d4.ascii b/docs/images/snippets/curvature/afd8cb8b0fe291ff703752c1c9cc33d4.ascii new file mode 100644 index 00000000..af5474f0 --- /dev/null +++ b/docs/images/snippets/curvature/afd8cb8b0fe291ff703752c1c9cc33d4.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + B '(t)B ''(t) - B ''(t)B '(t) + x y x y + \kappa(t) = ───────────────────────────── + 3 + ─ + 2 2 2 + (B '(t) +B '(t) ) + x y diff --git a/docs/images/snippets/curvefitting/06605e008956609e8844ef95697c9096.ascii b/docs/images/snippets/curvefitting/06605e008956609e8844ef95697c9096.ascii new file mode 100644 index 00000000..5650f150 --- /dev/null +++ b/docs/images/snippets/curvefitting/06605e008956609e8844ef95697c9096.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 2 3 + B =a(1-t) + 3b(1-t) t + 3c(1-t)t + dt + cubic diff --git a/docs/images/snippets/curvefitting/2f82371abb7835f9b9d440dc5dd151a8.ascii b/docs/images/snippets/curvefitting/2f82371abb7835f9b9d440dc5dd151a8.ascii new file mode 100644 index 00000000..5baf680d --- /dev/null +++ b/docs/images/snippets/curvefitting/2f82371abb7835f9b9d440dc5dd151a8.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ d = 0 + D = ┌ d d ... d ┐, where ╡ 1 + └ 1 2 n ┘ │ d = d + length(p , p ) + ╰ i i-1 i-1 i diff --git a/docs/images/snippets/curvefitting/31d659cbc72bf304abf4c9a75b6b81de.ascii b/docs/images/snippets/curvefitting/31d659cbc72bf304abf4c9a75b6b81de.ascii new file mode 100644 index 00000000..63badfeb --- /dev/null +++ b/docs/images/snippets/curvefitting/31d659cbc72bf304abf4c9a75b6b81de.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 2 + B = a (1-t) + 2 b (1-t) t + c t + quadratic + 2 2 2 + = a - 2at + at + 2bt - 2bt + ct diff --git a/docs/images/snippets/curvefitting/38bb81bdd3eaa72c2336514187aa374b.ascii b/docs/images/snippets/curvefitting/38bb81bdd3eaa72c2336514187aa374b.ascii new file mode 100644 index 00000000..623a3fec --- /dev/null +++ b/docs/images/snippets/curvefitting/38bb81bdd3eaa72c2336514187aa374b.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 ... 0 0 ┐ + │ n-2 n-1 │ + │ 1 s s s │ + │ 2 2 2 │ + 𝕋 = │ \vdots ... \vdots │ + │ n-2 n-1 │ + │ 1 s s s │ + │ n-1 n-1 n-1 │ + └ 1 1 ... 1 1 ┘ diff --git a/docs/images/snippets/curvefitting/409d10c3005b0c93489d72a5dba692d7.ascii b/docs/images/snippets/curvefitting/409d10c3005b0c93489d72a5dba692d7.ascii new file mode 100644 index 00000000..f44cabd1 --- /dev/null +++ b/docs/images/snippets/curvefitting/409d10c3005b0c93489d72a5dba692d7.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 0 0 0 ┐ ┌ a ┐ + │ -4 4 0 0 0 │ │ b │ + B = T · M · C = ┌ 2 3 4 ┐ · │ 6 -12 6 0 0 │ · │ c │ + quartic └ 1 t t t t ┘ │ -4 12 -12 4 0 │ │ d │ + └ 1 -4 6 -4 1 ┘ └ e ┘ diff --git a/docs/images/snippets/curvefitting/464dbfb5adb6233108053dfac6fa4fe5.ascii b/docs/images/snippets/curvefitting/464dbfb5adb6233108053dfac6fa4fe5.ascii new file mode 100644 index 00000000..0bb85076 --- /dev/null +++ b/docs/images/snippets/curvefitting/464dbfb5adb6233108053dfac6fa4fe5.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 + E(C) = (p - Bézier(s )) + i i i diff --git a/docs/images/snippets/curvefitting/4dd55c228a26bb50da912a45e8721024.ascii b/docs/images/snippets/curvefitting/4dd55c228a26bb50da912a45e8721024.ascii new file mode 100644 index 00000000..87ecd45d --- /dev/null +++ b/docs/images/snippets/curvefitting/4dd55c228a26bb50da912a45e8721024.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 0 1 n-2 n-1 ┐ + │ s s ... s s │ + │ 1 1 1 1 │ + │ │ + 𝕋 = │ \vdots ... \vdots │ + │ │ + │ 0 1 n-2 n-1 │ + │ s s ... s s │ + └ n n n n ┘ diff --git a/docs/images/snippets/curvefitting/505ab1ada6a187e9ba392d19739ac2c5.ascii b/docs/images/snippets/curvefitting/505ab1ada6a187e9ba392d19739ac2c5.ascii new file mode 100644 index 00000000..f3555f4c --- /dev/null +++ b/docs/images/snippets/curvefitting/505ab1ada6a187e9ba392d19739ac2c5.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ a 0 0 ┐ ┌ 1 0 0 ┐ ┌ a ┐ + B = T · M · C = ┌ 2 ┐ · │ -2a 2b 0 │ = ┌ 2 ┐ · │ -2 2 0 │ · │ b │ + quadratic └ 1 t t ┘ └ a -2b c ┘ └ 1 t t ┘ └ 1 -2 1 ┘ └ c ┘ diff --git a/docs/images/snippets/curvefitting/6f734d319a1cfe0de76574a65abb07e1.ascii b/docs/images/snippets/curvefitting/6f734d319a1cfe0de76574a65abb07e1.ascii new file mode 100644 index 00000000..b71ce883 --- /dev/null +++ b/docs/images/snippets/curvefitting/6f734d319a1cfe0de76574a65abb07e1.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ s = 0 + │ 1 + S = ┌ s s ... s ┐, where ╡ s = d / d + └ 1 2 n ┘ │ i i n + │ s = 1 + ╰ n diff --git a/docs/images/snippets/curvefitting/7b0199bb515d2754c03d8f796b29febf.ascii b/docs/images/snippets/curvefitting/7b0199bb515d2754c03d8f796b29febf.ascii new file mode 100644 index 00000000..86355628 --- /dev/null +++ b/docs/images/snippets/curvefitting/7b0199bb515d2754c03d8f796b29febf.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 + E(C) = (P - TMC) diff --git a/docs/images/snippets/curvefitting/7c6b50cee5dc685515943a199d7a65fc.ascii b/docs/images/snippets/curvefitting/7c6b50cee5dc685515943a199d7a65fc.ascii new file mode 100644 index 00000000..05afbf6d --- /dev/null +++ b/docs/images/snippets/curvefitting/7c6b50cee5dc685515943a199d7a65fc.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + B =a + cubic + - 3at + 3bt + 2 2 2 + + 3at - 6bt +3ct + 3 3 3 3 + - at + 3bt -3ct + dt diff --git a/docs/images/snippets/curvefitting/8068231b915832938136d5833f74751d.ascii b/docs/images/snippets/curvefitting/8068231b915832938136d5833f74751d.ascii new file mode 100644 index 00000000..4376580d --- /dev/null +++ b/docs/images/snippets/curvefitting/8068231b915832938136d5833f74751d.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + T + E(C) = (P - TMC) (P - TMC) diff --git a/docs/images/snippets/curvefitting/940455f4016ab1be6d46c6f176fd2f76.ascii b/docs/images/snippets/curvefitting/940455f4016ab1be6d46c6f176fd2f76.ascii new file mode 100644 index 00000000..31a201a4 --- /dev/null +++ b/docs/images/snippets/curvefitting/940455f4016ab1be6d46c6f176fd2f76.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n 2 + E(C) = ❯ (p - Bézier(s )) + ‾‾ i=1 i i diff --git a/docs/images/snippets/curvefitting/9651a687e1522b00bcba063881230902.ascii b/docs/images/snippets/curvefitting/9651a687e1522b00bcba063881230902.ascii new file mode 100644 index 00000000..94c84155 --- /dev/null +++ b/docs/images/snippets/curvefitting/9651a687e1522b00bcba063881230902.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 0 0 ┐ ┌ a ┐ + B = T · M · C = ┌ 2 3 ┐ · │ -3 3 0 0 │ · │ b │ + cubic └ 1 t t t ┘ │ 3 -6 3 0 │ │ c │ + └ -1 3 -3 1 ┘ └ d ┘ diff --git a/docs/images/snippets/curvefitting/989f2ad06ae308f71cef527a5594129a.ascii b/docs/images/snippets/curvefitting/989f2ad06ae308f71cef527a5594129a.ascii new file mode 100644 index 00000000..e738aeae --- /dev/null +++ b/docs/images/snippets/curvefitting/989f2ad06ae308f71cef527a5594129a.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + T + E(C) = (P - 𝕋MC) (P - 𝕋MC) diff --git a/docs/images/snippets/curvefitting/9dec10b81a61b456ca1550cd9b7ba513.ascii b/docs/images/snippets/curvefitting/9dec10b81a61b456ca1550cd9b7ba513.ascii new file mode 100644 index 00000000..dae89d92 --- /dev/null +++ b/docs/images/snippets/curvefitting/9dec10b81a61b456ca1550cd9b7ba513.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + -1 T -1 T + C = M (𝕋 𝕋) 𝕋 P diff --git a/docs/images/snippets/curvefitting/a6faaf6083c818431988fef49421cc47.ascii b/docs/images/snippets/curvefitting/a6faaf6083c818431988fef49421cc47.ascii new file mode 100644 index 00000000..216f8113 --- /dev/null +++ b/docs/images/snippets/curvefitting/a6faaf6083c818431988fef49421cc47.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + B =a + quadratic + - 2at+ 2bt + 2 2 2 + + at - 2bt + ct diff --git a/docs/images/snippets/curvefitting/b017da988c9a778a4ce6a6f4ea4790d4.ascii b/docs/images/snippets/curvefitting/b017da988c9a778a4ce6a6f4ea4790d4.ascii new file mode 100644 index 00000000..5700c1a5 --- /dev/null +++ b/docs/images/snippets/curvefitting/b017da988c9a778a4ce6a6f4ea4790d4.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ p ┐ + │ 1 │ + │ p │ + P = │ 2 │ + │ ... │ + │ p │ + └ n ┘ diff --git a/docs/images/snippets/curvefitting/ea24b0e42f0a89464bda275ac8f9bacf.ascii b/docs/images/snippets/curvefitting/ea24b0e42f0a89464bda275ac8f9bacf.ascii new file mode 100644 index 00000000..9d7d848d --- /dev/null +++ b/docs/images/snippets/curvefitting/ea24b0e42f0a89464bda275ac8f9bacf.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ∂E T + ── = 0 = -2𝕋 (P - 𝕋MC) + ∂C diff --git a/docs/images/snippets/derivatives/12fa7f83f055ef2078cc9f04e1468663.ascii b/docs/images/snippets/derivatives/12fa7f83f055ef2078cc9f04e1468663.ascii new file mode 100644 index 00000000..16fd8bea --- /dev/null +++ b/docs/images/snippets/derivatives/12fa7f83f055ef2078cc9f04e1468663.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + kn! k-1 n-k (n-k)n! k n-1-k + ... = ──────── t (1-t) - ──────── t (1-t) + k!(n-k)! k!(n-k)! diff --git a/docs/images/snippets/derivatives/18c6e782012234a2c7425204505c8888.ascii b/docs/images/snippets/derivatives/18c6e782012234a2c7425204505c8888.ascii new file mode 100644 index 00000000..8f08c5ad --- /dev/null +++ b/docs/images/snippets/derivatives/18c6e782012234a2c7425204505c8888.ascii @@ -0,0 +1,13 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + n · B (t) · w + + n-1,-1 0 + n · B (t) · w - n · B (t) · w + + n-1,\colorblue0 1 n-1,\colorblue0 0 + n · B (t) · w - n · B (t) · w + + n-1,\colorred1 2 n-1,\colorred1 1 + n · B (t) · w - n · B (t) · w + + n-1,\colormagenta2 3 n-1,\colormagenta2 2 + ... - n · B (t) · w + + n-1,3 3 + ... diff --git a/docs/images/snippets/derivatives/2d733684f81b65a42c4cdb3f1e589c8b.ascii b/docs/images/snippets/derivatives/2d733684f81b65a42c4cdb3f1e589c8b.ascii new file mode 100644 index 00000000..d5f076bb --- /dev/null +++ b/docs/images/snippets/derivatives/2d733684f81b65a42c4cdb3f1e589c8b.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + B(n,t), w = {A,B,C,D} + B'(n,t), n = 3, w' = {A',B',C'} = {3 · (B-A), 3 · (C-B), 3 · (D-C)} + B''(n,t), n = 2, w'' = {A'',B''} = {2 · (B'-A'), 2 · (C'-B')} + B'''(n,t), n = 1, w''' = {A'''} = {1 · (B''-A'')} diff --git a/docs/images/snippets/derivatives/2fc50617b6886534d1ab4638ed8a24ac.ascii b/docs/images/snippets/derivatives/2fc50617b6886534d1ab4638ed8a24ac.ascii new file mode 100644 index 00000000..38ca7e22 --- /dev/null +++ b/docs/images/snippets/derivatives/2fc50617b6886534d1ab4638ed8a24ac.ascii @@ -0,0 +1,7 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ k k-i i +Bézier'(n,t) = ❯ \undersetbinomial term\underbrace\binomki · \ \undersetpolynomial term\underbrace(1-t) · t · \ \undersetderivative + ‾‾ i=0 + weight\underbracen · (w - w ) , with k=n-1 + i+1 i diff --git a/docs/images/snippets/derivatives/50616f9c922967c0c9c179af9b091947.ascii b/docs/images/snippets/derivatives/50616f9c922967c0c9c179af9b091947.ascii new file mode 100644 index 00000000..43a04070 --- /dev/null +++ b/docs/images/snippets/derivatives/50616f9c922967c0c9c179af9b091947.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + d __ n-1 __ n-1 + Bézier (t) ── = ❯ n · B (t) · (w - w ) = ❯ B (t) · \undersetderivative weights \underbracen · (w - w ) + n,k dt ‾‾ k=0 n-1,k k+1 k ‾‾ k=0 n-1,k k+1 k diff --git a/docs/images/snippets/derivatives/64c06c61727d0912a67c0f287a395e47.ascii b/docs/images/snippets/derivatives/64c06c61727d0912a67c0f287a395e47.ascii new file mode 100644 index 00000000..6acb8f0e --- /dev/null +++ b/docs/images/snippets/derivatives/64c06c61727d0912a67c0f287a395e47.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + n! k-1 n-k (n-k)n! k n-1-k + ... = ──────────── t (1-t) - ──────── t (1-t) + (k-1)!(n-k)! k!(n-k)! + ╭ (n-1)! k-1 n-k (n-k)(n-1)! k n-1-k ╮ + ... = n │ ──────────── t (1-t) - ─────────── t (1-t) │ + ╰ (k-1)!(n-k)! k!(n-k)! ╯ + ╭ (n-1)! (k-1) (n-1)-(k-1) (n-1)! k (n-1)-k ╮ + ... = n │ ──────────────────── t (1-t) - ──────────── t (1-t) │ + ╰ (k-1)!((n-1)-(k-1))! k!((n-1)-k)! ╯ diff --git a/docs/images/snippets/derivatives/67ca2710769505572e097ffb40de099f.ascii b/docs/images/snippets/derivatives/67ca2710769505572e097ffb40de099f.ascii new file mode 100644 index 00000000..d6bd6578 --- /dev/null +++ b/docs/images/snippets/derivatives/67ca2710769505572e097ffb40de099f.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n-1 + Bézier'(n,t) = ❯ Bézier(n-1,t) · n · (w -w ) + ‾‾ i=0 i i+1 i diff --git a/docs/images/snippets/derivatives/6a3672344bb571eadb72669f60a93ff4.ascii b/docs/images/snippets/derivatives/6a3672344bb571eadb72669f60a93ff4.ascii new file mode 100644 index 00000000..c4b9ddf2 --- /dev/null +++ b/docs/images/snippets/derivatives/6a3672344bb571eadb72669f60a93ff4.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ x! y x-y x! k x-k ╮ + ... = n │ ──────── t (1-t) - ──────── t (1-t) │ , with x=n-1, y=k-1 + ╰ y!(x-y)! k!(x-k)! ╯ + ... = n (B (t) - B (t)) + (n-1),(k-1) (n-1),k diff --git a/docs/images/snippets/derivatives/897cfd8648720dc21463a9358cc65ab4.ascii b/docs/images/snippets/derivatives/897cfd8648720dc21463a9358cc65ab4.ascii new file mode 100644 index 00000000..27521999 --- /dev/null +++ b/docs/images/snippets/derivatives/897cfd8648720dc21463a9358cc65ab4.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + Bézier (t) = B (t) · w + B (t) · w + B (t) · w + B (t) · w + ... + n,k n,0 0 n,1 1 n,2 2 n,3 3 + d + Bézier (t) ── = n · (B (t) - B (t)) · w + + n,k dt n-1,-1 n-1,0 0 + n · (B (t) - B (t)) · w + + n-1,0 n-1,1 1 + n · (B (t) - B (t)) · w + + n-1,1 n-1,2 2 + n · (B (t) - B (t)) · w + + n-1,2 n-1,3 3 + ... diff --git a/docs/images/snippets/derivatives/a7c61e0e8b42010df6dab641c92ef13d.ascii b/docs/images/snippets/derivatives/a7c61e0e8b42010df6dab641c92ef13d.ascii new file mode 100644 index 00000000..e95fb088 --- /dev/null +++ b/docs/images/snippets/derivatives/a7c61e0e8b42010df6dab641c92ef13d.ascii @@ -0,0 +1,6 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + d +Bézier (t) ── = n · B (t) · (w - w ) + n · B (t) · (w - w ) + n · B (t) · (w - w ) + + n,k dt (n-1),\colorblue0 1 0 (n-1),\colorred1 2 1 (n-1),\colormagenta2 3 2 + ... diff --git a/docs/images/snippets/derivatives/a992185a346518b5ca159484019b6917.ascii b/docs/images/snippets/derivatives/a992185a346518b5ca159484019b6917.ascii new file mode 100644 index 00000000..cd821581 --- /dev/null +++ b/docs/images/snippets/derivatives/a992185a346518b5ca159484019b6917.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + d ╭ n ╮ k n-k d + B (t) ── = │ │ t (1-t) ── + n,k dt ╰ k ╯ dt diff --git a/docs/images/snippets/derivatives/b58fb122c5c8159938182c185f287142.ascii b/docs/images/snippets/derivatives/b58fb122c5c8159938182c185f287142.ascii new file mode 100644 index 00000000..596ece8d --- /dev/null +++ b/docs/images/snippets/derivatives/b58fb122c5c8159938182c185f287142.ascii @@ -0,0 +1,7 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n n-i i +Bézier(n,t) = ❯ \undersetbinomial term\underbrace\binomni · \ \undersetpolynomial term\underbrace(1-t) · t · \ + ‾‾ i=0 + \undersetweight\underbracew + i diff --git a/docs/images/snippets/derivatives/c3ac18fe4ba0606a15bc111e52b17a9a.ascii b/docs/images/snippets/derivatives/c3ac18fe4ba0606a15bc111e52b17a9a.ascii new file mode 100644 index 00000000..69c7944f --- /dev/null +++ b/docs/images/snippets/derivatives/c3ac18fe4ba0606a15bc111e52b17a9a.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ n ╮ k-1 n-k k n-k-1 + ... = │ │ (k · t (1-t) + t · (1-t) · (n-k) · -1) + ╰ k ╯ diff --git a/docs/images/snippets/derivatives/f29a9d52897d2060a0c8a37073ed04fc.ascii b/docs/images/snippets/derivatives/f29a9d52897d2060a0c8a37073ed04fc.ascii new file mode 100644 index 00000000..f600e037 --- /dev/null +++ b/docs/images/snippets/derivatives/f29a9d52897d2060a0c8a37073ed04fc.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + n · B (t) · w - n · B (t) · w + + n-1,\colorblue0 1 n-1,\colorblue0 0 + n · B (t) · w - n · B (t) · w + + n-1,\colorred1 2 n-1,\colorred1 1 + n · B (t) · w - n · B (t) · w + + n-1,\colormagenta2 3 n-1,\colormagenta2 2 + ... diff --git a/docs/images/snippets/derivatives/f67d2d379ba6dfaa7f7686a7d1eae367.ascii b/docs/images/snippets/derivatives/f67d2d379ba6dfaa7f7686a7d1eae367.ascii new file mode 100644 index 00000000..c1292623 --- /dev/null +++ b/docs/images/snippets/derivatives/f67d2d379ba6dfaa7f7686a7d1eae367.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n-1 + Bézier'(n,t) = n · ❯ (b -b ) · Bézier(n-1,t) + ‾‾ i=0 i+1 i i diff --git a/docs/images/snippets/explanation/0cc876c56200446c60114c1b0eeeb2cc.ascii b/docs/images/snippets/explanation/0cc876c56200446c60114c1b0eeeb2cc.ascii new file mode 100644 index 00000000..bdae38d7 --- /dev/null +++ b/docs/images/snippets/explanation/0cc876c56200446c60114c1b0eeeb2cc.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + f(x) = cos (x) diff --git a/docs/images/snippets/explanation/2493468e73b73f43eba8f66f0c189d1a.ascii b/docs/images/snippets/explanation/2493468e73b73f43eba8f66f0c189d1a.ascii new file mode 100644 index 00000000..a4711580 --- /dev/null +++ b/docs/images/snippets/explanation/2493468e73b73f43eba8f66f0c189d1a.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + linear= (1-t) + t + 2 2 + square= (1-t) + 2 · (1-t) · t + t + 3 2 2 3 + cubic= (1-t) + 3 · (1-t) · t + 3 · (1-t) · t + t diff --git a/docs/images/snippets/explanation/2c47081c2a9c20d2110f13daa482a3ab.ascii b/docs/images/snippets/explanation/2c47081c2a9c20d2110f13daa482a3ab.ascii new file mode 100644 index 00000000..bfa97e16 --- /dev/null +++ b/docs/images/snippets/explanation/2c47081c2a9c20d2110f13daa482a3ab.ascii @@ -0,0 +1,8 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + +linear= \colorbluea + \colorredb +square= \colorbluea · \colorbluea + \colorbluea · \colorredb + \colorredb · \colorredb + cubic= \colorbluea · \colorbluea · \colorbluea + \colorbluea · \colorbluea · \colorredb + \colorbluea · \colorredb · \colorredb + \colorredb · + + + \colorredb · \colorredb diff --git a/docs/images/snippets/explanation/6914ba615733c387251682db7a3db045.ascii b/docs/images/snippets/explanation/6914ba615733c387251682db7a3db045.ascii new file mode 100644 index 00000000..a359fa43 --- /dev/null +++ b/docs/images/snippets/explanation/6914ba615733c387251682db7a3db045.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + { x = cos (t) + y = sin (t) diff --git a/docs/images/snippets/explanation/6aa5d4e20e83be1c95eaad792517dde9.ascii b/docs/images/snippets/explanation/6aa5d4e20e83be1c95eaad792517dde9.ascii new file mode 100644 index 00000000..599535f2 --- /dev/null +++ b/docs/images/snippets/explanation/6aa5d4e20e83be1c95eaad792517dde9.ascii @@ -0,0 +1,6 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + 1次= 1 + 1 + 2次= 1 + 2 + 1 + 3次= 1 + 3 + 3 + 1 + 4次= 1 + 4 + 6 + 4 + 1 diff --git a/docs/images/snippets/explanation/7acc94ec70f053fd10dab69d424b02a6.ascii b/docs/images/snippets/explanation/7acc94ec70f053fd10dab69d424b02a6.ascii new file mode 100644 index 00000000..204db2a1 --- /dev/null +++ b/docs/images/snippets/explanation/7acc94ec70f053fd10dab69d424b02a6.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ f (t) = cos (t) + ╡ a + │ f (t) = sin (t) + ╰ b diff --git a/docs/images/snippets/explanation/855a34c7f72733be6529c3fb33fa1a23.ascii b/docs/images/snippets/explanation/855a34c7f72733be6529c3fb33fa1a23.ascii new file mode 100644 index 00000000..9c13e82c --- /dev/null +++ b/docs/images/snippets/explanation/855a34c7f72733be6529c3fb33fa1a23.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 + f(x) = a · x + b · x + c · x + d diff --git a/docs/images/snippets/explanation/8986c536df8153b30197c3a5407d233a.ascii b/docs/images/snippets/explanation/8986c536df8153b30197c3a5407d233a.ascii new file mode 100644 index 00000000..271cd244 --- /dev/null +++ b/docs/images/snippets/explanation/8986c536df8153b30197c3a5407d233a.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + linear= 1 + 1 + square= 1 + 2 + 1 + cubic= 1 + 3 + 3 + 1 + quartic= 1 + 4 + 6 + 4 + 1 diff --git a/docs/images/snippets/explanation/9229934d71b0b02921bc92594ef11a98.ascii b/docs/images/snippets/explanation/9229934d71b0b02921bc92594ef11a98.ascii new file mode 100644 index 00000000..bfd645d7 --- /dev/null +++ b/docs/images/snippets/explanation/9229934d71b0b02921bc92594ef11a98.ascii @@ -0,0 +1,8 @@ + \usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + +1次= \colorbluea + \colorredb +2次= \colorbluea · \colorbluea + \colorbluea · \colorredb + \colorredb · \colorredb +3次= \colorbluea · \colorbluea · \colorbluea + \colorbluea · \colorbluea · \colorredb + \colorbluea · \colorredb · \colorredb + \colorredb · \co + + + lorredb · \colorredb diff --git a/docs/images/snippets/explanation/a2891980850ddbb27d308ac112d69f74.ascii b/docs/images/snippets/explanation/a2891980850ddbb27d308ac112d69f74.ascii new file mode 100644 index 00000000..0fdf3d82 --- /dev/null +++ b/docs/images/snippets/explanation/a2891980850ddbb27d308ac112d69f74.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + f(a) = cos (a) + f(b) = sin (b) diff --git a/docs/images/snippets/explanation/adc7729f7872d71f3fbb1a79741ce10f.ascii b/docs/images/snippets/explanation/adc7729f7872d71f3fbb1a79741ce10f.ascii new file mode 100644 index 00000000..92184ce2 --- /dev/null +++ b/docs/images/snippets/explanation/adc7729f7872d71f3fbb1a79741ce10f.ascii @@ -0,0 +1,7 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + 1次= (1-t) + t + 2 2 + 2次= (1-t) + 2 · (1-t) · t + t + 3 2 2 3 + 3次= (1-t) + 3 · (1-t) · t + 3 · (1-t) · t + t diff --git a/docs/images/snippets/explanation/b5977078d36d847fb299cbe3e7e2c3ba.ascii b/docs/images/snippets/explanation/b5977078d36d847fb299cbe3e7e2c3ba.ascii new file mode 100644 index 00000000..c5a4987d --- /dev/null +++ b/docs/images/snippets/explanation/b5977078d36d847fb299cbe3e7e2c3ba.ascii @@ -0,0 +1,5 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + __ n n-i i + Bézier(n,t) = ❯ \underset二項係数部分の項\underbrace\binomni · \ \underset多項式部分の項\underbrace(1-t) · t + ‾‾ i=0 diff --git a/docs/images/snippets/explanation/f79dd2f2d992e22b8d057fdc641290b0.ascii b/docs/images/snippets/explanation/f79dd2f2d992e22b8d057fdc641290b0.ascii new file mode 100644 index 00000000..6c385df0 --- /dev/null +++ b/docs/images/snippets/explanation/f79dd2f2d992e22b8d057fdc641290b0.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n n-i i + Bézier(n,t) = ❯ \undersetbinomial term\underbrace\binomni · \ \undersetpolynomial term\underbrace(1-t) · t + ‾‾ i=0 diff --git a/docs/images/snippets/extended/b0eb0b24e7fa29c545ab1479d2df0554.ascii b/docs/images/snippets/extended/b0eb0b24e7fa29c545ab1479d2df0554.ascii new file mode 100644 index 00000000..879cd5b7 --- /dev/null +++ b/docs/images/snippets/extended/b0eb0b24e7fa29c545ab1479d2df0554.ascii @@ -0,0 +1,4 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + 混ぜ合わさった値 = a · 値 + b · 値 + 1 2 diff --git a/docs/images/snippets/extended/e2e71b397009b51af8a3ee848bc727b4.ascii b/docs/images/snippets/extended/e2e71b397009b51af8a3ee848bc727b4.ascii new file mode 100644 index 00000000..026f43ad --- /dev/null +++ b/docs/images/snippets/extended/e2e71b397009b51af8a3ee848bc727b4.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + m = a · value + (1 - a) · value + 1 2 diff --git a/docs/images/snippets/extended/f56f59f3c0b057c8ec79a477e4e38bec.ascii b/docs/images/snippets/extended/f56f59f3c0b057c8ec79a477e4e38bec.ascii new file mode 100644 index 00000000..2e6e9bd6 --- /dev/null +++ b/docs/images/snippets/extended/f56f59f3c0b057c8ec79a477e4e38bec.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + mixture = a · value + b · value + 1 2 diff --git a/docs/images/snippets/extended/fd520a6e2c7f39e90496e5cf494cce2e.ascii b/docs/images/snippets/extended/fd520a6e2c7f39e90496e5cf494cce2e.ascii new file mode 100644 index 00000000..fa9b04d0 --- /dev/null +++ b/docs/images/snippets/extended/fd520a6e2c7f39e90496e5cf494cce2e.ascii @@ -0,0 +1,4 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + 混ぜ合わさった値 = a · 値 + (1 - a) · 値 + 1 2 diff --git a/docs/images/snippets/extremities/1fab66c84e7df38a2edda147f939bd80.ascii b/docs/images/snippets/extremities/1fab66c84e7df38a2edda147f939bd80.ascii new file mode 100644 index 00000000..ba19851b --- /dev/null +++ b/docs/images/snippets/extremities/1fab66c84e7df38a2edda147f939bd80.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + (b-a)t + a= 0, + (b-a)t= -a, + -a + t= ─── + b-a diff --git a/docs/images/snippets/extremities/2c398b492aadc90eb4e4853fc20b23e9.ascii b/docs/images/snippets/extremities/2c398b492aadc90eb4e4853fc20b23e9.ascii new file mode 100644 index 00000000..14f1d267 --- /dev/null +++ b/docs/images/snippets/extremities/2c398b492aadc90eb4e4853fc20b23e9.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌────────┐ + │ 2 + 2 -b ±⟍│b - 4ac + Given f(t) = at + bt + c, f(t)=0 when t = ─────────────── + 2a diff --git a/docs/images/snippets/extremities/53e67a29f134bd561aca550a2091a196.ascii b/docs/images/snippets/extremities/53e67a29f134bd561aca550a2091a196.ascii new file mode 100644 index 00000000..d9315d4c --- /dev/null +++ b/docs/images/snippets/extremities/53e67a29f134bd561aca550a2091a196.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + f (x ) + y n + x = x - ─────── + n+1 n f' (x ) + y n diff --git a/docs/images/snippets/extremities/55e16ef652d30face0f6586b675a6c7b.ascii b/docs/images/snippets/extremities/55e16ef652d30face0f6586b675a6c7b.ascii new file mode 100644 index 00000000..f1978f06 --- /dev/null +++ b/docs/images/snippets/extremities/55e16ef652d30face0f6586b675a6c7b.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + B'(t) = a(1-t) + b(t)= 0, + a - at + bt= 0, + (b-a)t + a= 0 diff --git a/docs/images/snippets/extremities/a6acf08f43aa1f48c08a40e76bdd2a31.ascii b/docs/images/snippets/extremities/a6acf08f43aa1f48c08a40e76bdd2a31.ascii new file mode 100644 index 00000000..e01ab1b7 --- /dev/null +++ b/docs/images/snippets/extremities/a6acf08f43aa1f48c08a40e76bdd2a31.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + a= v -2v +v = 3(-p + 3p - 3p + p ) + 1 2 3 1 2 3 4 + b= 2(v -v ) = 6(p - 2p + p ) + 2 1 1 2 3 + c= v = 3(p -p ) + 1 2 1 diff --git a/docs/images/snippets/extremities/c4858be225d004441b2aefedacda89a3.ascii b/docs/images/snippets/extremities/c4858be225d004441b2aefedacda89a3.ascii new file mode 100644 index 00000000..02bf844f --- /dev/null +++ b/docs/images/snippets/extremities/c4858be225d004441b2aefedacda89a3.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + B(t) uses { p ,p ,p ,p } + 1 2 3 4 + B'(t) uses { v ,v ,v }, where v = 3(p -p ), v = 3(p -p ), v = 3(p -p ) + 1 2 3 1 2 1 2 3 2 3 4 3 diff --git a/docs/images/snippets/extremities/d1c65d927825f20c3c358d1ff96ce881.ascii b/docs/images/snippets/extremities/d1c65d927825f20c3c358d1ff96ce881.ascii new file mode 100644 index 00000000..7422ce79 --- /dev/null +++ b/docs/images/snippets/extremities/d1c65d927825f20c3c358d1ff96ce881.ascii @@ -0,0 +1,17 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 2 + B'(t)= v (1-t) + 2v (1-t)t + v t + 1 2 3 + 2 2 2 + ...= v (t - 2t + 1) + 2v (t-t ) + v t + 1 2 3 + 2 2 2 + ...= v t - 2v t + v + 2v t - 2v t + v t + 1 1 1 2 2 3 + 2 2 2 + ...= v t - 2v t + v t - 2v t + v + 2v t + 1 2 3 1 1 2 + 2 + ...= (v -2v +v )t + 2(v -v )t + v + 1 2 3 2 1 1 diff --git a/docs/images/snippets/extremities/d31432533bd7940545d4a269eefbabf2.ascii b/docs/images/snippets/extremities/d31432533bd7940545d4a269eefbabf2.ascii new file mode 100644 index 00000000..150a20ac --- /dev/null +++ b/docs/images/snippets/extremities/d31432533bd7940545d4a269eefbabf2.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 + very hard: solve at + bt + ct + d = 0 + 3 + easier: solve t + pt + q = 0 diff --git a/docs/images/snippets/inflections/2dbf3071d74e2ba37ab888aaa3c1a17c.ascii b/docs/images/snippets/inflections/2dbf3071d74e2ba37ab888aaa3c1a17c.ascii new file mode 100644 index 00000000..6e8fa798 --- /dev/null +++ b/docs/images/snippets/inflections/2dbf3071d74e2ba37ab888aaa3c1a17c.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + a = x · y ╮ + 3 2 │ + b = x · y │ 2 + 4 2 ╞ C(t) = (-3a + 2b + 3c - d)t + (3a - b - 3c)t + (c - a) + c = x · y │ + 2 3 │ + d = x · y │ + 4 3 ╯ diff --git a/docs/images/snippets/inflections/75fae2d0a94eae4addf074c294855fc7.ascii b/docs/images/snippets/inflections/75fae2d0a94eae4addf074c294855fc7.ascii new file mode 100644 index 00000000..2e50620c --- /dev/null +++ b/docs/images/snippets/inflections/75fae2d0a94eae4addf074c294855fc7.ascii @@ -0,0 +1,15 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 2 2 2 2 + -18 t x y + 36 t x y - 18 t x y + 18 t x y - 54 t x y + 2 1 3 1 4 1 1 2 3 2 + 2 2 2 2 2 + +36 t x y - 36 t x y + 54 t x y - 18 t x y + 18 t x y + 4 2 1 3 2 3 4 3 1 4 + 2 2 + -36 t x y + 18 t x y + 36 t x y - 54 t x y + 18 t x y - 36 t x y + 2 4 3 4 2 1 3 1 4 1 1 2 + +54 t x y - 18 t x y + 54 t x y - 54 t x y - 18 t x y + 18 t x y + 3 2 4 2 1 3 2 3 1 4 2 4 + -18 x y + 18 x y + 18 x y - 18 x y - 18 x y + 18 x y + 2 1 3 1 1 2 3 2 1 3 2 3 diff --git a/docs/images/snippets/inflections/a283e01df17f3d763ec89621f2af6c5c.ascii b/docs/images/snippets/inflections/a283e01df17f3d763ec89621f2af6c5c.ascii new file mode 100644 index 00000000..1ac847c9 --- /dev/null +++ b/docs/images/snippets/inflections/a283e01df17f3d763ec89621f2af6c5c.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C(t) = Bézier \prime(t) · Bézier \prime\prime(t) - Bézier \prime(t) · Bézier \prime\prime(t) + x y y x diff --git a/docs/images/snippets/inflections/be9e409d619ecd735b0fbc219bec6d07.ascii b/docs/images/snippets/inflections/be9e409d619ecd735b0fbc219bec6d07.ascii new file mode 100644 index 00000000..d6e925a0 --- /dev/null +++ b/docs/images/snippets/inflections/be9e409d619ecd735b0fbc219bec6d07.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 2 3 + Bézier(t) = y (1-t) + 3y (1-t) t + 3y (1-t)t + y t + 1 2 3 4 + \prime 2 2 + Bézier (t) = d(1-t) + 2e(1-t)t + ft + \prime\prime + Bézier (t) = w(1-t) + zt diff --git a/docs/images/snippets/inflections/d7d564126099bc0740058a7cdd744772.ascii b/docs/images/snippets/inflections/d7d564126099bc0740058a7cdd744772.ascii new file mode 100644 index 00000000..b9414ad2 --- /dev/null +++ b/docs/images/snippets/inflections/d7d564126099bc0740058a7cdd744772.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌──────────┐ + │ 2 + x = -3a + 2b + 3c - d ╮ -y ±⟍│y - 4 x z + y = 3a - b - 3c ╞ C(t) = 0 \Rightarrow t = ───────────────── + z = c - a ╯ 2x diff --git a/docs/images/snippets/inflections/e50243eaa99b5acc08533dd2e9b71a74.ascii b/docs/images/snippets/inflections/e50243eaa99b5acc08533dd2e9b71a74.ascii new file mode 100644 index 00000000..d1153936 --- /dev/null +++ b/docs/images/snippets/inflections/e50243eaa99b5acc08533dd2e9b71a74.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 2 + (3 x y +2 x y +3 x y -x y ) t + (3 x y -x y -3 x y ) t + (x y -x y ) + 3 2 4 2 2 3 4 3 3 2 4 2 2 3 2 3 3 2 diff --git a/docs/images/snippets/inflections/ed68dcfb203517ca080fe48914769fb0.ascii b/docs/images/snippets/inflections/ed68dcfb203517ca080fe48914769fb0.ascii new file mode 100644 index 00000000..7f18e4de --- /dev/null +++ b/docs/images/snippets/inflections/ed68dcfb203517ca080fe48914769fb0.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C(t) = 0 diff --git a/docs/images/snippets/inflections/f9f2258e59b038659087a5e87ba2e0af.ascii b/docs/images/snippets/inflections/f9f2258e59b038659087a5e87ba2e0af.ascii new file mode 100644 index 00000000..1c95bead --- /dev/null +++ b/docs/images/snippets/inflections/f9f2258e59b038659087a5e87ba2e0af.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 2 3 + Bézier(t) = x (1-t) + 3x (1-t) t + 3x (1-t)t + x t + 1 2 3 4 + \prime 2 2 + Bézier (t) = a(1-t) + 2b(1-t)t + ct { a=3(x -x ),b=3(x -x ),c=3(x -x ) } + 2 1 3 2 4 3 + \prime\prime + Bézier (t) = u(1-t) + vt {u=2(b-a),v=2(c-b)}\ diff --git a/docs/images/snippets/matrix/1a64ed455c6dd2f8cacca5e5e12bdcc1.ascii b/docs/images/snippets/matrix/1a64ed455c6dd2f8cacca5e5e12bdcc1.ascii new file mode 100644 index 00000000..6520d57c --- /dev/null +++ b/docs/images/snippets/matrix/1a64ed455c6dd2f8cacca5e5e12bdcc1.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 0 0 ┐ + ┌ 2 3 ┐ · │ -3 3 0 0 │ + └ 1 t t t ┘ │ 3 -6 3 0 │ + └ -1 3 -3 1 ┘ diff --git a/docs/images/snippets/matrix/1bae50fefa43210b3a6259d1984f6cbc.ascii b/docs/images/snippets/matrix/1bae50fefa43210b3a6259d1984f6cbc.ascii new file mode 100644 index 00000000..5fcb39cb --- /dev/null +++ b/docs/images/snippets/matrix/1bae50fefa43210b3a6259d1984f6cbc.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ 1 0 0 ┐ │ 1 │ + B(t) = ┌ 2 ┐ · │ -2 2 0 │ · │ P │ + └ 1 t t ┘ └ 1 -2 1 ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrix/67a5ea33d6c6558f7d954b18226f4956.ascii b/docs/images/snippets/matrix/67a5ea33d6c6558f7d954b18226f4956.ascii new file mode 100644 index 00000000..e363cc6b --- /dev/null +++ b/docs/images/snippets/matrix/67a5ea33d6c6558f7d954b18226f4956.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 + ... = -1 · t + 3 · t - 3 · t + 1 + 3 2 + + +3 · t - 6 · t + 3 · t + 0 + 3 2 + + -3 · t + 3 · t + 0 · t + 0 + 3 2 + + +1 · t + 0 · t + 0 · t + 0 diff --git a/docs/images/snippets/matrix/87cfac83cb8a4b0bee68ef006effc611.ascii b/docs/images/snippets/matrix/87cfac83cb8a4b0bee68ef006effc611.ascii new file mode 100644 index 00000000..2eac0924 --- /dev/null +++ b/docs/images/snippets/matrix/87cfac83cb8a4b0bee68ef006effc611.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 2 3 + B(t) = (1-t) + 3 · (1-t) · t + 3 · (1-t) · t + t diff --git a/docs/images/snippets/matrix/8ecff6b8a37d60385d287ea2b26876db.ascii b/docs/images/snippets/matrix/8ecff6b8a37d60385d287ea2b26876db.ascii new file mode 100644 index 00000000..59035dac --- /dev/null +++ b/docs/images/snippets/matrix/8ecff6b8a37d60385d287ea2b26876db.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ -1 ┐ ┌ 3 ┐ ┌ -3 ┐ ┌ 1 ┐ + ┌ 3 2 ┐ · │ 3 │ + ┌ 3 2 ┐ · │ -6 │ + ┌ 3 2 ┐ · │ 3 │ + ┌ 3 2 ┐ · │ 0 │ + └ t t t 1 ┘ │ -3 │ └ t t t 1 ┘ │ 3 │ └ t t t 1 ┘ │ 0 │ └ t t t 1 ┘ │ 0 │ + └ 1 ┘ └ 0 ┘ └ 0 ┘ └ 0 ┘ diff --git a/docs/images/snippets/matrix/9a9a55f5b0323d9ea88f82fc6be58ad3.ascii b/docs/images/snippets/matrix/9a9a55f5b0323d9ea88f82fc6be58ad3.ascii new file mode 100644 index 00000000..33bc4b3d --- /dev/null +++ b/docs/images/snippets/matrix/9a9a55f5b0323d9ea88f82fc6be58ad3.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 2 3 + B(t) = P · (1-t) + P · 3 · (1-t) · t + P · 3 · (1-t) · t + P · t + 1 2 3 4 diff --git a/docs/images/snippets/matrix/b32cae2dfc47d5f36df0bc3defb7dfa8.ascii b/docs/images/snippets/matrix/b32cae2dfc47d5f36df0bc3defb7dfa8.ascii new file mode 100644 index 00000000..a6db7a5e --- /dev/null +++ b/docs/images/snippets/matrix/b32cae2dfc47d5f36df0bc3defb7dfa8.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 1 │ + ┌ 1 0 0 0 ┐ │ P │ + B(t) = ┌ 2 3 ┐ · │ -3 3 0 0 │ · │ 2 │ + └ 1 t t t ┘ │ 3 -6 3 0 │ │ P │ + └ -1 3 -3 1 ┘ │ 3 │ + │ P │ + └ 4 ┘ diff --git a/docs/images/snippets/matrix/b9527f7d5a0f5d2d737eac118d69243e.ascii b/docs/images/snippets/matrix/b9527f7d5a0f5d2d737eac118d69243e.ascii new file mode 100644 index 00000000..0ffbebab --- /dev/null +++ b/docs/images/snippets/matrix/b9527f7d5a0f5d2d737eac118d69243e.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ -1 3 -3 1 ┐ + ┌ 3 2 ┐ · │ 3 -6 3 0 │ + └ t t t 1 ┘ │ -3 3 0 0 │ + └ 1 0 0 0 ┘ diff --git a/docs/images/snippets/matrix/cdd88611833f3b178df91278359a4193.ascii b/docs/images/snippets/matrix/cdd88611833f3b178df91278359a4193.ascii new file mode 100644 index 00000000..5f431800 --- /dev/null +++ b/docs/images/snippets/matrix/cdd88611833f3b178df91278359a4193.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 + ... = (1-t) + 2 + + 3 · (1-t) · t + 2 + + 3 · (1-t) · t + 3 + + t diff --git a/docs/images/snippets/matrix/ec118f296511c6e9ac8727be3703a7ce.ascii b/docs/images/snippets/matrix/ec118f296511c6e9ac8727be3703a7ce.ascii new file mode 100644 index 00000000..bd260ce0 --- /dev/null +++ b/docs/images/snippets/matrix/ec118f296511c6e9ac8727be3703a7ce.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + 3 2 + ... = (1-t) · (1-t) · (1-t) = -t + 3 · t - 3 · t + 1 + 3 2 + + 3 · (1-t) · (1-t) · t = 3 · t - 6 · t + 3 · t + 3 2 + + 3 · (1-t) · t · t = -3 · t + 3 · t + 3 + + t · t · t = t diff --git a/docs/images/snippets/matrixsplit/11505e0215ef026f2e49383ebb4a1abb.ascii b/docs/images/snippets/matrixsplit/11505e0215ef026f2e49383ebb4a1abb.ascii new file mode 100644 index 00000000..e6a3008f --- /dev/null +++ b/docs/images/snippets/matrixsplit/11505e0215ef026f2e49383ebb4a1abb.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ P ┐ │ 1 │ +┌ 1 0 0 0 ┐ │ 1 │ │ z · P - (z-1) · P │ +│ -(z-1) z 0 0 │ │ P │ │ 2 1 │ +│ 2 2 │ · │ 2 │ = │ 2 2 │ +│ (z-1) -2 · (z-1) · z z 0 │ │ P │ │ z · P - 2 · z · (z-1) · P + (z-1) · P │ +│ 3 2 2 3 │ │ 3 │ │ 3 2 1 │ +└ -(z-1) 3 · (z-1) · z -3 · (z-1) · z z ┘ │ P │ │ 3 2 2 3 │ + └ 4 ┘ │ z · P - 3 · z · (z-1) · P + 3 · z · (z-1) · P - (z-1) · P │ + └ 4 3 2 1 ┘ diff --git a/docs/images/snippets/matrixsplit/17e308aa6d459b1d06d3160cc8e2e786.ascii b/docs/images/snippets/matrixsplit/17e308aa6d459b1d06d3160cc8e2e786.ascii new file mode 100644 index 00000000..c92f6cb1 --- /dev/null +++ b/docs/images/snippets/matrixsplit/17e308aa6d459b1d06d3160cc8e2e786.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 2 2 ┐ + ┌ P ┐ │ z · P - 2 · z · (z-1) · P + (z-1) · P │ + ┌ 2 2 ┐ │ 1 │ │ 3 2 1 │ + │ (z-1) -2 · z · (z-1) z │ · │ P │ = │ z · P - (z-1) · P │ + │ 0 -(z-1) z │ │ 2 │ │ 3 2 │ + └ 0 0 1 ┘ │ P │ │ P │ + └ 3 ┘ └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/1bae50fefa43210b3a6259d1984f6cbc.ascii b/docs/images/snippets/matrixsplit/1bae50fefa43210b3a6259d1984f6cbc.ascii new file mode 100644 index 00000000..5fcb39cb --- /dev/null +++ b/docs/images/snippets/matrixsplit/1bae50fefa43210b3a6259d1984f6cbc.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ 1 0 0 ┐ │ 1 │ + B(t) = ┌ 2 ┐ · │ -2 2 0 │ · │ P │ + └ 1 t t ┘ └ 1 -2 1 ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/3b5e41808b6c3bc66f3da2f40651410e.ascii b/docs/images/snippets/matrixsplit/3b5e41808b6c3bc66f3da2f40651410e.ascii new file mode 100644 index 00000000..6b773faa --- /dev/null +++ b/docs/images/snippets/matrixsplit/3b5e41808b6c3bc66f3da2f40651410e.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ 1 0 0 ┐ ┌ 1 0 0 ┐ │ 1 │ + = ┌ 2 ┐ · │ 0 z 0 │ · │ -2 2 0 │ · │ P │ + └ 1 t t ┘ │ 2 │ └ 1 -2 1 ┘ │ 2 │ + └ 0 0 z ┘ │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/4764868f43815e471bb1ea95a81e1633.ascii b/docs/images/snippets/matrixsplit/4764868f43815e471bb1ea95a81e1633.ascii new file mode 100644 index 00000000..25f48e95 --- /dev/null +++ b/docs/images/snippets/matrixsplit/4764868f43815e471bb1ea95a81e1633.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 2 ┐ ┌ P ┐ + │ 1 z z │ ┌ 1 0 0 ┐ │ 1 │ + = ┌ 2 ┐ · │ 0 1-z 2 · z · (1-z) │ · │ -2 2 0 │ · │ P │ + └ 1 t t ┘ │ 2 │ └ 1 -2 1 ┘ │ 2 │ + └ 0 0 (1-z) ┘ │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/480ebd0234e2fe1adc94926e8ed4339c.ascii b/docs/images/snippets/matrixsplit/480ebd0234e2fe1adc94926e8ed4339c.ascii new file mode 100644 index 00000000..8f826f26 --- /dev/null +++ b/docs/images/snippets/matrixsplit/480ebd0234e2fe1adc94926e8ed4339c.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ P ┐ │ 1 │ + ┌ 1 0 0 ┐ │ 1 │ │ z · P - (z-1) · P │ + │ -(z-1) z 0 │ · │ P │ = │ 2 1 │ + │ 2 2 │ │ 2 │ │ 2 2 │ + └ (z - 1) -2 · (z-1) · z z ┘ │ P │ │ z · P - 2 · z · (z-1) · P + (z - 1) · P │ + └ 3 ┘ └ 3 2 1 ┘ diff --git a/docs/images/snippets/matrixsplit/4ce218bc968cbd98da0ca6ab66d415ed.ascii b/docs/images/snippets/matrixsplit/4ce218bc968cbd98da0ca6ab66d415ed.ascii new file mode 100644 index 00000000..cec76d25 --- /dev/null +++ b/docs/images/snippets/matrixsplit/4ce218bc968cbd98da0ca6ab66d415ed.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ ┌ P ┐ ╮ + ┌ 1 0 0 ┐ │ ┌ 2 2 ┐ │ 1 │ │ + = ┌ 2 ┐ · │ -2 2 0 │ · │ │ (z-1) -2 · z · (z-1) z │ · │ P │ │ + └ 1 t t ┘ └ 1 -2 1 ┘ │ │ 0 -(z-1) z │ │ 2 │ │ + │ └ 0 0 1 ┘ │ P │ │ + ╰ └ 3 ┘ ╯ diff --git a/docs/images/snippets/matrixsplit/55b45214ba90c96978cdc9cdfee24fef.ascii b/docs/images/snippets/matrixsplit/55b45214ba90c96978cdc9cdfee24fef.ascii new file mode 100644 index 00000000..6e6618e1 --- /dev/null +++ b/docs/images/snippets/matrixsplit/55b45214ba90c96978cdc9cdfee24fef.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + -1 │ 1 │ + = ┌ 2 ┐ · \underset...into this...\underbrace M · M · Z · M · │ P │ + └ 1 t t ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/598739d23cf8dbcdebe033e4c7f1d28a.ascii b/docs/images/snippets/matrixsplit/598739d23cf8dbcdebe033e4c7f1d28a.ascii new file mode 100644 index 00000000..25acefd4 --- /dev/null +++ b/docs/images/snippets/matrixsplit/598739d23cf8dbcdebe033e4c7f1d28a.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 1 │ + = ┌ 2 ┐ · M \underset...to get this!\underbrace \kern 1.25em · \kern 1.25em Q \kern 1.25em · \kern 1.25em │ P │ + └ 1 t t ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/5e008143622c66bb5e9cc4d5d6a8ea62.ascii b/docs/images/snippets/matrixsplit/5e008143622c66bb5e9cc4d5d6a8ea62.ascii new file mode 100644 index 00000000..352387b9 --- /dev/null +++ b/docs/images/snippets/matrixsplit/5e008143622c66bb5e9cc4d5d6a8ea62.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 0 ┐ + -1 │ 1 │ ┌ 1 0 0 ┐ ┌ 1 0 0 ┐ ┌ 1 0 0 ┐ + Q = M · Z · M = │ 1 ─ 0 │ · │ 0 z 0 │ · │ -2 2 0 │ = │ -(z-1) z 0 │ + │ 2 │ │ 2 │ └ 1 -2 1 ┘ │ 2 2 │ + └ 1 1 1 ┘ └ 0 0 z ┘ └ (z - 1) -2 · (z-1) · z z ┘ diff --git a/docs/images/snippets/matrixsplit/63d1337d275abf7b296d500b9b5821fd.ascii b/docs/images/snippets/matrixsplit/63d1337d275abf7b296d500b9b5821fd.ascii new file mode 100644 index 00000000..8eb21c3a --- /dev/null +++ b/docs/images/snippets/matrixsplit/63d1337d275abf7b296d500b9b5821fd.ascii @@ -0,0 +1,8 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + ┌ P ┐ + │ 1 │ + = ┌ 2 ┐ · \undersetこれを…\underbrace\kern 2.25em Z · M \kern 2.25em · │ P │ + └ 1 t t ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/6a22184e6ca869d28f4a252b64f23eff.ascii b/docs/images/snippets/matrixsplit/6a22184e6ca869d28f4a252b64f23eff.ascii new file mode 100644 index 00000000..8a598201 --- /dev/null +++ b/docs/images/snippets/matrixsplit/6a22184e6ca869d28f4a252b64f23eff.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ 1 0 0 ┐ │ 1 │ + B(t) = ┌ 2 ┐ · │ -2 2 0 │ · │ P │ + └ 1 ( 0 + z · t) ( 0 + z · t) ┘ └ 1 -2 1 ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/7a1e792cd3fa6f3482459e154abf2e7d.ascii b/docs/images/snippets/matrixsplit/7a1e792cd3fa6f3482459e154abf2e7d.ascii new file mode 100644 index 00000000..22ed8149 --- /dev/null +++ b/docs/images/snippets/matrixsplit/7a1e792cd3fa6f3482459e154abf2e7d.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 1 │ + = ┌ 2 ┐ · \undersetwe turn this...\underbrace\kern 2.25em Z · M \kern 2.25em · │ P │ + └ 1 t t ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/9a4899b69e03cd4ad02c5eedffaa6a2f.ascii b/docs/images/snippets/matrixsplit/9a4899b69e03cd4ad02c5eedffaa6a2f.ascii new file mode 100644 index 00000000..f326f553 --- /dev/null +++ b/docs/images/snippets/matrixsplit/9a4899b69e03cd4ad02c5eedffaa6a2f.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 2 2 ┐ + │ z · P - 2 · z · (z-1) · P + (z-1) · P │ + ┌ 1 0 0 ┐ │ 3 2 1 │ + = ┌ 2 ┐ · │ -2 2 0 │ · │ z · P - (z-1) · P │ + └ 1 t t ┘ └ 1 -2 1 ┘ │ 3 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/a899891096d82b7fdb23a90e6106b6df.ascii b/docs/images/snippets/matrixsplit/a899891096d82b7fdb23a90e6106b6df.ascii new file mode 100644 index 00000000..28c1101d --- /dev/null +++ b/docs/images/snippets/matrixsplit/a899891096d82b7fdb23a90e6106b6df.ascii @@ -0,0 +1,12 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 3 2 2 3 ┐ + ┌ P ┐ │ z · P - 3 · z · (z-1) · P + 3 · z · (z-1) · P - (z-1) · P │ +┌ 3 2 2 3 ┐ │ 1 │ │ 4 3 2 1 │ +│ -(z-1) 3 · (z-1) · z -3 · (z-1) · z z │ │ P │ │ 2 2 │ +│ 2 2 │ · │ 2 │ = │ z · P - 2 · z · (z-1) · P + (z-1) · P │ +│ 0 (z-1) -2 · (z-1) · z z │ │ P │ │ 4 3 2 │ +│ 0 0 -(z-1) z │ │ 3 │ │ z · P - (z-1) · P │ +└ 0 0 0 1 ┘ │ P │ │ 4 3 │ + └ 4 ┘ │ P │ + └ 4 ┘ diff --git a/docs/images/snippets/matrixsplit/baedd4067516584d425b93331b7ce04f.ascii b/docs/images/snippets/matrixsplit/baedd4067516584d425b93331b7ce04f.ascii new file mode 100644 index 00000000..ba9bb74d --- /dev/null +++ b/docs/images/snippets/matrixsplit/baedd4067516584d425b93331b7ce04f.ascii @@ -0,0 +1,8 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + ┌ P ┐ + │ 1 │ + = ┌ 2 ┐ · M \underset…こうじゃ!\underbrace \kern 1.25em · \kern 1.25em Q \kern 1.25em · \kern 1.25em │ P │ + └ 1 t t ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/c32007be095224e0d157a8f71c62c90e.ascii b/docs/images/snippets/matrixsplit/c32007be095224e0d157a8f71c62c90e.ascii new file mode 100644 index 00000000..daf1f127 --- /dev/null +++ b/docs/images/snippets/matrixsplit/c32007be095224e0d157a8f71c62c90e.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ 1 0 0 ┐ ┌ 1 0 0 ┐ │ 1 │ + B(t) = ┌ 2 ┐ · │ 0 z 0 │ · │ -2 2 0 │ · │ P │ + └ 1 t t ┘ │ 2 │ └ 1 -2 1 ┘ │ 2 │ + └ 0 0 z ┘ │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/c341532f693c2c1adfd298597bbfb5b5.ascii b/docs/images/snippets/matrixsplit/c341532f693c2c1adfd298597bbfb5b5.ascii new file mode 100644 index 00000000..6012b538 --- /dev/null +++ b/docs/images/snippets/matrixsplit/c341532f693c2c1adfd298597bbfb5b5.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 0 ┐ ┌ 2 ┐ + -1 │ 1 │ │ 1 z z │ ┌ 1 0 0 ┐ ┌ 2 2 ┐ + Q' = M · Z' · M = │ 1 ─ 0 │ · │ 0 1-z 2 · z · (1-z) │ · │ -2 2 0 │ = │ (z-1) -2 · z · (z-1) z │ + │ 2 │ │ 2 │ └ 1 -2 1 ┘ │ 0 -(z-1) z │ + └ 1 1 1 ┘ └ 0 0 (1-z) ┘ └ 0 0 1 ┘ diff --git a/docs/images/snippets/matrixsplit/d9d04b9b6c66788d18832a383d6f7ea0.ascii b/docs/images/snippets/matrixsplit/d9d04b9b6c66788d18832a383d6f7ea0.ascii new file mode 100644 index 00000000..baf1ab1c --- /dev/null +++ b/docs/images/snippets/matrixsplit/d9d04b9b6c66788d18832a383d6f7ea0.ascii @@ -0,0 +1,8 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + ┌ P ┐ + -1 │ 1 │ + = ┌ 2 ┐ · \underset…こうして…\underbrace M · M · Z · M · │ P │ + └ 1 t t ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/dceed84990aaf6878bcc67ddbaa8d8d9.ascii b/docs/images/snippets/matrixsplit/dceed84990aaf6878bcc67ddbaa8d8d9.ascii new file mode 100644 index 00000000..ba5384cc --- /dev/null +++ b/docs/images/snippets/matrixsplit/dceed84990aaf6878bcc67ddbaa8d8d9.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ ╭ ┌ P ┐ ╮ + │ 1 │ │ │ 1 │ │ + B(t) = ┌ 2 ┐ · M · Q · │ P │ = ┌ 2 ┐ · M · │ Q · │ P │ │ + └ 1 t t ┘ │ 2 │ └ 1 t t ┘ │ │ 2 │ │ + │ P │ │ │ P │ │ + └ 3 ┘ ╰ └ 3 ┘ ╯ diff --git a/docs/images/snippets/matrixsplit/e079f44b56e07c8d7f83c17c8ebf1ecf.ascii b/docs/images/snippets/matrixsplit/e079f44b56e07c8d7f83c17c8ebf1ecf.ascii new file mode 100644 index 00000000..c0f1f715 --- /dev/null +++ b/docs/images/snippets/matrixsplit/e079f44b56e07c8d7f83c17c8ebf1ecf.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + ┌ 1 0 0 ┐ │ 1 │ + B(t) = ┌ 2 ┐ · │ -2 2 0 │ · │ P │ + └ 1 ( z + (1-z) · t) ( z + (1-z) · t) ┘ └ 1 -2 1 ┘ │ 2 │ + │ P │ + └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/e2622175dadafecc015f15c79ddf3002.ascii b/docs/images/snippets/matrixsplit/e2622175dadafecc015f15c79ddf3002.ascii new file mode 100644 index 00000000..75077427 --- /dev/null +++ b/docs/images/snippets/matrixsplit/e2622175dadafecc015f15c79ddf3002.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ ╭ ┌ P ┐ ╮ + │ 1 │ │ │ 1 │ │ + B(t) = ┌ 2 ┐ · M · Q · │ P │ = ┌ 2 ┐ · M · │ Q' · │ P │ │ + └ 1 t t ┘ │ 2 │ └ 1 t t ┘ │ │ 2 │ │ + │ P │ │ │ P │ │ + └ 3 ┘ ╰ └ 3 ┘ ╯ diff --git a/docs/images/snippets/matrixsplit/e58196b82b78f584779208cce88137f5.ascii b/docs/images/snippets/matrixsplit/e58196b82b78f584779208cce88137f5.ascii new file mode 100644 index 00000000..95e764a2 --- /dev/null +++ b/docs/images/snippets/matrixsplit/e58196b82b78f584779208cce88137f5.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 1 │ + ┌ 1 0 0 ┐ │ z · P - (z-1) · P │ + = ┌ 2 ┐ · │ -2 2 0 │ · │ 2 1 │ + └ 1 t t ┘ └ 1 -2 1 ┘ │ 2 2 │ + │ z · P - 2 · z · (z-1) · P + (z - 1) · P │ + └ 3 2 1 ┘ diff --git a/docs/images/snippets/matrixsplit/ebf8d72c6056476172deeb89726b75c8.ascii b/docs/images/snippets/matrixsplit/ebf8d72c6056476172deeb89726b75c8.ascii new file mode 100644 index 00000000..4ffa192c --- /dev/null +++ b/docs/images/snippets/matrixsplit/ebf8d72c6056476172deeb89726b75c8.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ ┌ P ┐ + │ 1 │ ┌ 1 0 0 0 ┐ │ 1 │ + ┌ 1 0 0 0 ┐ │ P │ │ 0 z 0 0 │ ┌ 1 0 0 0 ┐ │ P │ + B(t) = ┌ 2 3 ┐ · │ -3 3 0 0 │ · │ 2 │ = ┌ 2 3 ┐ · │ 2 │ · │ -3 3 0 0 │ · │ 2 │ + └ 1 (z · t) (z · t) (z · t) ┘ │ 3 -6 3 0 │ │ P │ └ 1 t t t ┘ │ 0 0 z 0 │ │ 3 -6 3 0 │ │ P │ + └ -1 3 -3 1 ┘ │ 3 │ │ 3 │ └ -1 3 -3 1 ┘ │ 3 │ + │ P │ └ 0 0 0 z ┘ │ P │ + └ 4 ┘ └ 4 ┘ diff --git a/docs/images/snippets/matrixsplit/f565e66677138927335535d009409c3d.ascii b/docs/images/snippets/matrixsplit/f565e66677138927335535d009409c3d.ascii new file mode 100644 index 00000000..92f70d22 --- /dev/null +++ b/docs/images/snippets/matrixsplit/f565e66677138927335535d009409c3d.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ ┌ P ┐ + ┌ 1 0 0 ┐ │ 1 │ ┌ 1 0 0 ┐ ┌ 1 0 0 ┐ │ 1 │ + B(t) = ┌ 2 ┐ · │ -2 2 0 │ · │ P │ = ┌ 2 ┐ · │ 0 z 0 │ · │ -2 2 0 │ · │ P │ + └ 1 (z · t) (z · t) ┘ └ 1 -2 1 ┘ │ 2 │ └ 1 t t ┘ │ 2 │ └ 1 -2 1 ┘ │ 2 │ + │ P │ └ 0 0 z ┘ │ P │ + └ 3 ┘ └ 3 ┘ diff --git a/docs/images/snippets/matrixsplit/f63067c2c3042c374a58dfa7f692309e.ascii b/docs/images/snippets/matrixsplit/f63067c2c3042c374a58dfa7f692309e.ascii new file mode 100644 index 00000000..1c003746 --- /dev/null +++ b/docs/images/snippets/matrixsplit/f63067c2c3042c374a58dfa7f692309e.ascii @@ -0,0 +1,8 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ ┌ P ┐ ╮ + ┌ 1 0 0 ┐ │ ┌ 1 0 0 ┐ │ 1 │ │ + = ┌ 2 ┐ · │ -2 2 0 │ · │ │ -(z-1) z 0 │ · │ P │ │ + └ 1 t t ┘ └ 1 -2 1 ┘ │ │ 2 2 │ │ 2 │ │ + │ └ (z - 1) -2 · (z-1) · z z ┘ │ P │ │ + ╰ └ 3 ┘ ╯ diff --git a/docs/images/snippets/matrixsplit/f690ff0502d9fd7d4697cc43d98afd5d.ascii b/docs/images/snippets/matrixsplit/f690ff0502d9fd7d4697cc43d98afd5d.ascii new file mode 100644 index 00000000..a6db7a5e --- /dev/null +++ b/docs/images/snippets/matrixsplit/f690ff0502d9fd7d4697cc43d98afd5d.ascii @@ -0,0 +1,10 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ P ┐ + │ 1 │ + ┌ 1 0 0 0 ┐ │ P │ + B(t) = ┌ 2 3 ┐ · │ -3 3 0 0 │ · │ 2 │ + └ 1 t t t ┘ │ 3 -6 3 0 │ │ P │ + └ -1 3 -3 1 ┘ │ 3 │ + │ P │ + └ 4 ┘ diff --git a/docs/images/snippets/molding/6f12fcc00f4106bbc920d7451398d3b2.ascii b/docs/images/snippets/molding/6f12fcc00f4106bbc920d7451398d3b2.ascii new file mode 100644 index 00000000..59f99d3f --- /dev/null +++ b/docs/images/snippets/molding/6f12fcc00f4106bbc920d7451398d3b2.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C - B B - C + A = B - ───────── = B + ───────── + ratio(t) ratio(t) + q q diff --git a/docs/images/snippets/molding/70262c533569a7da06cc1b950e932d6f.ascii b/docs/images/snippets/molding/70262c533569a7da06cc1b950e932d6f.ascii new file mode 100644 index 00000000..c2870a14 --- /dev/null +++ b/docs/images/snippets/molding/70262c533569a7da06cc1b950e932d6f.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + C = u(t) · Start + (1-u(t) ) · End + q q diff --git a/docs/images/snippets/offsetting/3c80407cfd0bd8c8ebea239272aeabe5.ascii b/docs/images/snippets/offsetting/3c80407cfd0bd8c8ebea239272aeabe5.ascii new file mode 100644 index 00000000..83033f55 --- /dev/null +++ b/docs/images/snippets/offsetting/3c80407cfd0bd8c8ebea239272aeabe5.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + O(t) = B(t) + d diff --git a/docs/images/snippets/offsetting/57e62f3f2f7526b2cf7c1b276c17e472.ascii b/docs/images/snippets/offsetting/57e62f3f2f7526b2cf7c1b276c17e472.ascii new file mode 100644 index 00000000..b9a2c822 --- /dev/null +++ b/docs/images/snippets/offsetting/57e62f3f2f7526b2cf7c1b276c17e472.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ B'(t) ╮ + N(t) \bot │ ────────── │ + ╰ || B'(t)|| ╯ diff --git a/docs/images/snippets/offsetting/af4b584bb280cc941603255f62c9cc1a.ascii b/docs/images/snippets/offsetting/af4b584bb280cc941603255f62c9cc1a.ascii new file mode 100644 index 00000000..0b2ba0b8 --- /dev/null +++ b/docs/images/snippets/offsetting/af4b584bb280cc941603255f62c9cc1a.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌───────────────────┐ + ╭ 1 │ 2 2 + || B'(t)|| = | │B ''(t) + B ''(t) + ╯ 0 ⟍│ x y diff --git a/docs/images/snippets/offsetting/cf8e602eb0595cf4d9b851c6bda741af.ascii b/docs/images/snippets/offsetting/cf8e602eb0595cf4d9b851c6bda741af.ascii new file mode 100644 index 00000000..7c52ee92 --- /dev/null +++ b/docs/images/snippets/offsetting/cf8e602eb0595cf4d9b851c6bda741af.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌───────────┐ + ╭ b │ 2 2 + || f(x,y)|| = | │f ' + f ' + ╯ a ⟍│ x y diff --git a/docs/images/snippets/offsetting/de8cdb128273beff2d98534b9f090b85.ascii b/docs/images/snippets/offsetting/de8cdb128273beff2d98534b9f090b85.ascii new file mode 100644 index 00000000..05fe638f --- /dev/null +++ b/docs/images/snippets/offsetting/de8cdb128273beff2d98534b9f090b85.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + O(t) = B(t) + d · N(t) diff --git a/docs/images/snippets/pointcurves/4fe687c8a65265a2a755ba5841d0e31d.ascii b/docs/images/snippets/pointcurves/4fe687c8a65265a2a755ba5841d0e31d.ascii new file mode 100644 index 00000000..ba200658 --- /dev/null +++ b/docs/images/snippets/pointcurves/4fe687c8a65265a2a755ba5841d0e31d.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + d = { d if 0 ≤\phi ≤\pi + -d if \phi < 0 \lor \phi > \pi diff --git a/docs/images/snippets/pointcurves/8ffdd4a58cbd0fc24caef781f23a7950.ascii b/docs/images/snippets/pointcurves/8ffdd4a58cbd0fc24caef781f23a7950.ascii new file mode 100644 index 00000000..0801f31d --- /dev/null +++ b/docs/images/snippets/pointcurves/8ffdd4a58cbd0fc24caef781f23a7950.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ e = B + t · d + ╡ 1 + │ e = B - (1-t) · d + ╰ 2 diff --git a/docs/images/snippets/pointcurves/a5cd63b54be6b554290c38787cfbbabd.ascii b/docs/images/snippets/pointcurves/a5cd63b54be6b554290c38787cfbbabd.ascii new file mode 100644 index 00000000..aa3647b6 --- /dev/null +++ b/docs/images/snippets/pointcurves/a5cd63b54be6b554290c38787cfbbabd.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + \phi = (atan2(E -S , E -S ) - atan2(B -S , B -S ) + 2 \pi) mod 2 \pi + y y x x y y x x diff --git a/docs/images/snippets/pointcurves/f8182445c1cd7ae9f368b88fa7090e53.ascii b/docs/images/snippets/pointcurves/f8182445c1cd7ae9f368b88fa7090e53.ascii new file mode 100644 index 00000000..927d4218 --- /dev/null +++ b/docs/images/snippets/pointcurves/f8182445c1cd7ae9f368b88fa7090e53.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ d = || Start - B|| + │ 1 + │ d = || End - B|| + │ 2 + ╡ d + │ 1 + │ t= ───── + │ d +d + ╰ 1 2 diff --git a/docs/images/snippets/pointvectors/1df6c055ae8e41a46bfdebc55a4f17c0.ascii b/docs/images/snippets/pointvectors/1df6c055ae8e41a46bfdebc55a4f17c0.ascii new file mode 100644 index 00000000..cc4c2f12 --- /dev/null +++ b/docs/images/snippets/pointvectors/1df6c055ae8e41a46bfdebc55a4f17c0.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + x' = x · cos (\phi) - y · sin (\phi) + y' = x · sin (\phi) + y · cos (\phi) diff --git a/docs/images/snippets/pointvectors/58b19accb8a68c665ff5cbed610eea4e.ascii b/docs/images/snippets/pointvectors/58b19accb8a68c665ff5cbed610eea4e.ascii new file mode 100644 index 00000000..a2c7d26d --- /dev/null +++ b/docs/images/snippets/pointvectors/58b19accb8a68c665ff5cbed610eea4e.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ^ \pi ^ \pi ^ + normal (t) = x(t) · cos ─── - y(t) · sin ─── = - y(t) + x 2 2 + + ^ \pi ^ \pi ^ + normal (t) = \undersetquarter circle rotation \underbrace x(t) · sin ─── + y(t) · cos ─── = x(t) + y 2 2 diff --git a/docs/images/snippets/pointvectors/8b15a314beca97071b0ccb22c969355d.ascii b/docs/images/snippets/pointvectors/8b15a314beca97071b0ccb22c969355d.ascii new file mode 100644 index 00000000..37b640a4 --- /dev/null +++ b/docs/images/snippets/pointvectors/8b15a314beca97071b0ccb22c969355d.ascii @@ -0,0 +1,7 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + tangent (t) = B' (t) + x x + + tangent (t) = B' (t) + y y diff --git a/docs/images/snippets/pointvectors/b60cdba673c2c9fc84c800f07fd18145.ascii b/docs/images/snippets/pointvectors/b60cdba673c2c9fc84c800f07fd18145.ascii new file mode 100644 index 00000000..af541b1a --- /dev/null +++ b/docs/images/snippets/pointvectors/b60cdba673c2c9fc84c800f07fd18145.ascii @@ -0,0 +1,16 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌─────────────────┐ + │ 2 2 + d = \|tangent(t)\| = │B' (t) + B' (t) + ⟍│ x y + + tangent (t) B' (t) + ^ x x + x(t) = \|tangent (t)\| =────────────── = ────── + x \|tangent(t)\| d + + tangent (t) B' (t) + ^ y y + y(t) = \|tangent (t)\| = ────────────── = ────── + y \|tangent(t)\| d diff --git a/docs/images/snippets/pointvectors/f02e359a5e47667919738fff69d2625b.ascii b/docs/images/snippets/pointvectors/f02e359a5e47667919738fff69d2625b.ascii new file mode 100644 index 00000000..15a3c12b --- /dev/null +++ b/docs/images/snippets/pointvectors/f02e359a5e47667919738fff69d2625b.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ x' ┐ = ┌ cos (\phi) -sin (\phi) ┐ ┌ x ┐ + └ y' ┘ └ sin (\phi) cos (\phi) ┘ └ y ┘ diff --git a/docs/images/snippets/polybezier/a37252ff55837b918d9d64078ae92ae7.ascii b/docs/images/snippets/polybezier/a37252ff55837b918d9d64078ae92ae7.ascii new file mode 100644 index 00000000..89c0386b --- /dev/null +++ b/docs/images/snippets/polybezier/a37252ff55837b918d9d64078ae92ae7.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + B'(1) = B'(0) + n n+1 diff --git a/docs/images/snippets/polybezier/ec93d3c42f0ae52a05d0aff9739675e5.ascii b/docs/images/snippets/polybezier/ec93d3c42f0ae52a05d0aff9739675e5.ascii new file mode 100644 index 00000000..36d62e0d --- /dev/null +++ b/docs/images/snippets/polybezier/ec93d3c42f0ae52a05d0aff9739675e5.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ B + (B - A ) ┐ ┌ 2B - A ┐ + Mirrored = │ x x x │ = │ x x │ + │ B + (B - A ) │ │ 2B - A │ + └ y y y ┘ └ y y ┘ diff --git a/docs/images/snippets/reordering/056e25c397c524d80f378ce3823c7e78.ascii b/docs/images/snippets/reordering/056e25c397c524d80f378ce3823c7e78.ascii new file mode 100644 index 00000000..3e8a8c4e --- /dev/null +++ b/docs/images/snippets/reordering/056e25c397c524d80f378ce3823c7e78.ascii @@ -0,0 +1,21 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ┌ 1 0 . . . . . . ┐ + │ 1 k-1 │ + │ ─ ─── 0 . . . 0 . │ + │ k k │ + │ 2 k-2 │ + │ 0 ─ ─── 0 . . . . │ + │ k k │ + │ 3 k-3 │ + │ . 0 ─ ─── 0 . . . │ + M = │ k k │ + │ . . 0 ... ... 0 . . │ + │ . . . 0 ... ... 0 . │ + │ n-1 k-n+1 │ + │ . . . . 0 ─── ───── 0 │ + │ k k │ + │ n k-n │ + │ . 0 . . . 0 ─ ─── │ + │ k k │ + └ . . . . . . 0 1 ┘ diff --git a/docs/images/snippets/reordering/0f5698b31598b2390e966fc5e43ab53e.ascii b/docs/images/snippets/reordering/0f5698b31598b2390e966fc5e43ab53e.ascii new file mode 100644 index 00000000..3e1f720d --- /dev/null +++ b/docs/images/snippets/reordering/0f5698b31598b2390e966fc5e43ab53e.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + n n! n-i i + (1 - t) B (t)= (1-t) ──────── (1-t) t + i (n-i)!i! + n+1-i (n+1)! n+1-i i + = ───── ────────── (1-t) t + n+1 (n+1-i)!i! + k-i k! k-i i + = ─── ──────── (1-t) t , where k = n + 1 + k (k-i)!i! + k-i k + = ─── B (t) + k i diff --git a/docs/images/snippets/reordering/1f5b60d190a1c7099b3411e4cc477291.ascii b/docs/images/snippets/reordering/1f5b60d190a1c7099b3411e4cc477291.ascii new file mode 100644 index 00000000..ecbb65a0 --- /dev/null +++ b/docs/images/snippets/reordering/1f5b60d190a1c7099b3411e4cc477291.ascii @@ -0,0 +1,4 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + M B = B + n k diff --git a/docs/images/snippets/reordering/46e64dc07502e14217ec83d755f736ee.ascii b/docs/images/snippets/reordering/46e64dc07502e14217ec83d755f736ee.ascii new file mode 100644 index 00000000..48eaba44 --- /dev/null +++ b/docs/images/snippets/reordering/46e64dc07502e14217ec83d755f736ee.ascii @@ -0,0 +1,16 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + M B = B + n k + T T + (M M) B = M B + n k + T -1 T T -1 T + (M M) (M M) B = (M M) M B + n k + T -1 T + I B = (M M) M B + n k + T -1 T + B = (M M) M B + n k diff --git a/docs/images/snippets/reordering/4ff41e183d60d5fd10a5d3d30dd63358.ascii b/docs/images/snippets/reordering/4ff41e183d60d5fd10a5d3d30dd63358.ascii new file mode 100644 index 00000000..01aba82b --- /dev/null +++ b/docs/images/snippets/reordering/4ff41e183d60d5fd10a5d3d30dd63358.ascii @@ -0,0 +1,17 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n+1 n __ n+1 n + Bézier(n,t)= ❯ w (1 - t) B (t) + ❯ w t B (t) + ‾‾ i=0 i i ‾‾ i=0 i i + __ n+1 k-i k __ n+1 i+1 k + = ❯ w ─── B (t) + ❯ w ─── B (t), where k = n + 1 + ‾‾ i=0 i k i ‾‾ i=0 i k i+1 + __ n+1 k-i k __ n+1 i k + = ❯ w ─── B (t) + ❯ p ─ B (t) + ‾‾ i=0 i k i ‾‾ i=0 i-1 k i + __ n+1 ╭ k-i i ╮ k + = ❯ │ w ─── + p ─ │ B (t) + ‾‾ i=0 ╰ i k i-1 k ╯ i + __ n+1 k i + = ❯ (w (1-s) + p s) B (t), where s = ─ + ‾‾ i=0 i i-1 i k diff --git a/docs/images/snippets/reordering/56130afc4cb313e0e74cf670d34590f6.ascii b/docs/images/snippets/reordering/56130afc4cb313e0e74cf670d34590f6.ascii new file mode 100644 index 00000000..25164636 --- /dev/null +++ b/docs/images/snippets/reordering/56130afc4cb313e0e74cf670d34590f6.ascii @@ -0,0 +1,6 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + Bézier(n,t)= (1-t) B(n,t) + t B(n,t) + __ n n __ n n + = ❯ w (1 - t) B (t) + ❯ w t B (t) + ‾‾ i=0 i i ‾‾ i=0 i i diff --git a/docs/images/snippets/reordering/8090b63b005bf3edb916b97bda317a0e.ascii b/docs/images/snippets/reordering/8090b63b005bf3edb916b97bda317a0e.ascii new file mode 100644 index 00000000..9c7b7b40 --- /dev/null +++ b/docs/images/snippets/reordering/8090b63b005bf3edb916b97bda317a0e.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n n n n-i i + Bézier(n,t) = ❯ w B (t) , where B (t) = \binomni · (1-t) · t + ‾‾ i=0 i i i diff --git a/docs/images/snippets/reordering/ab7c087f7c070d43a42f3f03010a7427.ascii b/docs/images/snippets/reordering/ab7c087f7c070d43a42f3f03010a7427.ascii new file mode 100644 index 00000000..46d6d7ba --- /dev/null +++ b/docs/images/snippets/reordering/ab7c087f7c070d43a42f3f03010a7427.ascii @@ -0,0 +1,14 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + n n! n-i i + t B (t)= t ──────── (1-t) t + i (n-i)!i! + i+1 (n+1)! (n+1)-(i+1) i+1 + = ─── ──────────────────── (1-t) t + n+1 ((n+1)-(i+1))!(i+1)! + i+1 k! k-(i+1) i+1 + = ─── ──────────────── (1-t) t , where k = n + 1 + k (k-(i+1))!(i+1)! + i+1 k + = ─── B (t) + k i+1 diff --git a/docs/images/snippets/reordering/e9fc9c715bb55a702db68b2bb6da0a68.ascii b/docs/images/snippets/reordering/e9fc9c715bb55a702db68b2bb6da0a68.ascii new file mode 100644 index 00000000..62289a0c --- /dev/null +++ b/docs/images/snippets/reordering/e9fc9c715bb55a702db68b2bb6da0a68.ascii @@ -0,0 +1,9 @@ + \setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ k k-i i +Bézier(k,t) = ❯ \undersetbinomial term\underbrace\binomki · \ \undersetpolynomial term\underbrace(1-t) · t · \ \undersetnew + ‾‾ i=0 + ╭ (k-i) · w + i · w ╮ + │ i i-1 │ + weights\underbrace│ ─────────────────────── │ , with k = n+1 and w =0 when i = 0 + ╰ k ╯ i-1 diff --git a/docs/images/snippets/reordering/ff224ded6bbbc94b43130f5f8eeb5d29.ascii b/docs/images/snippets/reordering/ff224ded6bbbc94b43130f5f8eeb5d29.ascii new file mode 100644 index 00000000..055e773a --- /dev/null +++ b/docs/images/snippets/reordering/ff224ded6bbbc94b43130f5f8eeb5d29.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + x = 1 x = ((1-t) + t) x = (1-t) x + t x = x (1-t) + x t diff --git a/docs/images/snippets/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.ascii b/docs/images/snippets/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.ascii new file mode 100644 index 00000000..d08624b7 --- /dev/null +++ b/docs/images/snippets/weightcontrol/2ec04091c55fe31bf85ac28c5b6d95cb.ascii @@ -0,0 +1,9 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n n-i i + ❯ \binomni · (1-t) · t · w · \colorblueratio + ‾‾ i=0 i i + Rational Bézier(n,t) = ─────────────────────────────────────────────────────────── + __ n n-i i + \colorblue ❯ \binomni · (1-t) · t · ratio + ‾‾ i=0 i diff --git a/docs/images/snippets/weightcontrol/85d526fb17f9e859dcd7d40d22192e37.ascii b/docs/images/snippets/weightcontrol/85d526fb17f9e859dcd7d40d22192e37.ascii new file mode 100644 index 00000000..f1659f8a --- /dev/null +++ b/docs/images/snippets/weightcontrol/85d526fb17f9e859dcd7d40d22192e37.ascii @@ -0,0 +1,5 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n n-i i + Bézier(n,t) = ❯ \binomni · (1-t) · t · w + ‾‾ i=0 i diff --git a/docs/images/snippets/whatis/06bbc5c11ad3fd88ff93eb2c06177b66.ascii b/docs/images/snippets/whatis/06bbc5c11ad3fd88ff93eb2c06177b66.ascii new file mode 100644 index 00000000..f50f94c4 --- /dev/null +++ b/docs/images/snippets/whatis/06bbc5c11ad3fd88ff93eb2c06177b66.ascii @@ -0,0 +1,11 @@ +\usepackagexeCJK \xeCJKsetupCJKmath=true \setCJKmainfontipaexm.ttf + + ╭ p = 一方の点 ╮ + │ 1 │ + │ p = もう一方の点 │ + │ 2 │ + │ 距離= (p - p ) │のとき、新しい点 = p + 距離 · 比率 + │ 2 1 │ 1 + │ 百分率 │ + │ 比率= ─── │ + ╰ 100 ╯ diff --git a/docs/images/snippets/whatis/c3f06301f5ce610df1217bc633257297.ascii b/docs/images/snippets/whatis/c3f06301f5ce610df1217bc633257297.ascii new file mode 100644 index 00000000..5e5a7f9c --- /dev/null +++ b/docs/images/snippets/whatis/c3f06301f5ce610df1217bc633257297.ascii @@ -0,0 +1,11 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + ╭ p = some point ╮ + │ 1 │ + │ p = some other point │ + │ 2 │ + Given │ distance= (p - p ) │, our new point = p + distance · ratio + │ 2 1 │ 1 + │ percentage │ + │ ratio= ────────── │ + ╰ 100 ╯ diff --git a/docs/images/snippets/yforx/316e7fae61e10014000d770209779ab6.ascii b/docs/images/snippets/yforx/316e7fae61e10014000d770209779ab6.ascii new file mode 100644 index 00000000..19e4c64f --- /dev/null +++ b/docs/images/snippets/yforx/316e7fae61e10014000d770209779ab6.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + x(t) = a(1-t)³ + 3b(1-t)²t + 3c(1-t)t² + dt³ diff --git a/docs/images/snippets/yforx/4d23ee228c5b1cbc40e380496c2184d1.ascii b/docs/images/snippets/yforx/4d23ee228c5b1cbc40e380496c2184d1.ascii new file mode 100644 index 00000000..2f0edae6 --- /dev/null +++ b/docs/images/snippets/yforx/4d23ee228c5b1cbc40e380496c2184d1.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + x(t) = (-a + 3b- 3c + d)t³ + (3a - 6b + 3c)t² + (-3a + 3b)t + a diff --git a/docs/images/snippets/yforx/699459d89ca6622c90c1e42e4aa03f32.ascii b/docs/images/snippets/yforx/699459d89ca6622c90c1e42e4aa03f32.ascii new file mode 100644 index 00000000..898c5617 --- /dev/null +++ b/docs/images/snippets/yforx/699459d89ca6622c90c1e42e4aa03f32.ascii @@ -0,0 +1,3 @@ +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + (-a + 3b - 3c + d)t³ + (3a - 6b + 3c)t² + (-3a + 3b)t + (a-x) = 0 diff --git a/docs/index.html b/docs/index.html index cc51072a..e77526c3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -31,7 +31,7 @@ - + @@ -514,7 +514,20 @@ If we know the distance between those two points, and we want a new point that is, say, 20% the distance away from the first point (and thus 80% the distance away from the second point) then we can compute that really easily:

- + +

So let's look at that in action: the following graphic is interactive in that you can use your up and down arrow keys to increase or decrease the interpolation ratio, to see what happens. We start with three points, which gives us two lines. Linear interpolation over @@ -557,18 +570,37 @@ function". An illustration: Let's say we have a function that maps some value, let's call it x, to some other value, using some kind of number manipulation:

+

The notation f(x) is the standard way to show that it's a function (by convention called f if we're only listing one) and its output changes based on one variable (in this case, x). Change x, and the output for f(x) changes.

So far, so good. Now, let's look at parametric functions, and how they cheat. Let's take the following two functions:

+

There's nothing really remarkable about them, they're just a sine and cosine function, but you'll notice the inputs have different names. If we change the value for a, we're not going to change the output value for f(b), since a isn't used in that function. Parametric functions cheat by changing that. In a parametric function all the different functions share a variable, like this:

+ fa(t)
and fb(t) with what we usually mean with them for parametric curves, things might be a lot more obvious:

+

There we go. x/y coordinates, linked through some mystery value t.

@@ -606,6 +644,12 @@ binomial polynomials?

You may remember polynomials from high school. They're those sums that look like this:

+ a, b etc. taking the "binomial" form, which sounds fancy but is actually a pretty simple description for mixing values:

+ t and add in "times one", things suddenly look pretty easy. Check out these binomial terms:

+ (1-t) to a and t to b, and remove the weights for a moment, we get this:

+ + - + +

That looks complicated, but as it so happens, the "weights" are actually just the coordinate values we want our curve to have: for an nth order curve, w0 is our start coordinate, wn is our last coordinate, and everything in between is a controlling coordinate. Say we want a cubic curve that starts at (110,150), is controlled by (25,190) and (210,250) and ends at (210,30), we use this Bézier curve:

+

Which gives us the curve we saw at the top of the article:

@@ -1073,6 +1168,13 @@ function Bezier(3,t,w[]): the previous section, thereby gaining control over "how strongly" each coordinate influences the curve.

Adding these ratio values to the regular Bézier curve function is fairly easy. Where the regular function is the following:

+

The function for rational Bézier curves has two more terms:

+ @@ -1258,6 +1371,12 @@ function RationalBezier(3,t,w[],r[]): It all has to do with how we run from "the start" of our curve to "the end" of our curve. If we have a value that is a mixture of two other values, then the general formula for this is:

+

The obvious start and end values here need to be a=1, b=0, so that the mixed value is 100% value 1, and 0% value 2, and @@ -1267,6 +1386,12 @@ function RationalBezier(3,t,w[],r[]): and end point, so we need to make sure we can never set "a" and "b" to some values that lead to a mix value that sums to more than 100%. And that's easy:

+

With this we can guarantee that we never sum above 100%. By restricting a to values in the interval [0,1], we will always be @@ -1333,27 +1458,122 @@ function RationalBezier(3,t,w[],r[]): coefficients matrix, and the actual coordinates as a matrix. Let's look at what this means for the cubic curve, using P... to refer to coordinate values "in one or more dimensions":

+

Disregarding our actual coordinates for a moment, we have:

+

We can write this as a sum of four expressions:

+

And we can expand these expressions:

+

Furthermore, we can make all the 1 and 0 factors explicit:

+

And that, we can view as a series of four matrix operations:

+

If we compact this into a single matrix operation, we get:

+

This kind of polynomial basis representation is generally written with the bases in increasing order, which means we need to flip our t matrix horizontally, and our big "mixing" matrix upside down:

+

And then finally, we can add in our original coordinates as a single third matrix:

+

We can perform the same trick for the quadratic curve, in which case we end up with:

+

If we plug in a t value, and then multiply the matrices, we will get exactly the same values as when we evaluate the original @@ -1755,6 +1975,16 @@ function drawCurve(points[], t): we saw that we can represent curves as matrix multiplications. Specifically, we saw these two forms for the quadratic and cubic curves respectively: (we'll reverse the Bézier coefficients vector for legibility)

+

and

+ +

and

+ + + + + T · M · P]), with a new set of coordinates that represent the curve from t = 0 to t = z. So let's get computing:

+

Excellent! Now we can form our new quadratic curve:

+ + + z]. We were able to write it down in a more simple form because of the zero, but what we actually evaluated, making the zero explicit, was:

+ +

If we want the interval [z,1], we will be evaluating this instead:

+ + [something · M] into [M · something]:

+

So, our final second curve looks like:

+ + + t = z, we get two subcurves that are described as Bézier curves with simple-to-derive coordinates:

+

and

+ +

and

+ nth order curve to an (n+1)th order curve is as follows (observing that the start and end weights are the same as the start and end weights for the old curve):

- + +

However, this rule also has as direct consequence that you cannot generally safely lower a curve from nth order to (n-1)th order, because the control points cannot be "pulled apart" cleanly. We can @@ -2037,22 +2522,58 @@ function drawCurve(points[], t): some things can be done much more easily with matrices than with calculus functions, and this is one of those things. So... let's go!

We start by taking the standard Bézier function, and condensing it a little:

+

Then, we apply one of those silly (actually, super useful) calculus tricks: since our t value is always between zero and one (inclusive), we know that (1-t) plus t always sums to 1. As such, we can express any value as a sum of t and 1-t:

+

So, with that seemingly trivial observation, we rewrite that Bézier function by splitting it up into a sum of a (1-t) and t component:

+

So far so good. Now, to see why we did this, let's write out the (1-t) and t parts, and see what that gives us. I promise, it's about to make sense. We start with (1-t):

+ t part, but that's not a problem:

+

Let's do this:

+ +

where the matrix M is an n+1 by n matrix, and looks like:

+ A x = b, we can use it. And as it so happens, that's exactly what we're dealing with, so:

+

First, let's look at the derivative rule for Bézier curves, which is:

+ b in this formula is the same as our w weights, and that n times a summation is the same as a summation where each term is multiplied by n) as:

+ + product and chain rules gives us:

+

Which is hard to work with, so let's expand that properly:

+ n-1 and k-1, we'll be on the right track.

+

And that's the first part done: the two components inside the parentheses are actually regular, lower-order Bézier expressions:

+ + k we see the following:

+ . This term would have a binomial coefficient of [i choose i+1], which is a non-existent binomial coefficient. Again, this term would contribute "nothing", so we can ignore it, too. This means we're left with:

+

And that's just a summation of lower order curves:

+

We can rewrite this as a normal summation, and we're done:

+ + + + + + t? In that case we want the normal vector. This vector runs at a right angle to the direction of the curve, and is typically of length 1.0, so all we have to do is rotate the normalized directional vector and we're done:

+ To turn any point (x,y) into a rotated point (x',y') (over 0,0) by some angle φ, we apply this nice and easy computation:

+

Which is the "long" version of the following matrix transformation:

+ frames: cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the derivatives section:

+ frames: loading="lazy" />

And then we turn this into our solution for t using basic arithmetics:

+ frames: the Quadratic formula. If you've seen it before, you'll remember it, and if you haven't, it looks like this:

+ frames: First we turn our cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the derivatives section:

+

And then, using these v values, we can find out what our a, b, and c should be:

+ frames: This gives us three coefficients {a, b, c} that are expressed in terms of v values, where the v values are expressions of our original coordinate values, so we can do some substitution to get:

+ frames: Gerolamo Cardano figured out that even if the general cubic function is really hard to solve, it can be rewritten to a form for which finding the roots is "easier" (even if not "easy"):

+ x, at step n=1, we perform the following calculation until fy(x) is zero, so that the next t is the same as the one we already have:

+ n-2 term function. For instance, if we have a cubic curve such as this:

- + +

Then translating it so that the first coordinate lies on (0,0), moving all x coordinates by -120, and all y coordinates by -160, gives us:

- + +

If we then rotate the curve so that its end point lies on the x-axis, the coordinates (integer-rounded for illustrative purposes here) become:

- + +

If we drop all the zero-terms, this gives us:

- + +

We can see that our original curve definition has been simplified considerably. The following graphics illustrate the result of aligning our example curves to the x-axis, with the cubic case using the coordinates that were just used in the example formulae: @@ -3554,12 +4458,23 @@ function getCubicRoots(pa, pb, pc, pd) { inflection, and we can find out where those happen relatively easily.

What we need to do is solve a simple equation:

+

What we're saying here is that given the curvature function C(t), we want to know for which values of t this function is zero, meaning there is no "curvature", which will be exactly at the point between our circle being on one side of the curve, and our circle being on the other side of the curve. So what does C(t) look like? Actually something that seems not too hard:

+ +

And of course the same functions for y:

+ C(t) function for us (and to expand it to a readable form of simple terms) gives us this rather overly complicated set of arithmetic expressions:

+ t values, we end up with the following simple term function for C(t):

+ +

This is a plain quadratic curve, and we know how to solve C(t) = 0; we use the quadratic formula:

+ where, but we know there is one. This edge is described by the function:

+ +
  • ...on the top (blue) edge, the curve's start point touches the curve, forming a loop. This edge is described by the function:

    + z coordinate that is always 1, then we can suddenly add arbitrary values. For example:

    +

    Sweet! z stays 1, so we can effectively ignore it entirely, but we added some plain values to our x and y coordinates. So, if we want to subtract p1.x and p1.y, we use:

    +

    Running all our coordinates through this transformation gives a new set of coordinates, let's call those U, where the @@ -3807,11 +4831,29 @@ function getCubicRoots(pa, pb, pc, pd) { currently have. This is called shearing, and the typical x-shear matrix and its transformation looks like this:

    +

    So we want some shearing value that, when multiplied by y, yields -x, so our x coordinate becomes zero. That value is simply -x/y, because *-x/y * y = -x*. Done:

    +

    Now, running this on all our points generates a new set of coordinates, let's call those V, which now have point 1 on @@ -3820,6 +4862,19 @@ function getCubicRoots(pa, pb, pc, pd) { point 3 to end up on (1,1), so we can also scale x to make sure its x-coordinate will be 1 after we run the transform. That means we'll be x-scaling by 1/point3x, and y-scaling by point2y. This is really easy:

    +

    Then, finally, this generates a new set of coordinates, let's call those W, of which point 1 lies on (0,0), point 2 lies on (0,1), and @@ -3829,12 +4884,49 @@ function getCubicRoots(pa, pb, pc, pd) { but y-shearing. Additionally, we don't actually want to end up at zero (which is what we did before) so we need to shear towards an offset, in this case 1:

    +

    And this generates our final set of four coordinates. Of these, we already know that points 1 through 3 are (0,0), (0,1) and (1,1), and only the last coordinate is "free". In fact, given any four starting coordinates, the resulting "transformation mapped" coordinate will be:

    +

    Okay, well, that looks plain ridiculous, but: notice that every coordinate value is being offset by the initial translation, and also @@ -3845,12 +4937,36 @@ function getCubicRoots(pa, pb, pc, pd) { First, let's just do that translation step as a "preprocessing" operation so we don't have to subtract the values all the time. What does that leave?

    +

    Suddenly things look a lot simpler: the mapped x is fairly straight forward to compute, and we see that the mapped y actually contains the mapped x in its entirety, so we'll have that part already available when we need to evaluate it. In fact, let's pull out all those common factors to see just how simple this is:

    +

    That's kind of super-simple to write out in code, I think you'll agree. Coding math tends to be easier than the formulae initially make it @@ -3925,16 +5041,31 @@ function getCubicRoots(pa, pb, pc, pd) { cubic case either: because of the kind of curve we're starting with, we know there is only root, simplifying the code we need!

    First, let's look at the function for x(t):

    +

    We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:

    +

    Nothing special here: that's a standard cubic polynomial in "power" form (i.e. all the terms are ordered by their power of t). So, given that a, b, c, d, and x(t) are all known constants, we can trivially rewrite this (by moving the x(t) across the equal sign) as:

    +

    You might be wondering "where did all the other 'minus x' for all the other values a, b, c, and d go?" and the answer there is that they @@ -4014,8 +5145,24 @@ y = curve.get(t).yfy(t), then the length of the curve, measured from start point to some point t = z, is computed using the following seemingly straight forward (if a bit overwhelming) formula:

    +

    or, more commonly written using Leibnitz notation as:

    +

    This formula says that the length of a parametric curve is in fact equal to the area underneath a function that looks a @@ -4042,7 +5189,18 @@ y = curve.get(t).y - + +

    In plain text: an integral function can always be treated as the sum of an (infinite) number of (infinitely thin) rectangular strips sitting "under" the function's plotted graph. To illustrate this idea, the following graph shows the integral for a sinusoid function. The @@ -4102,6 +5260,20 @@ y = curve.get(t).yz). Thankfully, we can quite easily transform any integral interval to any other integral interval, by shifting and scaling the inputs. Doing so, we get the following:

    + n, so if we want to approximate our integral with only two terms (which is a bit low, really) then these tables would tell us that for n=2 we must use the following values:

    +

    Which means that in order for us to approximate the integral, we must plug these values into the approximate function, which gives us:

    +

    So, what does the function look like? This:

    +

    Which is really just a "short form" that glosses over the fact that we're dealing with functions of t, so let's expand that a tiny bit:

    +

    And while that's a little more verbose, it's still just as simple to work with as the first function: the curvature at some point on any @@ -4343,6 +5562,13 @@ function kappa(t, B): just do that. But let's take it one step further: we can also compute the associated "radius of curvature", which gives us the implicit circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:

    +

    So let's revisit the previous graphic with the curvature visualised on both sides of our curves, as well as showing the circle that "fits" @@ -4741,6 +5967,12 @@ lli = function(line1, line2): So, how can we compute C? We start with our observation that C always lies somewhere between the start and ends points, so logically C will have a function that interpolates between those two coordinates:

    +

    If we can figure out what the function u(t) looks like, we'll be done. Although we do need to remember that this @@ -4750,8 +5982,26 @@ lli = function(line1, line2): > (with thanks to Boris Zbarsky) shows us the following two formulae:

    +

    And

    +

    So, if we know the start and end coordinates, and we know the t value, we know C, without having to calculate the @@ -4760,10 +6010,35 @@ lli = function(line1, line2): pure function of t, too.

    We start by observing that, given A, B, and C, the following always holds:

    +

    Working out the maths for this, we see the following two formulae for quadratic and cubic curves:

    +

    And

    +

    Which now leaves us with some powerful tools: given thee points (start, end, and "some point on the curve"), as well as a @@ -4771,6 +6046,13 @@ lli = function(line1, line2): u(t) function, and once we have C, we can use our on-curve point (B) and the ratio(t) function to find A:

    +

    With A found, finding e1 and e2 for quadratic curves is a matter of running the linear @@ -4779,8 +6061,32 @@ lli = function(line1, line2): distance ratio between e1 to B and B to e2 is the Bézier ratio (1-t):t, we can reverse engineer v1 and v2:

    +

    And then reverse engineer the curve's control control points:

    +

    So: if we have a curve's start and end point, then for any t value we implicitly know all the ABC values, which (combined @@ -4804,6 +6110,19 @@ lli = function(line1, line2): in computing the ABC coordinates, but we can just as easily approximate one by treating the distance between the start and B point, and B and end point as a ratio, using

    + t value, and then our e1 and e2 coordinates must obey the standard de Casteljau rule for linear interpolation:

    + d depending on which side of the baseline our B is located, so we don't up creating a funky curve with a loop in it. To do this, we can use the atan2 function:

    + d:

    + B coordinate. We don't even need the latter: with our t value and "wherever the cursor is" as target B, we can compute the associated C:

    +

    And then the associated A:

    +

    And we're done, because that's our new quadratic control point!

    +

    And then we (trivially) rearrange the terms across multiple lines:

    +

    With that arrangement, we can easily decompose this as a matrix multiplication:

    +

    We can do the same for the cubic curve, of course. We know the base function for cubics:

    +

    So we write out the expansion and rearrange:

    +

    Which we can then decompose:

    +

    And, of course, we can do this for quartic curves too (skipping the expansion step):

    + th order curve, so we "start" with a vector P that represents the coordinates we already know, and for which we want to do curve fitting:

    + t is equal to the distance along the polygon, scaled to the [0,1] domain.

    To get these values, we first compute the general "distance along the polygon" matrix:

    + i=1 and i=n fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:

    + t value", which we'll square to get rid of any pesky negative signs:

    + + P coordinate matrix, and we can replace Bézier(si) with the matrix representation T x M x C we talked about before, which gives us:

    +

    In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:

    + S, so we need to form a new matrix, which we'll call 𝕋, that makes use of those, and then use that 𝕋 instead of T in our error function:

    +

    Which, because of the first and last values in S, means:

    +

    Now we can properly write out the error function as matrix operations:

    + + C:

    + can trivially be derived from knowing the previous and next point:

    + very similar, so let's see exactly how similar they are. We've already see the matrix form for Bézier curves, so how different is the matrix form for Catmull-Rom curves?:

    + P coordinates, by applying "some matrix T". We don't know what that T is yet, but we'll get to that:

    +

    Computing T is really more "arranging the numbers":

    +

    Thus:

    + T:

    + +

    Replace point/tangent vector with the expression for all-coordinates:

    +

    and merge the matrices:

    +

    This looks a lot like the Bézier matrix form, which as we saw in the chapter on Bézier curves, should look like this:

    +

    So, if we want to express a Catmull-Rom curve using a Bézier curve, we'll need to turn this Catmull-Rom bit:

    +

    Into something that looks like this:

    +

    And the way we do that is with a fairly straight forward bit of matrix rewriting. We start with the equality we need to ensure:

    +

    Then we remove the coordinate vector from both sides without affecting the equality:

    +

    Then we can "get rid of" the Bézier matrix on the right by left-multiply both with the inverse of the Bézier matrix:

    + +

    And now we're basically done. We just multiply those two matrices and we know what V is:

    +
  • Start with the Catmull-Rom function:
  • +
  • rewrite to pure coordinate form:
  • +
  • rewrite for "normal" coordinate vector:
  • +
  • merge the inner matrices:
  • +
  • rewrite for Bézier matrix form:
  • +
  • and transform the coordinates so we have a "pure" Bézier expression:
  • + 1 through P4, then we can draw that curve using a Bézier curve that has the vector:

    + 1 through P4, we can draw that using a standard tension Catmull-Rom curve with the following coordinate values:

    +

    Or, if your API allows you to specify Catmull-Rom curves using plain coordinates:

    + +

    We can effect this quite easily, because we know that the vector from a curve's last control point to its last on-curve point is equal to the derivative vector. If we want to ensure that the first control point of the next curve matches that, all we have to do is mirror that last control point through the last on-curve point. And mirroring any point A through any point B is really simple:

    +

    So let's implement that and see what it gets us. The following two graphics show a quadratic and a cubic poly-Bézier curve again, but this @@ -6070,6 +7951,11 @@ for p = 1 to points.length-3 (inclusive): From a mathematical point of view, an offset curve O(t) is a curve such that, given our original curve B(t), any point on O(t) is a fixed distance d away from coordinate B(t). So let's math that:

    + B(t), where the "normal" is a vector that runs perpendicular ("at a right angle") to the tangent at B(t). Easy enough:

    + N(t) always has length 1, which we can achieve by dividing B'(t) by its magnitude:

    + a to end b, we must use the formula we saw earlier. Noting that "length" is usually denoted with double vertical bars:

    + So if we want the length of the tangent, we plug in B'(t), with t = 0 as start and t = 1 as end:

    + φ:

    - + +

    What we want to find is the intersection of the tangents, so we want a point C such that:

    - + +

    i.e. we want a point that lies on the vertical line through S (at some distance a from S) and also lies on the tangent line through E (at some distance b from E). Solving this gives us:

    +

    First we solve for b:

    - + +

    which yields:

    +

    which we can then substitute in the expression for a:

    +

    A quick check shows that plugging these values for a and b into the expressions for Cx and Cy give @@ -6332,13 +8299,54 @@ for p = 1 to points.length-3 (inclusive): coordinate values for C, we know where our on-curve point T for t=0.5 (or angle φ/2) is, because we can just evaluate the Bézier polynomial, and we know where the circle arc's actual point P is for angle φ/2:

    - + +

    We compute T, observing that if t=0.5, the polynomial values (1-t)², 2(1-t)t, and t² are 0.25, 0.5, and 0.25 respectively:

    +

    Which, worked out for the x and y components, gives:

    +

    And the distance between these two is the standard Euclidean distance:

    - + +

    So, what does this distance function look like when we plot it for a number of ranges for the angle φ, such as a half circle, quarter circle and eighth circle? @@ -6379,6 +8387,16 @@ for p = 1 to points.length-3 (inclusive): In fact, let's flip the function around, so that if we plug in the precision error, labelled ε, we get back the maximum angle for that precision:

    +

    And frankly, things are starting to look a bit ridiculous at this point, we're doing way more maths than we've ever done, but thankfully @@ -6482,9 +8500,16 @@ for p = 1 to points.length-3 (inclusive): So with the error analysis out of the way, how do we actually compute the coordinates needed to get that "true fit" cubic curve? The first observation is that we already know the start and end points, because they're the same as for the quadratic attempt:

    + +

    where "a" is some scaling factor we'll need to find the expression for, and:

    + t=0.5 as our point "B" in the "A,B,C" projection, then we know the length of the line segment {C,A}, since it's d1 = {A,B} + d2 = {B,C}:

    + t=0.5 point, minus the distance from the centre to the line that runs from start point to end point. The first is the same as the point P we found for the quadratic curve:

    + + + + 1:

    + 1, we can find C2 fairly simply, since it's lies at distance -C1y along the end point's tangent:

    +

    So, to recap, given an angle φ, the new control coordinates are:

    +

    and

    + +

    Which, in decimal values, rounded to six significant digits, is:

    + , we can compute a point on the curve for some value t in the interval [0,1] (where 0 is the start of the curve, and 1 the end, just like for Bézier curves), by evaluating the following function:

    +

    Which, honestly, doesn't tell us all that much. All we can see is that a point on a B-Spline curve is defined as "a mix of all the control @@ -6843,6 +8998,15 @@ for p = 1 to points.length-3 (inclusive): k subscript to the N() function applies to.

    Then the N() function itself. What does it look like?

    +

    So this is where we see the interpolation: N(t) for an (i,k) pair (that is, for a step in the above summation, on a specific @@ -6850,6 +9014,13 @@ for p = 1 to points.length-3 (inclusive): iteration where i goes up, and k goes down, so it seem reasonable to expect that this recursion has to stop at some point; obviously, it does, and specifically it does so for the following i/k values:

    +

    And this function finally has a straight up evaluation: if a t value lies within a knot-specific interval once we reach a @@ -6867,11 +9038,25 @@ for p = 1 to points.length-3 (inclusive): Carl de Boor — came to a mathematically pleasing solution: to compute a point P(t), we can compute this point by evaluating d(t) on a curve section between knots i and i+1:

    +

    This is another recursive function, with k values decreasing from the curve order to 1, and the value α (alpha) defined by:

    +

    That looks complicated, but it's not. Computing alpha is just a fraction involving known, plain numbers. And, once we have our alpha @@ -6880,7 +9065,14 @@ for p = 1 to points.length-3 (inclusive): recursion might see computationally expensive, the total algorithm is cheap, as each step only involves very simple maths.

    Of course, the recursion does need a stop condition:

    - + +

    So, we actually see two stopping conditions: either i becomes 0, in which case d() is zero, or k becomes zero, in which case we get the same "either 1 or 0" that we saw in the N() function above. @@ -6890,7 +9082,39 @@ for p = 1 to points.length-3 (inclusive): Casteljau's algorithm. For instance, if we write out d() for i=3 and k=3, we get the following recursion diagram:

    - + +

    That is, we compute d(3,3) as a mixture of d(2,3) and d(2,2), where those two are themselves a mixture of d(1,3) and d(1,2), and d(1,2) and d(1,1), respectively, which are diff --git a/docs/ja-JP/index.html b/docs/ja-JP/index.html index d37298bb..26a6f398 100644 --- a/docs/ja-JP/index.html +++ b/docs/ja-JP/index.html @@ -33,7 +33,7 @@ - + @@ -492,6 +492,19 @@

    例えば、2点間の距離がわかっているとして、一方の点から距離の20%だけ離れた(すなわち、もう一方の点から80%離れた)新しい点を求めたい場合、次のようにとても簡単に計算できます。

    +

    では、実際に見てみましょう。下の図はインタラクティブになっています。上下キーで補間の比率が増減しますので、どうなるか確かめてみましょう。最初に3点があり、それを結んで2本の直線が引かれています。この直線の上でそれぞれ線形補間を行うと、2つの点が得られます。この2点の間でさらに線形補間を行うと、1つの点を得ることができます。そして、あらゆる比率に対して同様に点を求め、それをすべて集めると、このようにベジエ曲線ができるのです。 @@ -520,16 +533,35 @@

    ベジエ曲線は「パラメトリック」関数の一種です。数学的に言えば、パラメトリック関数というのはインチキです。というのも、「関数」はきっちり定義された用語であり、いくつかの入力を1つの出力に対応させる写像を表すものだからです。いくつかの数値を入れると、1つの数値が出てきます。入れる数値が変わっても、出てくる数値はやはり1つだけです。パラメトリック関数はインチキです。基本的には「じゃあわかった、値を複数個出したいから、関数を複数個使うことにするよ」ということです。例として、ある値xに何らかの操作を行い、別の値へと写す関数があるとします。

    +

    f(x)という記法は、これが関数(1つしかない場合は慣習的にfと呼びます)であり、その出力が1つの変数(この場合はxです)に応じて変化する、ということを示す標準的な方法です。xを変化させると、f(x)の出力が変化します。

    ここまでは順調です。では、パラメトリック関数について、これがどうインチキなのかを見てみましょう。以下の2つの関数を考えます。

    +

    注目すべき箇所は特に何もありません。ただの正弦関数と余弦関数です。ただし、入力が別々の名前になっていることに気づくでしょう。仮にaの値を変えたとしても、f(b)の出力の値は変わらないはずです。なぜなら、こちらの関数にはaは使われていないからです。パラメトリック関数は、これを変えてしまうのでインチキなのです。パラメトリック関数においては、どの関数も変数を共有しています。例えば、

    + 複数の関数がありますが、変数は1つだけです。tの値を変えた場合、fa(t)fb(t)の両方の出力が変わります。これがどのように役に立つのか、疑問に思うかもしれません。しかし、実際には答えは至ってシンプルです。fa(t)fb(t)のラベルを、パラメトリック曲線の表示によく使われているもので置き換えてやれば、ぐっとはっきりするかと思います。

    +

    きました。x/y座標です。謎の値tを通して繫がっています。

    @@ -558,6 +596,12 @@ ベジエ曲線はパラメトリック関数の一種であり、どの次元に対しても同じ基底関数を使うという点で特徴づけられます。先ほどの例では、xの値とyの値とで異なる関数(正弦関数と余弦関数)を使っていましたが、ベジエ曲線ではxyの両方で「二項係数多項式」を使います。では、二項係数多項式とは何でしょう?

    高校で習った、こんな形の多項式を思い出すかもしれません。

    + ベジエ曲線はxの多項式ではなく、tの多項式です。tの値は0から1までの間に制限され、その係数abなどは「二項係数」の形をとります。というと複雑そうに聞こえますが、実際には値を組み合わせて、とてもシンプルに記述できます。

    + 「そこまでシンプルには見えないよ」と思っていることでしょう。しかし仮に、tを取り去って係数に1を掛けることにしてしまえば、急激に簡単になります。これが二項係数部分の項です。

    + 多項式部分の項がどうなっているのか、同じぐらい簡単な方法で考えることができます。仮に、(1-t)aに、tbに書き換え、さらに重みを一旦削除してしまえば、このようになります。

    + これは要するに、「abのすべての組み合わせ」の単なる和です。プラスが出てくるたびに、abへと1つずつ置き換えていけばよいのです。こちらも本当に単純です。さて、これで「二項係数多項式」がわかりました。完璧を期するため、この関数の一般の形を示しておきます。

    + 曲線を変更したい場合は、各点の重みを変える(実質的には補間率を変える)必要があります。これはとても単純で、寄与の大きさを変えるための値を、各点にただ掛ければいいのです。この値は「重み」と呼ばれていますが、これを元のベジエ関数に組み込めば、次のようになります。

    +

    複雑そうに見えますが、運がいいことに「重み」というのは実はただの座標値です。というのはn次の曲線の場合、w0が始点の座標、wnが終点の座標となり、その間はどれも制御点の座標になります。例えば、始点が(120,160)、制御点が(35,200)と(220,260)、終点が(220,40)となる3次ベジエ曲線は、次のようになります。

    +

    この式からは、記事の冒頭に出てきた曲線が得られます。

    @@ -990,6 +1083,13 @@ function Bezier(3,t,w[]): the previous section, thereby gaining control over "how strongly" each coordinate influences the curve.

    Adding these ratio values to the regular Bézier curve function is fairly easy. Where the regular function is the following:

    +

    The function for rational Bézier curves has two more terms:

    + @@ -1173,12 +1284,24 @@ function RationalBezier(3,t,w[],r[]):

    このことは、曲線の「始点」から曲線の「終点」までどうやって動かすか、ということにすべて関係しています。2つの値を混ぜ合わせて1つの値をつくる場合、一般の式は次のようになります。

    +

    明らかに、始点ではa=1, b=0とする必要があります。こうすれば、値1が100%、値2が0%で混ぜ合わさるからです。また、終点ではa=0, b=1とする必要があります。こうすれば、値1が0%、値2が100%で混ぜ合わさります。これに加えて、abを独立にしておきたくはありません。独立になっている場合、何でも好きな値にすることできますが、こうすると例えば「値1が100%かつ値2が100%」のようなことが可能になってしまいます。これはこれで原則としてはかまいませんが、ベジエ曲線の場合は混ぜ合わさった値が常に始点と終点のになってほしいのです。というわけで、混ぜ合わせの和が100%を決して超えないように、abの値を設定する必要があります。これは次のようにすれば簡単です。

    +

    こうすれば、和が100%を超えることはないと保証できます。aの値を区間[0,1]に制限してしまえば、混ぜ合わさった値は常に2つの値の間のどこか(両端を含む)になり、また和は常に100%になります。 @@ -1229,26 +1352,121 @@ function RationalBezier(3,t,w[],r[]):

    ベジエ曲線は、行列演算の形でも表現することができます。ベジエ曲線の式を多項式基底と係数行列で表し、実際の座標も行列として表現するのです。これがどういうことを意味しているのか、3次ベジエ曲線について見てみましょう。

    +

    実際の座標を一旦無視すると、次のようになります。

    +

    これは、4つの項の和になっています。

    +

    それぞれの項を展開します。

    +

    その上で、係数の0や1もすべて明示的に書けば、このようになります。

    +

    さらに、これは4つの行列演算の和として見ることができます。

    +

    これを1つの行列演算にまとめると、以下のようになります。

    +

    多項式基底をこのような形で表現する場合、通常はその基底を昇冪の順に並べます。したがって、tの行列を左右反転させ、大きな「混合」行列は上下に反転させる必要があります。

    +

    そして最後に、もともとあった座標を3番目の行列として付け加えます。

    +

    2次ベジエ曲線の場合も同様に変形することができ、最終的には以下のようになります。

    +

    t行列についての節では、行列の乗算で曲線が表現できることを確認しました。特に2次・3次のベジエ曲線に関しては、それぞれ以下のような形になりました(読みやすさのため、ベジエの係数ベクトルを反転させています)。

    +

    ならびに

    + t = zで分割し、新しく2つの(自明ですが、より短い)ベジエ曲線を作ることを考えましょう。曲線の行列表現と線形代数を利用すると、この2つのベジエ曲線の座標を求めることができます。まず、実際の「曲線上の点」の情報を分解し、新しい行列の積のかたちにします。

    +

    ならびに

    + 曲線を分割して2つの部分を得るためには、いくつかの段階を経る必要があります。曲線の次数が高くなるほど手間がかかるようになりますので、まずは2次の曲線で見てみましょう。

    + + + + ]の値が分かれば、それを座標に掛け合わせることによって、2次ベジエ曲線の正しい行列表現(すなわち[T · M · P])と、t = 0からt = zまでの曲線を表す座標の組とが得られます。では、計算してみましょう。

    +

    いいですね!これで、新しい2次ベジエ曲線が得られます。

    + + + t = zからt = 1の部分を得るためには、同様の計算をする必要があります。まず、今さっき行ったのは、一般の区間[0,z]についての計算でした。これは0があるので簡単な形になっていましたが、実際には、次の式を計算していたということがわかります。

    + +

    区間[z,1]を求めたい場合は、かわりに次のような計算になります。

    + +

    先ほどと同じ手法を使い、[なにか · M]を[M · なにか]に変えます。

    +

    よって、後半部分の曲線は結局のところ以下のようになります。

    + + + t = zで分割すれば2つのベジエ曲線となり、しかもその座標は簡単に求められる、ということがわかりました。

    +

    および

    + 3次の曲線についても同様です。ただし、実際の導出はあなたにとっておきますので(自力で書き下してみてください)、新しい座標の組の結果を示すだけにします。

    +

    および

    + nth order curve to an (n+1)th order curve is as follows (observing that the start and end weights are the same as the start and end weights for the old curve):

    - + +

    However, this rule also has as direct consequence that you cannot generally safely lower a curve from nth order to (n-1)th order, because the control points cannot be "pulled apart" cleanly. We can @@ -1882,22 +2365,58 @@ function drawCurve(points[], t): some things can be done much more easily with matrices than with calculus functions, and this is one of those things. So... let's go!

    We start by taking the standard Bézier function, and condensing it a little:

    +

    Then, we apply one of those silly (actually, super useful) calculus tricks: since our t value is always between zero and one (inclusive), we know that (1-t) plus t always sums to 1. As such, we can express any value as a sum of t and 1-t:

    +

    So, with that seemingly trivial observation, we rewrite that Bézier function by splitting it up into a sum of a (1-t) and t component:

    +

    So far so good. Now, to see why we did this, let's write out the (1-t) and t parts, and see what that gives us. I promise, it's about to make sense. We start with (1-t):

    + t part, but that's not a problem:

    +

    Let's do this:

    + +

    where the matrix M is an n+1 by n matrix, and looks like:

    + A x = b, we can use it. And as it so happens, that's exactly what we're dealing with, so:

    +

    First, let's look at the derivative rule for Bézier curves, which is:

    + b in this formula is the same as our w weights, and that n times a summation is the same as a summation where each term is multiplied by n) as:

    + + product and chain rules gives us:

    +

    Which is hard to work with, so let's expand that properly:

    + n-1 and k-1, we'll be on the right track.

    +

    And that's the first part done: the two components inside the parentheses are actually regular, lower-order Bézier expressions:

    + + k we see the following:

    + . This term would have a binomial coefficient of [i choose i+1], which is a non-existent binomial coefficient. Again, this term would contribute "nothing", so we can ignore it, too. This means we're left with:

    +

    And that's just a summation of lower order curves:

    +

    We can rewrite this as a normal summation, and we're done:

    + + + + + + t? In that case we want the normal vector. This vector runs at a right angle to the direction of the curve, and is typically of length 1.0, so all we have to do is rotate the normalized directional vector and we're done:

    + To turn any point (x,y) into a rotated point (x',y') (over 0,0) by some angle φ, we apply this nice and easy computation:

    +

    Which is the "long" version of the following matrix transformation:

    + frames: cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the derivatives section:

    + frames: loading="lazy" />

    And then we turn this into our solution for t using basic arithmetics:

    + frames: the Quadratic formula. If you've seen it before, you'll remember it, and if you haven't, it looks like this:

    + frames: First we turn our cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the derivatives section:

    +

    And then, using these v values, we can find out what our a, b, and c should be:

    + frames: This gives us three coefficients {a, b, c} that are expressed in terms of v values, where the v values are expressions of our original coordinate values, so we can do some substitution to get:

    + frames: Gerolamo Cardano figured out that even if the general cubic function is really hard to solve, it can be rewritten to a form for which finding the roots is "easier" (even if not "easy"):

    + x, at step n=1, we perform the following calculation until fy(x) is zero, so that the next t is the same as the one we already have:

    + n-2 term function. For instance, if we have a cubic curve such as this:

    - + +

    Then translating it so that the first coordinate lies on (0,0), moving all x coordinates by -120, and all y coordinates by -160, gives us:

    - + +

    If we then rotate the curve so that its end point lies on the x-axis, the coordinates (integer-rounded for illustrative purposes here) become:

    - + +

    If we drop all the zero-terms, this gives us:

    - + +

    We can see that our original curve definition has been simplified considerably. The following graphics illustrate the result of aligning our example curves to the x-axis, with the cubic case using the coordinates that were just used in the example formulae: @@ -3399,12 +4301,23 @@ function getCubicRoots(pa, pb, pc, pd) { inflection, and we can find out where those happen relatively easily.

    What we need to do is solve a simple equation:

    +

    What we're saying here is that given the curvature function C(t), we want to know for which values of t this function is zero, meaning there is no "curvature", which will be exactly at the point between our circle being on one side of the curve, and our circle being on the other side of the curve. So what does C(t) look like? Actually something that seems not too hard:

    + +

    And of course the same functions for y:

    + C(t) function for us (and to expand it to a readable form of simple terms) gives us this rather overly complicated set of arithmetic expressions:

    + t values, we end up with the following simple term function for C(t):

    + +

    This is a plain quadratic curve, and we know how to solve C(t) = 0; we use the quadratic formula:

    + where, but we know there is one. This edge is described by the function:

    + +
  • ...on the top (blue) edge, the curve's start point touches the curve, forming a loop. This edge is described by the function:

    + z coordinate that is always 1, then we can suddenly add arbitrary values. For example:

    +

    Sweet! z stays 1, so we can effectively ignore it entirely, but we added some plain values to our x and y coordinates. So, if we want to subtract p1.x and p1.y, we use:

    +

    Running all our coordinates through this transformation gives a new set of coordinates, let's call those U, where the @@ -3652,11 +4674,29 @@ function getCubicRoots(pa, pb, pc, pd) { currently have. This is called shearing, and the typical x-shear matrix and its transformation looks like this:

    +

    So we want some shearing value that, when multiplied by y, yields -x, so our x coordinate becomes zero. That value is simply -x/y, because *-x/y * y = -x*. Done:

    +

    Now, running this on all our points generates a new set of coordinates, let's call those V, which now have point 1 on @@ -3665,6 +4705,19 @@ function getCubicRoots(pa, pb, pc, pd) { point 3 to end up on (1,1), so we can also scale x to make sure its x-coordinate will be 1 after we run the transform. That means we'll be x-scaling by 1/point3x, and y-scaling by point2y. This is really easy:

    +

    Then, finally, this generates a new set of coordinates, let's call those W, of which point 1 lies on (0,0), point 2 lies on (0,1), and @@ -3674,12 +4727,49 @@ function getCubicRoots(pa, pb, pc, pd) { but y-shearing. Additionally, we don't actually want to end up at zero (which is what we did before) so we need to shear towards an offset, in this case 1:

    +

    And this generates our final set of four coordinates. Of these, we already know that points 1 through 3 are (0,0), (0,1) and (1,1), and only the last coordinate is "free". In fact, given any four starting coordinates, the resulting "transformation mapped" coordinate will be:

    +

    Okay, well, that looks plain ridiculous, but: notice that every coordinate value is being offset by the initial translation, and also @@ -3690,12 +4780,36 @@ function getCubicRoots(pa, pb, pc, pd) { First, let's just do that translation step as a "preprocessing" operation so we don't have to subtract the values all the time. What does that leave?

    +

    Suddenly things look a lot simpler: the mapped x is fairly straight forward to compute, and we see that the mapped y actually contains the mapped x in its entirety, so we'll have that part already available when we need to evaluate it. In fact, let's pull out all those common factors to see just how simple this is:

    +

    That's kind of super-simple to write out in code, I think you'll agree. Coding math tends to be easier than the formulae initially make it @@ -3770,16 +4884,31 @@ function getCubicRoots(pa, pb, pc, pd) { cubic case either: because of the kind of curve we're starting with, we know there is only root, simplifying the code we need!

    First, let's look at the function for x(t):

    +

    We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:

    +

    Nothing special here: that's a standard cubic polynomial in "power" form (i.e. all the terms are ordered by their power of t). So, given that a, b, c, d, and x(t) are all known constants, we can trivially rewrite this (by moving the x(t) across the equal sign) as:

    +

    You might be wondering "where did all the other 'minus x' for all the other values a, b, c, and d go?" and the answer there is that they @@ -3859,8 +4988,24 @@ y = curve.get(t).yfy(t), then the length of the curve, measured from start point to some point t = z, is computed using the following seemingly straight forward (if a bit overwhelming) formula:

    +

    or, more commonly written using Leibnitz notation as:

    +

    This formula says that the length of a parametric curve is in fact equal to the area underneath a function that looks a @@ -3887,7 +5032,18 @@ y = curve.get(t).y - + +

    In plain text: an integral function can always be treated as the sum of an (infinite) number of (infinitely thin) rectangular strips sitting "under" the function's plotted graph. To illustrate this idea, the following graph shows the integral for a sinusoid function. The @@ -3947,6 +5103,20 @@ y = curve.get(t).yz). Thankfully, we can quite easily transform any integral interval to any other integral interval, by shifting and scaling the inputs. Doing so, we get the following:

    + n, so if we want to approximate our integral with only two terms (which is a bit low, really) then these tables would tell us that for n=2 we must use the following values:

    +

    Which means that in order for us to approximate the integral, we must plug these values into the approximate function, which gives us:

    +

    So, what does the function look like? This:

    +

    Which is really just a "short form" that glosses over the fact that we're dealing with functions of t, so let's expand that a tiny bit:

    +

    And while that's a little more verbose, it's still just as simple to work with as the first function: the curvature at some point on any @@ -4188,6 +5405,13 @@ function kappa(t, B): just do that. But let's take it one step further: we can also compute the associated "radius of curvature", which gives us the implicit circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:

    +

    So let's revisit the previous graphic with the curvature visualised on both sides of our curves, as well as showing the circle that "fits" @@ -4586,6 +5810,12 @@ lli = function(line1, line2): So, how can we compute C? We start with our observation that C always lies somewhere between the start and ends points, so logically C will have a function that interpolates between those two coordinates:

    +

    If we can figure out what the function u(t) looks like, we'll be done. Although we do need to remember that this @@ -4595,8 +5825,26 @@ lli = function(line1, line2): > (with thanks to Boris Zbarsky) shows us the following two formulae:

    +

    And

    +

    So, if we know the start and end coordinates, and we know the t value, we know C, without having to calculate the @@ -4605,10 +5853,35 @@ lli = function(line1, line2): pure function of t, too.

    We start by observing that, given A, B, and C, the following always holds:

    +

    Working out the maths for this, we see the following two formulae for quadratic and cubic curves:

    +

    And

    +

    Which now leaves us with some powerful tools: given thee points (start, end, and "some point on the curve"), as well as a @@ -4616,6 +5889,13 @@ lli = function(line1, line2): u(t) function, and once we have C, we can use our on-curve point (B) and the ratio(t) function to find A:

    +

    With A found, finding e1 and e2 for quadratic curves is a matter of running the linear @@ -4624,8 +5904,32 @@ lli = function(line1, line2): distance ratio between e1 to B and B to e2 is the Bézier ratio (1-t):t, we can reverse engineer v1 and v2:

    +

    And then reverse engineer the curve's control control points:

    +

    So: if we have a curve's start and end point, then for any t value we implicitly know all the ABC values, which (combined @@ -4649,6 +5953,19 @@ lli = function(line1, line2): in computing the ABC coordinates, but we can just as easily approximate one by treating the distance between the start and B point, and B and end point as a ratio, using

    + t value, and then our e1 and e2 coordinates must obey the standard de Casteljau rule for linear interpolation:

    + d depending on which side of the baseline our B is located, so we don't up creating a funky curve with a loop in it. To do this, we can use the atan2 function:

    + d:

    + B coordinate. We don't even need the latter: with our t value and "wherever the cursor is" as target B, we can compute the associated C:

    +

    And then the associated A:

    +

    And we're done, because that's our new quadratic control point!

    +

    And then we (trivially) rearrange the terms across multiple lines:

    +

    With that arrangement, we can easily decompose this as a matrix multiplication:

    +

    We can do the same for the cubic curve, of course. We know the base function for cubics:

    +

    So we write out the expansion and rearrange:

    +

    Which we can then decompose:

    +

    And, of course, we can do this for quartic curves too (skipping the expansion step):

    + th order curve, so we "start" with a vector P that represents the coordinates we already know, and for which we want to do curve fitting:

    + t is equal to the distance along the polygon, scaled to the [0,1] domain.

    To get these values, we first compute the general "distance along the polygon" matrix:

    + i=1 and i=n fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:

    + t value", which we'll square to get rid of any pesky negative signs:

    + + P coordinate matrix, and we can replace Bézier(si) with the matrix representation T x M x C we talked about before, which gives us:

    +

    In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:

    + S, so we need to form a new matrix, which we'll call 𝕋, that makes use of those, and then use that 𝕋 instead of T in our error function:

    +

    Which, because of the first and last values in S, means:

    +

    Now we can properly write out the error function as matrix operations:

    + + C:

    + can trivially be derived from knowing the previous and next point:

    + very similar, so let's see exactly how similar they are. We've already see the matrix form for Bézier curves, so how different is the matrix form for Catmull-Rom curves?:

    + P coordinates, by applying "some matrix T". We don't know what that T is yet, but we'll get to that:

    +

    Computing T is really more "arranging the numbers":

    +

    Thus:

    + T:

    + +

    Replace point/tangent vector with the expression for all-coordinates:

    +

    and merge the matrices:

    +

    This looks a lot like the Bézier matrix form, which as we saw in the chapter on Bézier curves, should look like this:

    +

    So, if we want to express a Catmull-Rom curve using a Bézier curve, we'll need to turn this Catmull-Rom bit:

    +

    Into something that looks like this:

    +

    And the way we do that is with a fairly straight forward bit of matrix rewriting. We start with the equality we need to ensure:

    +

    Then we remove the coordinate vector from both sides without affecting the equality:

    +

    Then we can "get rid of" the Bézier matrix on the right by left-multiply both with the inverse of the Bézier matrix:

    + +

    And now we're basically done. We just multiply those two matrices and we know what V is:

    +
  • Start with the Catmull-Rom function:
  • +
  • rewrite to pure coordinate form:
  • +
  • rewrite for "normal" coordinate vector:
  • +
  • merge the inner matrices:
  • +
  • rewrite for Bézier matrix form:
  • +
  • and transform the coordinates so we have a "pure" Bézier expression:
  • + 1 through P4, then we can draw that curve using a Bézier curve that has the vector:

    + 1 through P4, we can draw that using a standard tension Catmull-Rom curve with the following coordinate values:

    +

    Or, if your API allows you to specify Catmull-Rom curves using plain coordinates:

    + +

    We can effect this quite easily, because we know that the vector from a curve's last control point to its last on-curve point is equal to the derivative vector. If we want to ensure that the first control point of the next curve matches that, all we have to do is mirror that last control point through the last on-curve point. And mirroring any point A through any point B is really simple:

    +

    So let's implement that and see what it gets us. The following two graphics show a quadratic and a cubic poly-Bézier curve again, but this @@ -5915,6 +7794,11 @@ for p = 1 to points.length-3 (inclusive): From a mathematical point of view, an offset curve O(t) is a curve such that, given our original curve B(t), any point on O(t) is a fixed distance d away from coordinate B(t). So let's math that:

    + B(t), where the "normal" is a vector that runs perpendicular ("at a right angle") to the tangent at B(t). Easy enough:

    + N(t) always has length 1, which we can achieve by dividing B'(t) by its magnitude:

    + a to end b, we must use the formula we saw earlier. Noting that "length" is usually denoted with double vertical bars:

    + So if we want the length of the tangent, we plug in B'(t), with t = 0 as start and t = 1 as end:

    + φ:

    - + +

    What we want to find is the intersection of the tangents, so we want a point C such that:

    - + +

    i.e. we want a point that lies on the vertical line through S (at some distance a from S) and also lies on the tangent line through E (at some distance b from E). Solving this gives us:

    +

    First we solve for b:

    - + +

    which yields:

    +

    which we can then substitute in the expression for a:

    +

    A quick check shows that plugging these values for a and b into the expressions for Cx and Cy give @@ -6177,13 +8142,54 @@ for p = 1 to points.length-3 (inclusive): coordinate values for C, we know where our on-curve point T for t=0.5 (or angle φ/2) is, because we can just evaluate the Bézier polynomial, and we know where the circle arc's actual point P is for angle φ/2:

    - + +

    We compute T, observing that if t=0.5, the polynomial values (1-t)², 2(1-t)t, and t² are 0.25, 0.5, and 0.25 respectively:

    +

    Which, worked out for the x and y components, gives:

    +

    And the distance between these two is the standard Euclidean distance:

    - + +

    So, what does this distance function look like when we plot it for a number of ranges for the angle φ, such as a half circle, quarter circle and eighth circle? @@ -6224,6 +8230,16 @@ for p = 1 to points.length-3 (inclusive): In fact, let's flip the function around, so that if we plug in the precision error, labelled ε, we get back the maximum angle for that precision:

    +

    And frankly, things are starting to look a bit ridiculous at this point, we're doing way more maths than we've ever done, but thankfully @@ -6327,9 +8343,16 @@ for p = 1 to points.length-3 (inclusive): So with the error analysis out of the way, how do we actually compute the coordinates needed to get that "true fit" cubic curve? The first observation is that we already know the start and end points, because they're the same as for the quadratic attempt:

    + +

    where "a" is some scaling factor we'll need to find the expression for, and:

    + t=0.5 as our point "B" in the "A,B,C" projection, then we know the length of the line segment {C,A}, since it's d1 = {A,B} + d2 = {B,C}:

    + t=0.5 point, minus the distance from the centre to the line that runs from start point to end point. The first is the same as the point P we found for the quadratic curve:

    + + + + 1:

    + 1, we can find C2 fairly simply, since it's lies at distance -C1y along the end point's tangent:

    +

    So, to recap, given an angle φ, the new control coordinates are:

    +

    and

    + +

    Which, in decimal values, rounded to six significant digits, is:

    + , we can compute a point on the curve for some value t in the interval [0,1] (where 0 is the start of the curve, and 1 the end, just like for Bézier curves), by evaluating the following function:

    +

    Which, honestly, doesn't tell us all that much. All we can see is that a point on a B-Spline curve is defined as "a mix of all the control @@ -6688,6 +8841,15 @@ for p = 1 to points.length-3 (inclusive): k subscript to the N() function applies to.

    Then the N() function itself. What does it look like?

    +

    So this is where we see the interpolation: N(t) for an (i,k) pair (that is, for a step in the above summation, on a specific @@ -6695,6 +8857,13 @@ for p = 1 to points.length-3 (inclusive): iteration where i goes up, and k goes down, so it seem reasonable to expect that this recursion has to stop at some point; obviously, it does, and specifically it does so for the following i/k values:

    +

    And this function finally has a straight up evaluation: if a t value lies within a knot-specific interval once we reach a @@ -6712,11 +8881,25 @@ for p = 1 to points.length-3 (inclusive): Carl de Boor — came to a mathematically pleasing solution: to compute a point P(t), we can compute this point by evaluating d(t) on a curve section between knots i and i+1:

    +

    This is another recursive function, with k values decreasing from the curve order to 1, and the value α (alpha) defined by:

    +

    That looks complicated, but it's not. Computing alpha is just a fraction involving known, plain numbers. And, once we have our alpha @@ -6725,7 +8908,14 @@ for p = 1 to points.length-3 (inclusive): recursion might see computationally expensive, the total algorithm is cheap, as each step only involves very simple maths.

    Of course, the recursion does need a stop condition:

    - + +

    So, we actually see two stopping conditions: either i becomes 0, in which case d() is zero, or k becomes zero, in which case we get the same "either 1 or 0" that we saw in the N() function above. @@ -6735,7 +8925,39 @@ for p = 1 to points.length-3 (inclusive): Casteljau's algorithm. For instance, if we write out d() for i=3 and k=3, we get the following recursion diagram:

    - + +

    That is, we compute d(3,3) as a mixture of d(2,3) and d(2,2), where those two are themselves a mixture of d(1,3) and d(1,2), and d(1,2) and d(1,1), respectively, which are diff --git a/docs/news/00-draft.md b/docs/news/00-draft.md index 04f30b66..05a77571 100644 --- a/docs/news/00-draft.md +++ b/docs/news/00-draft.md @@ -1,5 +1,31 @@ # Writing a web page +Lets talk about writing a web page, and perhaps more specifically, let's talk about not writing web _applications_. + +At their core, web pages are a way to make information publicly available, in a navigable and discoverable manner. Things like wikipedia or a news website are collections of webpages, and they use the web stack - HTML, CSS, and JS - to get that information in front of readers' eyes, ideally under all circumstances: if your browser's broken and JS or even CSS doesn't work, the information is still there. It'll just look less polished than intended. + +Web applications, on the other hand, are software that "let people do things", with the only thing distinguishing them from any other software being that they're built using the web stack, and presented using the browser as user interface library. These applications can only work if the tech stack works, and not having the correct styling or event handling means the software is considered broken. + +Sometimes it's obvious to say what is which: wikipedia is clearly a (collection of) web page(s), and a browser based game is clearly a web app. But what about things in between? A weather website, or your bank, or even a communications platform like gmail or facebook? All of these have an information aspect to them that is based entirely around how web pages work: what's the current weather and the short forecast? No "software use" should be required. What is your current balance and transaction history? Again, plain information. Even basic web mail itself (a list of emails, that you can click to read) or facebook (a list X messages posted to the platform) are informational. But the functionality _around_ that information is more software-like in nature, so we end up with systems that need to balance "being a web page" with "also being a web app", or depending on the service, "being a web app" while also trying to "be a web page" when the web stack fails. + +And the web stack essentially fails by default these days: the exploitation of people on the web through underhanded practices got so bad that your browser is more than likely to have a script blocker installed, as well as something will filter out all the advertisement spam, as well as an extension that tries to ensure your privacy on the web overall. Which means that most of the things that web apps rely on are disabled by default: no cookies, no tab-associated storage, not even JS by default. So if you're writing a web app, you need to also write a web page, which you can run your web app "on top of". + +So back in 2016, somewhere around 0.14/0.15, after I was tasked with investigating if it was a useful technology for things that my employer was creating at the time, I was quite taken by this technology: this was a real webapp framework: it didn't care that it happened to run in the browser, everything it did, _it did_, and the fact that it happened to use a browser to render itself was essentially a bonus, but also entirely irrelevant. For software development, it was _fantastic_. + +For web pages, not so much, and after a while React came with a way to "render" pages in an offline context, yielding static HTML that your server could serve up, which would then load React, which would then hook up that HTML to the React application that had generated that HTML. This was _very cool_ but meant you needed a server to generate that static content. It also meant you were serving _really large_ HTML files, because in order to hook everything up, React generated HTML with lots of additional markup that told it which elements corresponded to which parts of the UI. It was "cheaper" to just not serve pregenerated pages and instead say "you need JS to run this website". + +And that's what the Primer for Bezier curves did, too. I loved React, and the idea that you needed JS anyway made sense: how are you going to use interactive graphics if you don't have JS enabled? + +And for a while that was fine, but after a year or two it became obvious that in many ways, the older, more cumbersome to maintain web page was in fact superior as far as user experience went: at its core, the primer is an information source, and it shouldn't matter whether you're loading it in a state of the art browser, or using [lynx](https://en.wikipedia.org/wiki/Lynx_(web_browser)). + +For a while this stayed at a realisation: the technology simply made it way too much work to cleanly pregenerate the primer and then have React cleanly hook back into things, but as with all things 2020, I found myself with some time off and a strong itch to finally fix this situation. Had I had that itch half a year earlier, I wouldn't have been able to do this rewrite, but in August 2020, everything had lined up: every browser except for IE11 has modern JS support, Node.js v14 has native ES module support, the `node-canvas` package is far enough along to support (almost!) everything I needed. The only real problem was Firefox on Android, which was still stuck on an ancient version, but amazingly while I was working on the rewrite a new version came out that got it on par with everything else, and so this rewrite was a go: it was time to make a web page. + +Of course the days of "firing up Dreamweaver" are long gone, and these days if you want to make a web page, what you'll actually be doing is _assembling_ a web page. In my case, all the content was in Markdown format, and I had no intention of changing that: Markdown is super convenient for writing long stretches of text. But of course, my markdown is peppered with LaTeX and interactive graphics, so that needs to work too. + + + + + ## Let's talk about React - React vs HTML: web apps are not web pages @@ -15,7 +41,7 @@ - will it mine crypto? - will it break if someone doesn't trust Google? - etc. - - pregenerate everything that can be generated. You're building a web page, not a web page builder. It should work immediately. + - pregenerate everything that can be generated. You're building a web page, not an in-browser page builder. It should work immediately. ## Let's talk about modern JS diff --git a/docs/news/2020-09-18.html b/docs/news/2020-09-18.html index f8c4d89b..e8f53796 100644 --- a/docs/news/2020-09-18.html +++ b/docs/news/2020-09-18.html @@ -27,7 +27,7 @@ - + @@ -168,6 +168,19 @@

    +
    diff --git a/docs/news/index.html b/docs/news/index.html index 38b0a3e0..ae73eabf 100644 --- a/docs/news/index.html +++ b/docs/news/index.html @@ -26,7 +26,7 @@ - + diff --git a/docs/news/rss.xml b/docs/news/rss.xml index 99b6043d..f54f28e9 100644 --- a/docs/news/rss.xml +++ b/docs/news/rss.xml @@ -6,7 +6,7 @@ News updates for the primer on Bézier Curves by Pomax en-GB - Sun Sep 27 2020 10:43:19 +00:00 + Sun Oct 18 2020 14:26:48 +00:00 https://pomax.github.io/bezierinfo/images/og-image.png A Primer on Bézier Curves @@ -44,6 +44,19 @@ <li>Real LaTeX code, that gets saved as <code>.tex</code> file, so it can be compiled into optimized SVG using <code>xelatex</code>, <code>pdfcrop</code>, <code>pdf2svg</code>, and <code>svgo</code>:</li> </ul> <blockquote> +<!-- +\setmainfont[Ligatures=TeX]TeX Gyre Pagella \setmathfontTeX Gyre Pagella Math + + __ n=3 n-k k + B(t) = ❯ \ P \binomnk(1-t) t + cubic ‾‾ k=0 + k + + 3 2 2 3 + = P (1-t) + 3 P (1-t) t + 3P (1-t)t + P t + + 0 1 2 3 +--> <img class="LaTeX SVG" src="./images/news/2020-09-18.html/15225da473048d8c7b5b473b89de0b66.svg" width="401px" height="97px" loading="lazy"> </blockquote> diff --git a/docs/zh-CN/index.html b/docs/zh-CN/index.html index bb66950c..67bbe064 100644 --- a/docs/zh-CN/index.html +++ b/docs/zh-CN/index.html @@ -33,7 +33,7 @@ - + @@ -472,7 +472,20 @@ >的结果。这听起来很复杂,但你在很小的时候就做过线性插值:当你指向两个物体中的另外一个物体时,你就用到了线性插值。它就是很简单的“选出两点之间的一个点”。

    如果我们知道两点之间的距离,并想找出离第一个点20%间距的一个新的点(也就是离第二个点80%的间距),我们可以通过简单的计算来得到:

    - + +

    让我们来通过实际操作看一下:下面的图形都是可交互的,因此你可以通过上下键来增加或减少插值距离,来观察图形的变化。我们从三个点构成的两条线段开始。通过对各条线段进行线性插值得到两个点,对点之间的线段再进行线性插值,产生一个新的点。最终这些点——所有的点都可以通过选取不同的距离插值产生——构成了贝塞尔曲线 : @@ -500,15 +513,34 @@

    贝塞尔曲线是“参数”方程的一种形式。从数学上讲,参数方程作弊了:“方程”实际上是一个从输入到唯一输出的、良好定义的映射关系。几个输入进来,一个输出返回。改变输入变量,还是只有一个输出值。参数方程在这里作弊了。它们基本上干了这么件事,“好吧,我们想要更多的输出值,所以我们用了多个方程”。举个例子:假如我们有一个方程,通过一些计算,将假设为x的一些值映射到另外的值:

    +

    记号f(x)是表示函数的标准方式(为了方便起见,如果只有一个的话,我们称函数为f),函数的输出根据一个变量(本例中是x)变化。改变xf(x)的输出值也会变。

    到目前没什么问题。现在,让我们来看一下参数方程,以及它们是怎么作弊的。我们取以下两个方程:

    +

    这俩方程没什么让人印象深刻的,只不过是正弦函数和余弦函数,但正如你所见,输入变量有两个不同的名字。如果我们改变了a的值,f(b)的输出不会有变化,因为这个方程没有用到a。参数方程通过改变这点来作弊。在参数方程中,所有不同的方程共用一个变量,如下所示:

    + 多个方程,但只有一个变量。如果我们改变了t的值,fa(t)fb(t)的输出都会发生变化。你可能会好奇这有什么用,答案其实很简单:对于参数曲线,如果我们用常用的标记来替代fa(t)fb(t),看起来就有些明朗了:

    +

    好了,通过一些神秘的t值将x/y坐标系联系起来。

    @@ -536,6 +574,12 @@ 贝塞尔曲线是(一种)参数方程,并在它的多个维度上使用相同的基本方程。在上述的例子中x值和y值使用了不同的方程,与此不同的是,贝塞尔曲线的xy都用了“二项多项式”。那什么是二项多项式呢?

    你可能记得高中所学的多项式,看起来像这样:

    + 贝塞尔曲线不是x的多项式,它是t的多项式,t的值被限制在0和1之间,并且含有ab等参数。它采用了二次项的形式,听起来很神奇但实际上就是混合不同值的简单描述:

    +

    我明白你在想什么:这看起来并不简单,但如果我们拿掉t并让系数乘以1,事情就会立马简单很多,看看这些二次项:

    + 还有一个简单的办法可以弄清参数项怎么工作的:如果我们将(1-t)重命名为a,将t重命名为b,暂时把权重删掉,可以得到这个:

    + 基本上它就是“每个ab结合项”的和,在每个加号后面逐步的将a换成b。因此这也很简单。现在你已经知道了二次多项式,为了叙述的完整性,我将给出一般方程:

    + 如果我们要改变曲线,就需要改变每个点的权重,有效地改变插值。可以很直接地做到这个:只要用一个值乘以每个点,来改变它的强度。这个值照惯例称为“权重”,我们可以将它加入我们原始的贝塞尔函数:

    - + +

    看起来很复杂,但实际上“权重”只是我们想让曲线所拥有的坐标值:对于一条nth阶曲线,w0是起始坐标,wn是终点坐标,中间的所有点都是控制点坐标。假设说一条曲线的起点为(120,160),终点为(220,40),并受点(35,200)和点(220,260)的控制,贝塞尔曲线方程就为:

    +

    这就是我们在文章开头看到的曲线:

    @@ -958,6 +1053,13 @@ function Bezier(3,t,w[]): the previous section, thereby gaining control over "how strongly" each coordinate influences the curve.

    Adding these ratio values to the regular Bézier curve function is fairly easy. Where the regular function is the following:

    +

    The function for rational Bézier curves has two more terms:

    + @@ -1139,12 +1252,24 @@ function RationalBezier(3,t,w[],r[]): 既然我们知道了贝塞尔曲线背后的数学原理,你可能会注意到一件奇怪的事:它们都是从t=0t=1。为什么是这个特殊区间?

    这一切都与我们如何从曲线的“起点”变化到曲线“终点”有关。如果有一个值是另外两个值的混合,一般方程如下:

    +

    很显然,起始值需要a=1, b=0,混合值就为100%的value 1和0%的value 2。终点值需要a=0, b=1,则混合值是0%的value 1和100%的value 2。另外,我们不想让“a”和“b”是互相独立的:如果它们是互相独立的话,我们可以任意选出自己喜欢的值,并得到混合值,比如说100%的value1和100%的value2。原则上这是可以的,但是对于贝塞尔曲线来说,我们通常想要的是起始值和终点值之间的混合值,所以要确保我们不会设置一些“a”和"b"而导致混合值超过100%。这很简单:

    +

    用这个式子我们可以保证相加的值永远不会超过100%。通过将a限制在区间[0,1],我们将会一直处于这两个值之间(包括这两个端点),并且相加为100%。 @@ -1192,24 +1317,119 @@ function RationalBezier(3,t,w[],r[]):

    通过将贝塞尔公式表示成一个多项式基本方程、系数矩阵以及实际的坐标,我们也可以用矩阵运算来表示贝塞尔。让我们看一下这对三次曲线来说有什么含义:

    +

    暂时不用管我们具体的坐标,现在有:

    +

    可以将它写成四个表达式之和:

    +

    我们可以扩展这些表达式:

    +

    更进一步,我们可以加上所有的1和0系数,以便看得更清楚:

    +

    现在,我们可以将它看作四个矩阵运算:

    +

    如果我们将它压缩到一个矩阵操作里,就能得到:

    +

    这种多项式表达式一般是以递增的顺序来写的,所以我们应该将t矩阵水平翻转,并将大的那个“混合”矩阵上下颠倒:

    +

    最终,我们可以加入原始的坐标,作为第三个单独矩阵:

    +

    我们可以对二次曲线运用相同的技巧,可以得到:

    +

    如果我们代入t值并乘以矩阵来计算,得到的值与解原始多项式方程或用逐步线性插值计算的结果一样。

    @@ -1574,6 +1794,16 @@ function drawCurve(points[], t): we saw that we can represent curves as matrix multiplications. Specifically, we saw these two forms for the quadratic and cubic curves respectively: (we'll reverse the Bézier coefficients vector for legibility)

    +

    and

    + +

    and

    + + + + + T · M · P]), with a new set of coordinates that represent the curve from t = 0 to t = z. So let's get computing:

    +

    Excellent! Now we can form our new quadratic curve:

    + + + z]. We were able to write it down in a more simple form because of the zero, but what we actually evaluated, making the zero explicit, was:

    + +

    If we want the interval [z,1], we will be evaluating this instead:

    + + [something · M] into [M · something]:

    +

    So, our final second curve looks like:

    + + + t = z, we get two subcurves that are described as Bézier curves with simple-to-derive coordinates:

    +

    and

    + +

    and

    + nth order curve to an (n+1)th order curve is as follows (observing that the start and end weights are the same as the start and end weights for the old curve):

    - + +

    However, this rule also has as direct consequence that you cannot generally safely lower a curve from nth order to (n-1)th order, because the control points cannot be "pulled apart" cleanly. We can @@ -1856,22 +2341,58 @@ function drawCurve(points[], t): some things can be done much more easily with matrices than with calculus functions, and this is one of those things. So... let's go!

    We start by taking the standard Bézier function, and condensing it a little:

    +

    Then, we apply one of those silly (actually, super useful) calculus tricks: since our t value is always between zero and one (inclusive), we know that (1-t) plus t always sums to 1. As such, we can express any value as a sum of t and 1-t:

    +

    So, with that seemingly trivial observation, we rewrite that Bézier function by splitting it up into a sum of a (1-t) and t component:

    +

    So far so good. Now, to see why we did this, let's write out the (1-t) and t parts, and see what that gives us. I promise, it's about to make sense. We start with (1-t):

    + t part, but that's not a problem:

    +

    Let's do this:

    + +

    where the matrix M is an n+1 by n matrix, and looks like:

    + A x = b, we can use it. And as it so happens, that's exactly what we're dealing with, so:

    +

    First, let's look at the derivative rule for Bézier curves, which is:

    + b in this formula is the same as our w weights, and that n times a summation is the same as a summation where each term is multiplied by n) as:

    + + product and chain rules gives us:

    +

    Which is hard to work with, so let's expand that properly:

    + n-1 and k-1, we'll be on the right track.

    +

    And that's the first part done: the two components inside the parentheses are actually regular, lower-order Bézier expressions:

    + + k we see the following:

    + . This term would have a binomial coefficient of [i choose i+1], which is a non-existent binomial coefficient. Again, this term would contribute "nothing", so we can ignore it, too. This means we're left with:

    +

    And that's just a summation of lower order curves:

    +

    We can rewrite this as a normal summation, and we're done:

    + + + + + + t? In that case we want the normal vector. This vector runs at a right angle to the direction of the curve, and is typically of length 1.0, so all we have to do is rotate the normalized directional vector and we're done:

    + To turn any point (x,y) into a rotated point (x',y') (over 0,0) by some angle φ, we apply this nice and easy computation:

    +

    Which is the "long" version of the following matrix transformation:

    + frames: cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the derivatives section:

    + frames: loading="lazy" />

    And then we turn this into our solution for t using basic arithmetics:

    + frames: the Quadratic formula. If you've seen it before, you'll remember it, and if you haven't, it looks like this:

    + frames: First we turn our cubic Bézier function into a quadratic one, by following the rule mentioned at the end of the derivatives section:

    +

    And then, using these v values, we can find out what our a, b, and c should be:

    + frames: This gives us three coefficients {a, b, c} that are expressed in terms of v values, where the v values are expressions of our original coordinate values, so we can do some substitution to get:

    + frames: Gerolamo Cardano figured out that even if the general cubic function is really hard to solve, it can be rewritten to a form for which finding the roots is "easier" (even if not "easy"):

    + x, at step n=1, we perform the following calculation until fy(x) is zero, so that the next t is the same as the one we already have:

    + n-2 term function. For instance, if we have a cubic curve such as this:

    - + +

    Then translating it so that the first coordinate lies on (0,0), moving all x coordinates by -120, and all y coordinates by -160, gives us:

    - + +

    If we then rotate the curve so that its end point lies on the x-axis, the coordinates (integer-rounded for illustrative purposes here) become:

    - + +

    If we drop all the zero-terms, this gives us:

    - + +

    We can see that our original curve definition has been simplified considerably. The following graphics illustrate the result of aligning our example curves to the x-axis, with the cubic case using the coordinates that were just used in the example formulae: @@ -3373,12 +4277,23 @@ function getCubicRoots(pa, pb, pc, pd) { inflection, and we can find out where those happen relatively easily.

    What we need to do is solve a simple equation:

    +

    What we're saying here is that given the curvature function C(t), we want to know for which values of t this function is zero, meaning there is no "curvature", which will be exactly at the point between our circle being on one side of the curve, and our circle being on the other side of the curve. So what does C(t) look like? Actually something that seems not too hard:

    + +

    And of course the same functions for y:

    + C(t) function for us (and to expand it to a readable form of simple terms) gives us this rather overly complicated set of arithmetic expressions:

    + t values, we end up with the following simple term function for C(t):

    + +

    This is a plain quadratic curve, and we know how to solve C(t) = 0; we use the quadratic formula:

    + where, but we know there is one. This edge is described by the function:

    + +
  • ...on the top (blue) edge, the curve's start point touches the curve, forming a loop. This edge is described by the function:

    + z coordinate that is always 1, then we can suddenly add arbitrary values. For example:

    +

    Sweet! z stays 1, so we can effectively ignore it entirely, but we added some plain values to our x and y coordinates. So, if we want to subtract p1.x and p1.y, we use:

    +

    Running all our coordinates through this transformation gives a new set of coordinates, let's call those U, where the @@ -3626,11 +4650,29 @@ function getCubicRoots(pa, pb, pc, pd) { currently have. This is called shearing, and the typical x-shear matrix and its transformation looks like this:

    +

    So we want some shearing value that, when multiplied by y, yields -x, so our x coordinate becomes zero. That value is simply -x/y, because *-x/y * y = -x*. Done:

    +

    Now, running this on all our points generates a new set of coordinates, let's call those V, which now have point 1 on @@ -3639,6 +4681,19 @@ function getCubicRoots(pa, pb, pc, pd) { point 3 to end up on (1,1), so we can also scale x to make sure its x-coordinate will be 1 after we run the transform. That means we'll be x-scaling by 1/point3x, and y-scaling by point2y. This is really easy:

    +

    Then, finally, this generates a new set of coordinates, let's call those W, of which point 1 lies on (0,0), point 2 lies on (0,1), and @@ -3648,12 +4703,49 @@ function getCubicRoots(pa, pb, pc, pd) { but y-shearing. Additionally, we don't actually want to end up at zero (which is what we did before) so we need to shear towards an offset, in this case 1:

    +

    And this generates our final set of four coordinates. Of these, we already know that points 1 through 3 are (0,0), (0,1) and (1,1), and only the last coordinate is "free". In fact, given any four starting coordinates, the resulting "transformation mapped" coordinate will be:

    +

    Okay, well, that looks plain ridiculous, but: notice that every coordinate value is being offset by the initial translation, and also @@ -3664,12 +4756,36 @@ function getCubicRoots(pa, pb, pc, pd) { First, let's just do that translation step as a "preprocessing" operation so we don't have to subtract the values all the time. What does that leave?

    +

    Suddenly things look a lot simpler: the mapped x is fairly straight forward to compute, and we see that the mapped y actually contains the mapped x in its entirety, so we'll have that part already available when we need to evaluate it. In fact, let's pull out all those common factors to see just how simple this is:

    +

    That's kind of super-simple to write out in code, I think you'll agree. Coding math tends to be easier than the formulae initially make it @@ -3744,16 +4860,31 @@ function getCubicRoots(pa, pb, pc, pd) { cubic case either: because of the kind of curve we're starting with, we know there is only root, simplifying the code we need!

    First, let's look at the function for x(t):

    +

    We can rewrite this to a plain polynomial form, by just fully writing out the expansion and then collecting the polynomial factors, as:

    +

    Nothing special here: that's a standard cubic polynomial in "power" form (i.e. all the terms are ordered by their power of t). So, given that a, b, c, d, and x(t) are all known constants, we can trivially rewrite this (by moving the x(t) across the equal sign) as:

    +

    You might be wondering "where did all the other 'minus x' for all the other values a, b, c, and d go?" and the answer there is that they @@ -3833,8 +4964,24 @@ y = curve.get(t).yfy(t), then the length of the curve, measured from start point to some point t = z, is computed using the following seemingly straight forward (if a bit overwhelming) formula:

    +

    or, more commonly written using Leibnitz notation as:

    +

    This formula says that the length of a parametric curve is in fact equal to the area underneath a function that looks a @@ -3861,7 +5008,18 @@ y = curve.get(t).y - + +

    In plain text: an integral function can always be treated as the sum of an (infinite) number of (infinitely thin) rectangular strips sitting "under" the function's plotted graph. To illustrate this idea, the following graph shows the integral for a sinusoid function. The @@ -3921,6 +5079,20 @@ y = curve.get(t).yz). Thankfully, we can quite easily transform any integral interval to any other integral interval, by shifting and scaling the inputs. Doing so, we get the following:

    + n, so if we want to approximate our integral with only two terms (which is a bit low, really) then these tables would tell us that for n=2 we must use the following values:

    +

    Which means that in order for us to approximate the integral, we must plug these values into the approximate function, which gives us:

    +

    So, what does the function look like? This:

    +

    Which is really just a "short form" that glosses over the fact that we're dealing with functions of t, so let's expand that a tiny bit:

    +

    And while that's a little more verbose, it's still just as simple to work with as the first function: the curvature at some point on any @@ -4162,6 +5381,13 @@ function kappa(t, B): just do that. But let's take it one step further: we can also compute the associated "radius of curvature", which gives us the implicit circle that "fits" the curve's curvature at any point, using what is possibly the simplest bit of maths found in this entire primer:

    +

    So let's revisit the previous graphic with the curvature visualised on both sides of our curves, as well as showing the circle that "fits" @@ -4560,6 +5786,12 @@ lli = function(line1, line2): So, how can we compute C? We start with our observation that C always lies somewhere between the start and ends points, so logically C will have a function that interpolates between those two coordinates:

    +

    If we can figure out what the function u(t) looks like, we'll be done. Although we do need to remember that this @@ -4569,8 +5801,26 @@ lli = function(line1, line2): > (with thanks to Boris Zbarsky) shows us the following two formulae:

    +

    And

    +

    So, if we know the start and end coordinates, and we know the t value, we know C, without having to calculate the @@ -4579,10 +5829,35 @@ lli = function(line1, line2): pure function of t, too.

    We start by observing that, given A, B, and C, the following always holds:

    +

    Working out the maths for this, we see the following two formulae for quadratic and cubic curves:

    +

    And

    +

    Which now leaves us with some powerful tools: given thee points (start, end, and "some point on the curve"), as well as a @@ -4590,6 +5865,13 @@ lli = function(line1, line2): u(t) function, and once we have C, we can use our on-curve point (B) and the ratio(t) function to find A:

    +

    With A found, finding e1 and e2 for quadratic curves is a matter of running the linear @@ -4598,8 +5880,32 @@ lli = function(line1, line2): distance ratio between e1 to B and B to e2 is the Bézier ratio (1-t):t, we can reverse engineer v1 and v2:

    +

    And then reverse engineer the curve's control control points:

    +

    So: if we have a curve's start and end point, then for any t value we implicitly know all the ABC values, which (combined @@ -4623,6 +5929,19 @@ lli = function(line1, line2): in computing the ABC coordinates, but we can just as easily approximate one by treating the distance between the start and B point, and B and end point as a ratio, using

    + t value, and then our e1 and e2 coordinates must obey the standard de Casteljau rule for linear interpolation:

    + d depending on which side of the baseline our B is located, so we don't up creating a funky curve with a loop in it. To do this, we can use the atan2 function:

    + d:

    + B coordinate. We don't even need the latter: with our t value and "wherever the cursor is" as target B, we can compute the associated C:

    +

    And then the associated A:

    +

    And we're done, because that's our new quadratic control point!

    +

    And then we (trivially) rearrange the terms across multiple lines:

    +

    With that arrangement, we can easily decompose this as a matrix multiplication:

    +

    We can do the same for the cubic curve, of course. We know the base function for cubics:

    +

    So we write out the expansion and rearrange:

    +

    Which we can then decompose:

    +

    And, of course, we can do this for quartic curves too (skipping the expansion step):

    + th order curve, so we "start" with a vector P that represents the coordinates we already know, and for which we want to do curve fitting:

    + t is equal to the distance along the polygon, scaled to the [0,1] domain.

    To get these values, we first compute the general "distance along the polygon" matrix:

    + i=1 and i=n fall in the [0,1] interval, so we need to scale all values down by whatever the total length of the polygon is:

    + t value", which we'll square to get rid of any pesky negative signs:

    + + P coordinate matrix, and we can replace Bézier(si) with the matrix representation T x M x C we talked about before, which gives us:

    +

    In which we can replace the rather cumbersome "squaring" operation with a more conventional matrix equivalent:

    + S, so we need to form a new matrix, which we'll call 𝕋, that makes use of those, and then use that 𝕋 instead of T in our error function:

    +

    Which, because of the first and last values in S, means:

    +

    Now we can properly write out the error function as matrix operations:

    + + C:

    + can trivially be derived from knowing the previous and next point:

    + very similar, so let's see exactly how similar they are. We've already see the matrix form for Bézier curves, so how different is the matrix form for Catmull-Rom curves?:

    + P coordinates, by applying "some matrix T". We don't know what that T is yet, but we'll get to that:

    +

    Computing T is really more "arranging the numbers":

    +

    Thus:

    + T:

    + +

    Replace point/tangent vector with the expression for all-coordinates:

    +

    and merge the matrices:

    +

    This looks a lot like the Bézier matrix form, which as we saw in the chapter on Bézier curves, should look like this:

    +

    So, if we want to express a Catmull-Rom curve using a Bézier curve, we'll need to turn this Catmull-Rom bit:

    +

    Into something that looks like this:

    +

    And the way we do that is with a fairly straight forward bit of matrix rewriting. We start with the equality we need to ensure:

    +

    Then we remove the coordinate vector from both sides without affecting the equality:

    +

    Then we can "get rid of" the Bézier matrix on the right by left-multiply both with the inverse of the Bézier matrix:

    + +

    And now we're basically done. We just multiply those two matrices and we know what V is:

    +
  • Start with the Catmull-Rom function:
  • +
  • rewrite to pure coordinate form:
  • +
  • rewrite for "normal" coordinate vector:
  • +
  • merge the inner matrices:
  • +
  • rewrite for Bézier matrix form:
  • +
  • and transform the coordinates so we have a "pure" Bézier expression:
  • + 1 through P4, then we can draw that curve using a Bézier curve that has the vector:

    + 1 through P4, we can draw that using a standard tension Catmull-Rom curve with the following coordinate values:

    +

    Or, if your API allows you to specify Catmull-Rom curves using plain coordinates:

    + +

    We can effect this quite easily, because we know that the vector from a curve's last control point to its last on-curve point is equal to the derivative vector. If we want to ensure that the first control point of the next curve matches that, all we have to do is mirror that last control point through the last on-curve point. And mirroring any point A through any point B is really simple:

    +

    So let's implement that and see what it gets us. The following two graphics show a quadratic and a cubic poly-Bézier curve again, but this @@ -5889,6 +7770,11 @@ for p = 1 to points.length-3 (inclusive): From a mathematical point of view, an offset curve O(t) is a curve such that, given our original curve B(t), any point on O(t) is a fixed distance d away from coordinate B(t). So let's math that:

    + B(t), where the "normal" is a vector that runs perpendicular ("at a right angle") to the tangent at B(t). Easy enough:

    + N(t) always has length 1, which we can achieve by dividing B'(t) by its magnitude:

    + a to end b, we must use the formula we saw earlier. Noting that "length" is usually denoted with double vertical bars:

    + So if we want the length of the tangent, we plug in B'(t), with t = 0 as start and t = 1 as end:

    + φ:

    - + +

    What we want to find is the intersection of the tangents, so we want a point C such that:

    - + +

    i.e. we want a point that lies on the vertical line through S (at some distance a from S) and also lies on the tangent line through E (at some distance b from E). Solving this gives us:

    +

    First we solve for b:

    - + +

    which yields:

    +

    which we can then substitute in the expression for a:

    +

    A quick check shows that plugging these values for a and b into the expressions for Cx and Cy give @@ -6151,13 +8118,54 @@ for p = 1 to points.length-3 (inclusive): coordinate values for C, we know where our on-curve point T for t=0.5 (or angle φ/2) is, because we can just evaluate the Bézier polynomial, and we know where the circle arc's actual point P is for angle φ/2:

    - + +

    We compute T, observing that if t=0.5, the polynomial values (1-t)², 2(1-t)t, and t² are 0.25, 0.5, and 0.25 respectively:

    +

    Which, worked out for the x and y components, gives:

    +

    And the distance between these two is the standard Euclidean distance:

    - + +

    So, what does this distance function look like when we plot it for a number of ranges for the angle φ, such as a half circle, quarter circle and eighth circle? @@ -6198,6 +8206,16 @@ for p = 1 to points.length-3 (inclusive): In fact, let's flip the function around, so that if we plug in the precision error, labelled ε, we get back the maximum angle for that precision:

    +

    And frankly, things are starting to look a bit ridiculous at this point, we're doing way more maths than we've ever done, but thankfully @@ -6301,9 +8319,16 @@ for p = 1 to points.length-3 (inclusive): So with the error analysis out of the way, how do we actually compute the coordinates needed to get that "true fit" cubic curve? The first observation is that we already know the start and end points, because they're the same as for the quadratic attempt:

    + +

    where "a" is some scaling factor we'll need to find the expression for, and:

    + t=0.5 as our point "B" in the "A,B,C" projection, then we know the length of the line segment {C,A}, since it's d1 = {A,B} + d2 = {B,C}:

    + t=0.5 point, minus the distance from the centre to the line that runs from start point to end point. The first is the same as the point P we found for the quadratic curve:

    + + + + 1:

    + 1, we can find C2 fairly simply, since it's lies at distance -C1y along the end point's tangent:

    +

    So, to recap, given an angle φ, the new control coordinates are:

    +

    and

    + +

    Which, in decimal values, rounded to six significant digits, is:

    + , we can compute a point on the curve for some value t in the interval [0,1] (where 0 is the start of the curve, and 1 the end, just like for Bézier curves), by evaluating the following function:

    +

    Which, honestly, doesn't tell us all that much. All we can see is that a point on a B-Spline curve is defined as "a mix of all the control @@ -6662,6 +8817,15 @@ for p = 1 to points.length-3 (inclusive): k subscript to the N() function applies to.

    Then the N() function itself. What does it look like?

    +

    So this is where we see the interpolation: N(t) for an (i,k) pair (that is, for a step in the above summation, on a specific @@ -6669,6 +8833,13 @@ for p = 1 to points.length-3 (inclusive): iteration where i goes up, and k goes down, so it seem reasonable to expect that this recursion has to stop at some point; obviously, it does, and specifically it does so for the following i/k values:

    +

    And this function finally has a straight up evaluation: if a t value lies within a knot-specific interval once we reach a @@ -6686,11 +8857,25 @@ for p = 1 to points.length-3 (inclusive): Carl de Boor — came to a mathematically pleasing solution: to compute a point P(t), we can compute this point by evaluating d(t) on a curve section between knots i and i+1:

    +

    This is another recursive function, with k values decreasing from the curve order to 1, and the value α (alpha) defined by:

    +

    That looks complicated, but it's not. Computing alpha is just a fraction involving known, plain numbers. And, once we have our alpha @@ -6699,7 +8884,14 @@ for p = 1 to points.length-3 (inclusive): recursion might see computationally expensive, the total algorithm is cheap, as each step only involves very simple maths.

    Of course, the recursion does need a stop condition:

    - + +

    So, we actually see two stopping conditions: either i becomes 0, in which case d() is zero, or k becomes zero, in which case we get the same "either 1 or 0" that we saw in the N() function above. @@ -6709,7 +8901,39 @@ for p = 1 to points.length-3 (inclusive): Casteljau's algorithm. For instance, if we write out d() for i=3 and k=3, we get the following recursion diagram:

    - + +

    That is, we compute d(3,3) as a mixture of d(2,3) and d(2,2), where those two are themselves a mixture of d(1,3) and d(1,2), and d(1,2) and d(1,1), respectively, which are diff --git a/package.json b/package.json index d34ccbb3..98a89330 100644 --- a/package.json +++ b/package.json @@ -17,34 +17,36 @@ "---": "--- These are the only three scripts you should care about ---", "start": "run-s clean:* time lint:* build time clean:temp", "test": "run-s start && run-p watch server browser", - "deploy": "run-s start polish copy", - "-------": "--- Note that due to github's naming policy, the public dir is called `docs` rather than `public` ---", + "deploy": "run-s deploy:nocopy copy", + "----": "--- The rest are just the various parts that make the previous three work ---", "browser": "open-cli http://localhost:8000", "build": "node ./src/build.js", "time": "node ./src/mark.js", "clean:temp": "rm -f .timing && rm -rf ./temp", + "-----": "--- Note that due to github's naming policy, the public dir is called `docs` rather than `public` ---", "clean:news": "rm -f ./docs/news/*.html", "polish": "run-s pretty link-checker", - "----": "--- The copy commands rely on a parallel `bezierinfo` git repo existing ---", + "deploy:nocopy": "run-s start polish", + "------": "--- The copy commands rely on a parallel `bezierinfo` git repo existing ---", "copy": "run-s copy:*", "copy:prepare": "mkdir _ && mv ../bezierinfo/.git _ && rm -rf ../bezierinfo ", "copy:files": "cp -r ./docs/. ../bezierinfo", "copy:remove-md": "rm ../bezierinfo/chapters/**/*.md && rm ../bezierinfo/news/*.md", "copy:cleanup": "mv _/.git ../bezierinfo && rm -rf _", - "----------": "--- Prettier is your friend. ---", + "-------": "--- Prettier is your friend. ---", "lint:tools": "prettier \"./src/**/*.js\" --print-width 150 --write", "lint:lib": "prettier \"./docs/js/**/*.js\" --print-width 150 --write", "lint:css": "prettier \"./docs/**/*.css\" --print-width 150 --write", "link-checker": "link-checker \"docs/index.html\" --allow-hash-href --url-ignore \"(ja-JP|zh-CN|legendre).*\" --ignore-error-exit", "pretty": "prettier \"./docs/{!(legendre-gauss),**/*}.html\" --use-tabs --print-width 150 --write", - "------": "--- Server and watch tasks ---", + "--------": "--- Server and watch tasks ---", "server": "cd docs && http-server -e -p 8000 --cors", "watch": "run-p watch:*", "watch:chapters": "chokidar \"./docs/chapters/**/*.(md|js)\" -c \"npm run build\"", "watch:news": "chokidar \"./docs/news/**/*.md\" -c \"npm run build\"", "watch:customelement": "chokidar \"./docs/js/custom-element/**/*.js\" -c \"npm run build\"", "watch:src": "chokidar \"./src/**/*.*\" -c \"npm run build\"", - "-----": "--- Used as part of LaTeX generation: ---", + "---------": "--- Used as part of LaTeX generation: ---", "svgo": "svgo", "svgo:pretty": "node ./src/svgo-pretty.js" }, diff --git a/src/build/markdown/processors/latex/latex-to-svg.js b/src/build/markdown/processors/latex/latex-to-svg.js index c562847d..aedcf53b 100644 --- a/src/build/markdown/processors/latex/latex-to-svg.js +++ b/src/build/markdown/processors/latex/latex-to-svg.js @@ -18,81 +18,101 @@ import toPOSIX from "../../../../to-posix.js"; */ export default async function latexToSVG(latex, pathdata, localeStrings, block) { const { imagepath, id } = pathdata; + fs.ensureDirSync(imagepath); + fs.ensureDirSync(path.join(paths.snippets, id)); + latex = colorPreProcess(latex); const locale = localeStrings.getCurrentLocale(); const hash = createHash(`md5`).update(latex).digest(`hex`); const TeXfilename = path.join(paths.temp, `${hash}.tex`); - fs.ensureDirSync(imagepath); - + const ASCIIfilename = path.join(paths.snippets, id, `${hash}.ascii`); + const PDFfilename = TeXfilename.replace(`.tex`, `.pdf`); + const PDFfilenameCropped = TeXfilename.replace(`.tex`, `-crop.pdf`); const SVGfilename = path.join(imagepath, `${hash}.svg`); + const srcURL = `./${toPOSIX(path.relative(paths.public, SVGfilename))}`; - if (!fs.existsSync(SVGfilename)) { + const commands = { + xetex: `xelatex -output-directory "${path.dirname(TeXfilename)}" "${TeXfilename}"`, + crop: `pdfcrop "${PDFfilename}"`, + svg: `pdf2svg "${PDFfilenameCropped}" "${SVGfilename}"`, + svgo: `npm run svgo -- "${SVGfilename}"`, + tex2utf: `perl ./src/tex2utf/tex2utf.pl "${TeXfilename}" > "${ASCIIfilename}"`, + }; + + if (!fs.existsSync(TeXfilename)) { // There is no SVG graphic for the LaTeX code yet, so we need to generate // one, but it's possible we already tried and failed for a different locale. // As the temp dir gets wiped on each run, we can check for the the existence // of our TeX file: if it exists, we already unsuccessfully ran this code. if (fs.existsSync(TeXfilename)) return fail(hash); - const PDFfilename = TeXfilename.replace(`.tex`, `.pdf`); - const PDFfilenameCropped = TeXfilename.replace(`.tex`, `-crop.pdf`); - - let fonts = ["\\setmainfont[Ligatures=TeX]{TeX Gyre Pagella}", "\\setmathfont{TeX Gyre Pagella Math}"]; + let fonts = ` + \\setmainfont[Ligatures=TeX]{TeX Gyre Pagella} + \\setmathfont{TeX Gyre Pagella Math} + `; // For Chinese, we need the xeCJK package because there might be Chinese // in maths context, which base XeLaTeX can't quite deal with. if (locale === "zh-CN") { - fonts = ["\\usepackage{xeCJK}", "\\xeCJKsetup{CJKmath=true}", "\\setCJKmainfont{gbsn00lp.ttf}"]; + fonts = ` + \\usepackage{xeCJK} + \\xeCJKsetup{CJKmath=true} + \\setCJKmainfont{gbsn00lp.ttf} + `; } // The same goes for Japanese, although we obviously want a different // font than Chinese, as they are different languages entirely. if (locale === "ja-JP") { - fonts = ["\\usepackage{xeCJK}", "\\xeCJKsetup{CJKmath=true}", "\\setCJKmainfont{ipaexm.ttf}"]; + fonts = ` + \\usepackage{xeCJK} + \\xeCJKsetup{CJKmath=true} + \\setCJKmainfont{ipaexm.ttf} + `; } fs.writeFileSync( TeXfilename, - [ - `\\documentclass[12pt]{article}`, - `\\usepackage[paperwidth=12in, paperheight=12in]{geometry}`, - `\\pagestyle{empty}`, - `\\usepackage[dvipsnames]{xcolor}`, - `\\definecolor{darkred}{rgb}{0.6,0,0}`, - `\\definecolor{darkgreen}{rgb}{0,0.6,0}`, - `\\definecolor{darkblue}{rgb}{0,0,0.6}`, - `\\definecolor{amber}{rgb}{0.9,0.6,0}`, - `\\usepackage{amsmath}`, - `\\usepackage{unicode-math}`, - ] - .concat(fonts) - .concat([`\\begin{document}`, `\\[`, cleanUp(latex), `\\]`, `\\end{document}`]) - .join(`\n`) + ` + \\documentclass[12pt]{article} + \\usepackage[paperwidth=12in, paperheight=12in]{geometry} + \\pagestyle{empty} + \\usepackage[dvipsnames]{xcolor} + \\definecolor{darkred}{rgb}{0.6,0,0} + \\definecolor{darkgreen}{rgb}{0,0.6,0} + \\definecolor{darkblue}{rgb}{0,0,0.6} + \\definecolor{amber}{rgb}{0.9,0.6,0} + \\usepackage{amsmath} + \\usepackage{unicode-math} + ${fonts} + \\begin{document} + \\[ ${cleanUp(latex)} \\] + \\end{document} + ` ); + } - const commands = { - xetex: `xelatex -output-directory "${path.dirname(TeXfilename)}" "${TeXfilename}"`, - crop: `pdfcrop "${PDFfilename}"`, - svg: `pdf2svg "${PDFfilenameCropped}" "${SVGfilename}"`, - svgo: `npm run svgo -- "${SVGfilename}"`, - }; - + if (!fs.existsSync(SVGfilename)) { // Finally: run the conversion try { process.stdout.write(`- running xelatex for block [${id}:${locale}:${block}] (${hash}.tex): `); - runCmd(commands.xetex, hash); + runCmd(commands.xetex); process.stdout.write(` - cropping PDF to document content: `); - runCmd(commands.crop, hash); + runCmd(commands.crop); process.stdout.write(` - converting cropped PDF to SVG: `); - runCmd(commands.svg, hash); + runCmd(commands.svg); process.stdout.write(` - cleaning up SVG: `); - runCmd(commands.svgo, hash); + runCmd(commands.svgo); } catch (e) { + // we don't really care about errors unless they happen as + // part of the xelatex command, in which case we need to know + // what actually went wrong so we can fix it. if (e.cmd === commands.xetex) { console.error(` | Error in ${TeXfilename}\n |`); @@ -100,7 +120,7 @@ export default async function latexToSVG(latex, pathdata, localeStrings, block) .filter((v) => !!v) .map((v) => v.toString("utf8").replace(/\r\n/g, `\n`))[0] .split(`\n`) - .slice(-6); // this may depend on the xelatex version used... + .slice(-6); // this is a magic number that *may* depend on the xelatex version used. loglines.splice(2, 1); // remove 'no pages of output' @@ -113,16 +133,23 @@ export default async function latexToSVG(latex, pathdata, localeStrings, block) } } + // Generate the "ASCII art" version for comment embedding, independently + // of the TeX -> SVG chain, as it is in effect a separate TeX conversion. + if (!fs.existsSync(ASCIIfilename)) { + process.stdout.write(`creating ASCII snippet ${hash}: `); + runCmd(commands.tex2utf, () => cleanASCII(ASCIIfilename)); + } + // Make sure we hardcode the size of this LaTeX SVG image, because we absolutely - // do not want the page to resize in any possible noticable way if we can help it. + // do not want the page to resize in any possible noticeable way if we can help it. let svg = fs.readFileSync(SVGfilename).toString(`utf8`); try { const vb = svg.match(/viewBox="([^"]+)"/)[1].split(/\s+/); // The SVG contains values in "pt" units, but to maximise legibility we convert - // these to "rem" instead, so that formulae are always sized based on the font - // around them, rather than being sized independently of the document text. + // these to pixel values instead, so that formulae are always sized based on the + // font around them, rather than being sized independently of the document text. // Base browser sizes are 16pt so the conversion factor is 4/3. const w = Math.round(((parseFloat(vb[2]) - parseFloat(vb[0])) * 4) / 3); const h = Math.round(((parseFloat(vb[3]) - parseFloat(vb[1])) * 4) / 3); @@ -132,7 +159,15 @@ export default async function latexToSVG(latex, pathdata, localeStrings, block) svg = svg.replace(`height="${vb[3]}pt"`, `height="${h}px"`); fs.writeFileSync(SVGfilename, svg, `utf8`); - return ``; + // Include the "ASCII" version of this formula as code comment + const ascii = fs.readFileSync(ASCIIfilename).toString(`utf8`); + const prefix = `\n`; + const img = ``; + return `${prefix}${img}`; + + // Note that, yes, this adds 100kb to the resulting .html file, + // but after gzip (which all sensible servers use) that's only 16kb + // and that's an acceptable amount of data. } catch (e) { // This code exists because sometimes a file turns out to be empty, and I suspect that's // because of successive SVGO calls, but whatever the cause: it's bad and should break the build. @@ -142,32 +177,48 @@ export default async function latexToSVG(latex, pathdata, localeStrings, block) } } -// This function really needs better stdio capture, -// so it can report _what went wrong_ when xelatex fails. -function runCmd(cmd, hash) { +// Run a command in an explicit unicode context. +function runCmd(cmd, thenRunThis) { try { - execSync(cmd); //, { stdio: 'inherit' }); + execSync(cmd, { encoding: `utf8` }); console.log(`✓`); } catch (e) { console.log(`✕`); e.cmd = cmd; throw e; } + if (thenRunThis) return thenRunThis(); } -// This function converst things like RED[a] into real LaTeX. +// Remove latex preamble and superfluous indents from "ASCII" graphics. +function cleanASCII(filename) { + let data = fs.readFileSync(filename).toString(`utf8`); + let lines = data.split(`\n`).slice(3); + let indent = lines.reduce((t, e) => { + if (!e.trim()) return t; + let m = e.match(/^\s+/); + let len = m ? m[0].length : 0; + return len < t ? len : t; + }, 1000); + let re = new RegExp(`^${" ".repeat(indent)}`); + data = lines.map((l) => l.replace(re, ``)).join(`\n`); + fs.writeFileSync(filename, data); + return data; +} + +// This function converts things like RED[a] into real LaTeX. function colorPreProcess(input) { var regexp = new RegExp(`([A-Z]+)\\[([^\\]]+)\\]`, `g`); var output = input.replace(regexp, function (_, color, content) { if (content.indexOf(` `) !== -1) { content = ` ${content}`; } - return `{\\color{${color.toLowerCase()}}${content.replace(/ /g, "\\ ")}}`; + return `{\\color{${color.toLowerCase()}}${content.replace(/ /g, "~")}}`; }); return output; } // Failure state HTML code is simply a script that yells in the console function fail(hash) { - return ``; + return ``; } diff --git a/src/project-paths.js b/src/project-paths.js index 01a79955..09a14488 100644 --- a/src/project-paths.js +++ b/src/project-paths.js @@ -19,6 +19,7 @@ const build = path.join(src, `build`); const chapters = path.join(publicDir, `chapters`); const html = path.join(src, `html`); const images = path.join(publicDir, `images`); +const snippets = path.join(images, `snippets`); const news = path.join(publicDir, `news`); const sitejs = path.join(publicDir, `js`); const temp = path.join(project, `temp`); @@ -32,6 +33,7 @@ const paths = { project, public: publicDir, sitejs, + snippets, src, temp, }; diff --git a/src/tex2utf/README.md b/src/tex2utf/README.md new file mode 100644 index 00000000..73104712 --- /dev/null +++ b/src/tex2utf/README.md @@ -0,0 +1 @@ +See https://github.com/Pomax/tex2utf diff --git a/src/tex2utf/tex2utf.pl b/src/tex2utf/tex2utf.pl new file mode 100644 index 00000000..c5f66356 --- /dev/null +++ b/src/tex2utf/tex2utf.pl @@ -0,0 +1,2264 @@ +#!/usr/local/bin/perl + +# $Id: tex2utf.pl, v 1.0 2020/10/16 16:09:00 Pomax $ +# +# UTF8-massaged version of https://ctan.org/pkg/tex2mail +# +# Updated October 2020 by pomax@nihongoressources.com, +# original header immediately follows this comment block, +# with spacing updated to something that looks uniform. + +# $Id: tex2mail.in,v 1.1 2000/10/27 19:13:53 karim Exp $ +# +# Features: +# % at the end of a line followed by \n\n is recognized as end of +# paragraph :-( +# +# Change log is at bottom. +# +# Options: +# linelength=75 # Cut at this line +# maxdef=400 # definition loops: croak if many substitutions +# debug=0 +# by_par=0 # Expect each paragraph to be terminated +# # by *exactly* 2 "\n", and do not print +# # an extra "\n" between paragraphs +# TeX # Assume it is not LaTeX +# ragged # leave right ragged +# noindent # assume \noindent everywhere + +use Getopt::Long; + +$linelength = 150; +$maxdef = 400; +$debug = false; +$opt_by_par = false; +$opt_TeX = true; +$opt_ragged = false; +$opt_noindent = false; + +GetOptions( + "linelength=s" => \$linelength, + "maxdef=s" => \$maxdef, + "debug" => \$debug, + "by_par" => \$opt_by_par, + "TeX" => \$opt_TeX, + "ragged" => \$opt_ragged, + "noindent" => \$opt_noindent +) or die "Could not parse provided runtime flag(s)"; + +# +# This part is a little different: enable utf8 and ensure that +# even on Windows, the input/output is fully unicode conformant: +# + +use utf8; + +use open ':std', ':encoding(UTF-8)'; +BEGIN { + if ($^O eq "MSWin32") { + require Win32::Unicode::File; + Win32::Unicode::File->import(); + } +} + +# +# The original code then continues here... +# + +$notusualtoks="\\\\" . '\${}^_~&@'; +$notusualtokenclass="[$notusualtoks]"; +$usualtokenclass="[^$notusualtoks]"; +$macro='\\\\([^a-zA-Z]|([a-zA-Z]+\s*))'; # Why \\\\? double interpretation! +$active="$macro|\\\$\\\$|$notusualtokenclass"; +$tokenpattern="$usualtokenclass|$active"; +$multitokenpattern="$usualtokenclass+|$active"; + +# Format of the record: height,length,baseline,expandable-spaces,string +# The string is not terminated by \n, but separated into rows by \n. +# height=0 denotes expandable string +# Baseline=3 means the 4th row is the baseline + +sub debug_print_record { + local($h,$l,$b,$xs,$s) = split /,/, shift, 5; + local(@arr) = split /\n/, $s; + print STDERR "len=$l, h=$h, b=$b, exp_sp=$xs.\n"; + local($i) = 0; + for (@arr) { + local($lead) = ($i++ == $b) ? 'b [' : ' ['; + print STDERR "$lead$_]\n"; + } + while ($i < $h) { # Empty lines may skipped + local($lead) = ($i++ == $b) ? 'b' : ''; + print STDERR "$lead\n"; + } +} + +# Takes length and a record, returns 2 records + +sub cut { + local($length)=(shift); + local($h,$l,$b,$sp,$str)=split(/,/,shift,5); + local($st1,$st2)=("",""); + local($sp1,$sp2,$first,$l2)=(0,0,1,$l-$length); + return (shift,&empty) if $l2<0; + if ($h) { + for (split(/\n/,$str,$h)) { + if (!$first) { + $st1 .= "\n"; + $st2 .= "\n"; + } else {$first=0;} + $st1 .= substr($_,0,$length); + $st2 .= substr($_,$length); + } + } else { + $st1 = substr($str,0,$length); + $st2 = substr($str,$length); + #if ($sp && ($st1 =~ /(\S)(\s+\S*)$/)) { + # $st2 = $2 . $st2; + # $st1 = $` . $1; + # $sp1 = ($st1 =~ /(\s)/g); + # $sp2 = ($st2 =~ /(\s)/g); + #} + } + return ("$h,$length,$b,$sp1,$st1","$h,$l2,$b,$sp2,$st2"); +} + +# Outputs a record + +sub printrecord { + warn "Printing $_[0]\n__ENDPRINT__\n" if $debug & $debug_record; + local($h,$l,$b,$sp,$str)=split(/,/,shift,5); + print $str,"\n"; +} + +# Joins two records + +sub join { + local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); + local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); + $h1 || $h1++; + $h2 || $h2++; + local($h,$l,$b,$sp,$str,@str,@str2)=(0,0,0,$sp1+$sp2,""); + $b = $b1 > $b2 ? $b1 : $b2; + # Calculate space below baseline + $h = $h1-$b1 > $h2-$b2 ? $h1-$b1 : $h2-$b2; + # And height + $h += $b; + $l=$l1+$l2; + @str="" x $h; + @str[$b-$b1 .. $b-$b1+$h1-1]=split(/\n/,$str1,$h1); + @str2[0..$h2-1]=split(/\n/,$str2,$h2); + unless (length($str2[$b2])) { + $str2[$b2] = ' ' x $l2; # Needed for length=0 "color" strings + # in the baseline. + } + if ($debug & $debug_record && (grep(/\n/,@str) || grep(/\n/,@str2))) { + warn "\\n found in \@str or \@str2"; + warn "`$str1', need $h1 rows\n"; + warn "`$str2', need $h2 rows\n"; + } + # This is may be wrong if a zero-length record with escape sequences + # is appended to with something not on the same row... But + # apparently, it should be OK for PARI... + for (0..$h2-1) { + $str[$b-$b2+$_] .= " " x ($l1 - length ($str[$b-$b2+$_])) . $str2[$_]; + } + return "$h,$l,$b,$sp," . join("\n",@str); +} + +# The current line is contained in the array @out of records and, possibly, +# one additional record $last. If $last exists, $islast is set to 1. +# The output channel length is contained in $linelength, the accumulated +# length of @out and $last is contained in $curlength. +# We guaranty that if $curlength>$linelength, then @out is empty. + +# Gets a length of a record + +sub length { + (warn "Wrong format of a record `$_[0]'", return 0) + unless $_[0] =~ /^\d+,(\d+)/; + $1; +} + +# Gets a height of a record + +sub height { + (warn "Wrong format of a record `$_[0]'", return 0) + unless $_[0] =~ /^(\d+),/; + $1; +} + +# Sets baseline of a record, Usage s...(rec,base) + +sub setbaseline { + (warn("Wrong format of a record `$_[0]'"), return undef) + unless $_[0] =~ s/^(\d+,\d+,)(\d+)/\1$_[1]/; +} + +# The hierarchical structure: the records to work are in the array @out. +# The array @chunks keeps the beginning record of the chunks, +# The array @level keeps the beginning chunks of the given level. +# The last chunk can begin after the last record if this chunk is still empty. + +# We do not keep the inner structure of the chunk unless it is the last +# chunk on the given level. + +# Each record is a rectangle to output to the "page". + +# Each chunk is a sequence of records which reflect one finished subgroup +# on the given level. + +# Each level is a sequence of chunks which correspond to a +# not-yet-finished group in TeX input. + + +# The parallel to @level array @wait +# contains an event we wait to complete the given level of array. + +# Chunks on a given level + +# Used to expand spaces + +sub exp_sp {$c1++;$c2=0 if $c1>$re; return " " x ($c2+$fr+1);} + +# Outputs the outermost level of the output list (until the start of level 1) +# If gets a true argument, does not expand spaces + +sub print { + warn "Printing...\n" if $debug & $debug_flow; + local($last,$l,$exp) = ($#level? $chunks[$level[1]]-1: $#out); + ($last >=0) || return; + $l=&length($out[0]); + if ($last >= 1) { + for (1..$last) { + $l += &length($out[$_]); + } + } + if ($debug & $debug_length) { + if ($l != $curlength) { + for (0..$last) { + warn "Wrong lengths Record $_ $out[$_]\n__ENDREC__\n" ; + } + } + } + $curlength=$l; + warn "l=$l, linelength=$linelength, curlength=$curlength\n" + if $debug & $debug_length; + IF_L: + { + if (!shift && ($l=$linelength-$curlength)>=0) { + warn "entered branch for long string\n" + if $debug & $debug_length; + $exp=0; + (($out[$last] =~ s/\s+$//) && ($l+=length($&))) + if $out[$last] =~ /^0,/; + warn "l=$l with whitespace\n" + if $debug & $debug_length; + last IF_L if $l<=0; + local($str,$h,$fr,$re,$c1,$c2,@t); + for (0..$last) { + ($str,$h)=(split(/,/,$out[$_],5))[4,0]; + (@t = ($str =~ /( )/g), $exp+=@t) if (!$h); + } + if ($exp) { + $re=$l % $exp; + $fr=int(($l-$re)/$exp); + warn "$l Extra spaces in $exp places, Fr=$fr," . + " Remainder=$re, LL=$linelength, CL=$curlength\n" if $debug & $debug_length; + $c1=0; + $c2=1; + for (0..$last) { + ($str,$h)=(split(/,/,$out[$_],5))[4,0]; + unless ($h || $opt_ragged) { + $str =~ s/ /&exp_sp/ge; + $out[$_]=&string2record($str); + } + } + } + } + else {warn "Do not want to expand $l spaces\n" if $debug & $debug_length;} + } + if ($last >= 1) { + for (1..$last) { + $out[0] = &join($out[0],$out[$_]); + } + } + $l=&length($out[0]); + warn "LL=$linelength, CurL=$curlength, OutL=$l\n" if $debug & $debug_length; + &printrecord($out[0]); + $curlength=0; + if ($#out>$last) { + @out=@out[$last+1..$#out]; + for (0..$#chunks) {$chunks[$_] -= $last+1;} + } else { + @out=(); + } + if ($#level) { + splice(@chunks,1,$level[1]-2); + } else { + @chunks=(0); + } +} + +# Cuts prepared piece and arg into printable parts (unfinished) +# Suppose that level==0 + +sub prepare_cut { + warn "Preparing to cut $_[0]\n" if $debug & $debug_flow; + warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow; + (warn "\$#level non 0", return $_[0]) if ($#level!=0); + local($lenadd)=(&length($_[0])); + local($lenrem)=($linelength-$curlength); + if ($lenadd+$curlength<=$linelength) { + warn "No need to cut, extra=$lenrem\n" if $debug & $debug_flow; + return $_[0]; + } + # Try to find a cut in the added record before $lenrem + local($rec)=@_; + local($h,$str,$ind,@p)=(split(/,/,$rec,5))[0,4]; + local($good)=(0); + if ($h<2) { + while ($lenrem<$lenadd && ($ind=rindex($str," ",$lenrem))>-1) { + warn "Cut found at $ind, lenrem=$lenrem\n" if $debug & $debug_flow; + $good=1; + # $ind=1 means we can cut 2 chars + @p= &cut($ind+1,$rec); + warn "After cut: @p\n" if $debug & $debug_record; + push(@out,$p[0]); + $curlength+=$ind+1; + #if ($#out!=$chunks[$#chunks]) {push(@chunks,$#out);} + &print(); + $rec=$p[1]; + ($lenadd,$str)=(split(/,/,$rec,5))[1,4]; + $lenrem=$linelength; + } + return $rec if $good; + } + # If the added record is too long, there is no sense in cutting + # things we have already, since we will cut the added record anyway... + local($forcedcut); + if ($lenadd > $linelength && $lenrem) { + @p= &cut($lenrem,$rec); + warn "After forced cut: @p\n" if $debug & $debug_record; + push(@out,$p[0]); + $curlength+=$lenrem; + &print(); + $rec=$p[1]; + ($lenadd,$str)=(split(/,/,$rec,5))[1,4]; + $lenrem=$linelength; + } + # Now try to find a cut before the added record + if ($#out>=0 && !$forcedcut) { + for (0..$#out) { + ($h,$str)=(split(/,/,$out[$#out-$_],5))[0,4]; + if ($h<2 && ($ind=rindex($str," "))>-1 && ($ind>0 || $_<$#out)) { + warn "Cut found at $ind, in chunk $#out-$_\n" + if $debug & $debug_flow; + # split at given position + @p=&cut($ind+1,$out[$#out-$_]); + $out[$#out-$_]=$p[0]; + @p=($p[1],@out[$#out-$_+1..$#out]); + @out=@out[0..$#out-$_]; +warn "\@p is !", join('!', @p), "!\n\@out is !", join('!', @out), "!\n" + if $debug & $debug_flow; + &print(); + warn "did reach that\n" + if $debug & $debug_length; + @out=@p; + $good=1; + $curlength=0; + for (@out) {$curlength+=&length($_);} + last; + } + warn "did reach wow-this\n" + if $debug & $debug_length; + } + warn "did reach this\n" + if $debug & $debug_length; + } + return &prepare_cut if $good; + warn "No cut found!\n" if $debug & $debug_flow; + # If anything else fails use force + &print(); + while (&length($rec)>$linelength) { + @p=&cut($linelength,$rec); + @out=($p[0]); + &print(); + $rec=$p[1]; + } + $curlength=0; + return $rec; +} + +# Adds a record to the output list + +sub commit { + warn "Adding $_[0]\n" if $debug & $debug_flow; + warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow; + local($rec)=@_; + if ($#level==0) { + local($len)=&length($_[0]); + if ($curlength+$len>$linelength) { + $rec=&prepare_cut; + $len=&length($rec); + } + $curlength+=$len; + } + push(@out,$rec); + if ($#out!=$chunks[$#chunks]) {push(@chunks,$#out);} + warn "a:Last chunk number $#chunks, last record $#out, the first chunk\n" if $debug & $debug_flow; + warn " on the last level=$#level is $level[$#level], waiting for $wait[$#level]\n" if $debug & $debug_flow; + if ($#level && $wait[$#level] == $#chunks-$level[$#level]+1) { + local($sub,$arg)=($action[$#level]); + if ($sub eq "") {&finish($wait[$#level]);} + else { + &callsub($sub); + } + } + warn "curlength=$curlength on level=$#level\n" if $debug & $debug_length; +} + +# Calls a subroutine, possibly with arguments + +sub callsub { + local($sub)=(shift); + index($sub,";")>=0? + (($sub,$arg)=split(";",$sub,2), &$sub($arg)): + &$sub; +} + +# Simulates Removing a record from the output list (unfinished) + +sub uncommit { + warn "Deleting...\n" if $debug & $debug_flow; + warn "B:Last chunk number $#chunks, last record $#out\n" if $debug & $debug_flow; + (warn "Nothing to uncommit", return) if $#out<0; + if ($#level==0) { + local($len)=&length($out[$#out]); + $curlength-=$len; + } + local($rec); + $rec=$out[$#out]; + $out[$#out]=&empty(); + warn "UnCommit: now $chunks[$#chunks] $rec\n__ENDREC__\n" + if $debug & $debug_record; + #if ($#out<$chunks[$#chunks]) {pop(@chunks);} + warn "a:Last chunk number $#chunks, last record $#out, the first chunk\n" if $debug & $debug_flow; + warn " on the last level=$#level is $level[$#level], waiting for $wait[$#level]" if $debug & $debug_flow; + warn "curlength=$curlength on level=$#level\n" if $debug & $debug_length; + return $rec; +} + +# finish($event, $force_one_group) + +# Finish the inner scope with the event $event. If this scope is empty, +# add an empty record. If finishing the group would bring us to toplevel +# and $force_one_group is not set, can break things into chunks to improve +# line-breaking. + +# No additional action is executed + +sub finish { + warn "Finishing with $_[0]\n" if $debug & $debug_flow; + local($event,$len,$rec)=(shift); + if (($wait[$#level] ne "") && ($wait[$#level] ne $event)) { + warn "Got `$event' while waiting for `$wait[$#wait]', rest=$par"; + } + warn "Got finishing event `$event' in the outermost block, rest=$par" + unless $#level; + if ($#out<$chunks[$level[$#level]]) {push(@out,&empty);} + # Make anything after $level[$#level] one chunk if there is anything + warn "B:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + $#chunks=$level[$#level]; #if $chunks[$level[$#level]]<=$#out; + local(@t); + if ($#level==1 && !$_[0]) { + @t=@out[$chunks[$#chunks]..$#out]; + $#out=$chunks[$#chunks]-1; + } + # $#chunks-- if $chunks[$#chunks-1]==$chunks[$#chunks]; + $#level--; + $#action--; + $#tokenByToken--; + $#wait--; + if ($#level==0 && !$_[0]) { + for (@t) {&commit($_);} + } + warn + "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" + if $debug & $debug_flow; + if ($wait[$#level] == $#chunks-$level[$#level]+1) { + local($sub)=($action[$#level]); + if ($sub eq "") {&finish($wait[$#level]);} + else {&callsub($sub);} + } +} + +# finish level and discard it + +sub finish_ignore { + warn "Finish_ignoring with $_[0]\n" if $debug & $debug_flow; + local($event,$len)=(shift); + if (($wait[$#level] ne "") && ($wait[$#level] ne $event)) { + warn "Got `$event' while waiting for `$wait[$#wait]', rest=$par"; + } + warn "Got finishing event `$event' in the outermost block, rest=$par" unless $#level; + $#out=$chunks[$level[$#level]]-1; + pop(@level); + pop(@tokenByToken); + pop(@action); + pop(@wait); +} + +# Begin a new level with waiting for $event + +# Special events: If number, wait this number of chunks + +sub start { + warn "Beginning with $_[0], $_[1]\n" if $debug & $debug_flow; + warn "B:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + if ($chunks[$level[$#level]] <= $#out && $chunks[$#chunks] <= $#out) { + # the last level is non empty + push(@chunks, $#out + 1); + } + push(@level, $#chunks); + push(@tokenByToken, 0); + $wait[$#level] = shift; + if ($#_<0) { $action[$#level] = ""; } else { $action[$#level] = shift; } + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; +} + +# Asserts that the given number of chunks exists in the last level + +sub assertHave { + local($i,$ii)=(shift); + if (($ii=$#chunks-$level[$#level]+1)<$i) { + warn "Too few chunks ($ii) in inner level, expecting $i"; + return 0; + } + return 1; +} + +# Takes the last ARGUMENT chunks, collapse them to records + +sub collapse { + warn "Collapsing $_[0]...\n" if $debug & $debug_flow; + local($i,$ii,$_)=(shift); + if (($ii=$#chunks-$level[$#level]+1)<$i) { + warn "Too few chunks ($ii) in inner level, expecting $i"; + $i=$ii; + } + if ($i>0) { + for (0..$i-1) { + &collapseOne($#chunks-$_); + } + for (1..$i-1) { + $chunks[$#chunks-$_+1]=$chunks[$#chunks-$i+1]+$i-$_; + } + } +} + +# Collapses all the chunks on given level + +sub collapseAll {&collapse($#chunks-$level[$#level]+1);} + +# Collapses a given chunk in the array @out. No correction of @chunks is +# performed + +sub collapseOne { + local($n)=(shift); + local($out,$last,$_)=($out[$chunks[$n]]); + if ($n==$#chunks) {$last=$#out;} else {$last=$chunks[$n+1]-1;} + warn "Collapsing_one $n, records $chunks[$n]..$last\n" + if $debug & $debug_flow; + return unless $last>$chunks[$n]; + warn "Collapsing chunk $n beginning at $chunks[$n], ending at $last\n" if $debug & $debug_flow; + for ($chunks[$n]+1..$last) { + $out=&join($out,$out[$_]); + } + splice(@out,$chunks[$n],$last+1-$chunks[$n],$out); + # $#out-=$last-$chunks[$n]; #bug in perl? + warn "Collapsed $chunks[$n]: $out[$chunks[$n]]\n__END__\n" if $debug & $debug_record; +} + +# Return an empty record + +sub empty { + return "0,0,0,0,"; +} + +# Commits a record with a sum symbol +sub sum { + &commit("3,2,1,0," . <<'EOF'); +__ +❯ +‾‾ +EOF +} + +# Additional argument specifies if to make not-expandable, not-trimmable + +sub string2record { + local($h,$sp)=(0); + if ($_[1]) {$h=1;$sp=0;} + else { + $sp=($_[0] =~ /(\s)/g); + $sp || ($sp=0); # Sometimes it is undef? + } + return "$h," . length($_[0]) . ",0,$sp,$_[0]"; +} + +# The second argument forces the block length no matter what is the +# length the string (for strings with screen escapes). + +sub record_forcelength { + $_[0] =~ s/^(\d+),(\d+)/$1,$_[1]/; +} + +sub finishBuffer { + while ($#level > 0) { + &finish(""); + } + &print(1); +} + +# Takes two records, returns a record that concatenates them vertically +# To make fraction simpler, baseline is the last line of the first record + +sub vStack { + local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); + local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); + $h1 || $h1++; + $h2 || $h2++; + local($h,$l,$b)=($h1+$h2, ($l1>$l2 ? $l1: $l2), $h1-1); + warn "\$h1=$h1, \$h2=$h2, Vstacked: $h,$l,$b,0,$str1\n$str2\n__END__\n" if $debug & $debug_record; + return "$h,$l,$b,0,$str1\n$str2"; +} + +# Takes two records, returns a record that contains them and forms +# SupSub block + +sub superSub { + local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); + local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); + $h1 || $h1++; + $h2 || $h2++; + local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2)); + return "$h,$l,$h1,0,$str1\n\n$str2"; +} + +# Takes two records, returns a record that contains them and forms +# SupSub block + +sub subSuper { + local($h1,$l1,$b1,$sp1,$str1)=split(/,/,shift,5); + local($h2,$l2,$b2,$sp2,$str2)=split(/,/,shift,5); + $h1 || $h1++; + $h2 || $h2++; + local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2)); + return "$h,$l,$h1,0,$str2\n\n$str1"; +} + +# Takes the last two records, returns a record that contains them and forms +# SupSub block + +sub f_subSuper { + warn "Entering f_subSuper...\n" if $debug & $debug_flow; + &trim(2); + &collapse(2); + &assertHave(2) || &finish("",1); + &sup_sub(0,1); +} + +sub sup_sub { + local($p1,$p2)=($#out-shift,$#out-shift); + warn "Super $p1 $out[$p1]\nSub $p2 $out[$p2]\n__END__\n" if $debug & $debug_record; + local($h1,$l1,$b1,$sp1,$str1)=split(/,/,$out[$p1],5); + local($h2,$l2,$b2,$sp2,$str2)=split(/,/,$out[$p2],5); + if ($l1==0 && $l2==0) {return;} + $h1 || $h1++; + $h2 || $h2++; + local($h,$l)=($h1+$h2+1, ($l1>$l2 ? $l1: $l2)); + $#chunks--; + $#out--; + if ($l1==0) { + $h2++; + $out[$#out]="$h2,$l,0,0,\n$str2"; + } elsif ($l2==0) { + $h=$h1+1; + $out[$#out]="$h,$l,$h1,0,$str1\n"; + } else { + $out[$#out]="$h,$l,$h1,0,$str1\n\n$str2"; + } + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(2,1); +} + +# Takes the last two records, returns a record that contains them and forms +# SupSub block + +sub f_superSub { + warn "Entering f_superSub...\n" if $debug & $debug_flow; + &trim(2); + &collapse(2); + &assertHave(2) || &finish("",1); + &sup_sub(1,0); +} + +# digest \begin{...} and similar: handles argument to a subroutine +# given as argument + +sub f_get1 { + warn "Entering f_get1...\n" if $debug & $debug_flow; + (warn "Argument of f_get1 consists of 2 or more chunks", return) + if $#out != $chunks[$#chunks]; + local($rec,$sub); + #$rec=&uncommit; + $rec=$out[$#out]; + $rec=~s/.*,//; + $sub=shift; + defined $sub ? return &$sub($rec): return $rec; +} + +sub f_begin { + warn "Entering f_begin...\n" if $debug & $debug_flow; + &collapse(1); + &assertHave(1) || &finish(""); + local($arg,$env)=(&f_get1()); + &finish_ignore(1); + $arg=~s/^\s+//; + $arg=~s/\s+$//; + return if defined $environment_none{$arg}; + if (defined ($env=$environment{$arg})) { + local($b,$e)=split(/,/,$env); + for (split(":",$b)) {&callsub($_);} + } else {&puts("\\begin{$arg}");} +} + +sub f_end { + warn "Entering f_end...\n" if $debug & $debug_flow; + &collapse(1); + &assertHave(1) || &finish(""); + local($arg,$env)=(&f_get1()); + &finish_ignore(1); + $arg=~s/^\s+//; + $arg=~s/\s+$//; + return if defined $environment_none{$arg}; + if (defined ($env=$environment{$arg})) { + local($b,$e)=split(/,/,$env,2); + for (split(":",$e)) {&callsub($_);} + } else {&puts("\\end{$arg}");} +} + + +sub f_literal_no_length { + warn "Entering f_literal_with_length...\n" if $debug & $debug_flow; + # &trim(1); + &collapse(1); + &assertHave(1) || &finish("",1); + record_forcelength($out[$#out], 0); + &finish(1,1); +} + +sub f_discard { + warn "Entering f_discard...\n" if $debug & $debug_flow; + &finish_ignore($wait[$#level]); +} + +# Takes a number and a record, returns a centered record + +sub center { + local($len,$left)=(shift,0); + warn "Entering center, ll=$len, rec=$_[0]\n__ENDREC__\n" if $debug & $debug_flow; + #$_[0]; # bug in perl? + local($h1,$l1,$b1,$sp1,$str1)=split(/,/,$_[0],5); + $h1 || $h1++; + if (($left=$len-$l1)<=0) {return $_[0];} + $left=int($left/2); + local($out,$first)=("",1); + for (split(/\n/,$str1,$h1)) { + if ($first) {$first=0;} + else {$out .= "\n";} + $out .= " " x $left . $_; + } + return "$h1,$len,$b1,0,$out"; +} + +# Example of radical +#<<'EOF'; +# +--+ +#\|12 +#EOF +<$l2 ? $l1: $l2)); + $out[$#out-1]=&vStack(&vStack(¢er($len,$out[$#out-1]), + &string2record("─" x $len)), + ¢er($len,$out[$#out])); + $#chunks--; + $#out--; + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(2,1); +} + +sub f_choose { + warn "Entering f_choose...\n" if $debug & $debug_flow; + &trim(2); + &collapse(2); + &assertHave(2) || &finish("",1); + warn "Numer `$out[$#out-1]'\nDenom `$out[$#out]'\n__END__\n" if $debug & $debug_record; + local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out])); + local($len)=(($l1>$l2 ? $l1: $l2)); + $out[$#out]=&vStack(&vStack(¢er($len,$out[$#out-1]), + &string2record(" " x $len)), + ¢er($len,$out[$#out])); + $#chunks++; + $#out++; + #warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + $out[$#out - 2] = &string2record("("); + $out[$#out] = &string2record(")"); + local($h,$b)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/)[0,1]; + &makehigh($out[$#out-2],$h,$b,0,1); + &makehigh($out[$#out],$h,$b,1,0); + &finish(2,1); +} + + +sub f_buildrel { + warn "Entering f_buildrel...\n" if $debug & $debug_flow; + &trim(3); + &collapse(3); + &assertHave(3) || &finish("",1); + warn "What: $out[$#out-2]\nOver $out[$#out]\n__END__\n" if $debug & $debug_record; + local($rec)=($out[$#out-2]); + $out[$#out-2]=$out[$#out]; + $#chunks-=2; + $#out-=2; + &f_putover($rec,1); + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(3,1); +} + +# Takes two records, returns a record that contains them and forms a +# fraction block + +sub fraction { + local($l1,$l2)=(&length($_[0]),&length($_[1])); + local($len)=(($l1>$l2 ? $l1: $l2)); + return &vStack(&vStack(¢er($len,shift), + &string2record("-" x $len)), + ¢er($len,shift)); +} + +# Commits a given string + +sub puts { + &commit(&string2record); +} + +# =========================================== +# +# Main script entry point: this function +# runs over and over until there is nothing +# left for it to process. +# +# =========================================== +sub paragraph { + local($par); + $par=<>; + return 0 unless defined $par; + return 1 unless $par =~ /\S/; # whitespace only + print "\n" if $secondtime++ && !$opt_by_par; + #$par =~ s/(^|[^\\])%.*\n[ \t]*/\1/g; + $par =~ s/((^|[^\\])(\\\\)*)(%.*\n[ \t]*)+/\1/g; + $par =~ s/\n\s*\n/\\par /g; + $par =~ s/\s+/ /g; + $par =~ s/\s+$//; + $par =~ s/(\$\$)\s+/\1/g; + $par =~ s/\\par\s*$//; + local($defcount,$piece,$pure,$type,$sub,@t,$arg)=(0); + &commit("1,5,0,0, ") + unless $opt_noindent || ($par =~ s/^\s*\\noindent\s*([^a-zA-Z\s]|$)/\1/); + while ($tokenByToken[$#level] ? + ($par =~ s/^\s*($tokenpattern)//o): ($par =~ s/^($multitokenpattern)//o)) { + warn "tokenByToken=$tokenByToken[$#level], eaten=`$1'\n" + if $debug & $debug_parsing; + if (($piece=$1) =~ /^$usualtokenclass/o) { + # plain piece + &puts($piece); + } else { + # macro or delimiter + ($pure = $piece) =~ s/\s+$//; + if (defined ($type=$type{$pure})) { + if ($type eq "def") { + warn "To many def expansions in a paragraph" if $defcount++==$maxdef; + last if $defcount>$maxdef; + @t=(0); + for (1..$args{$pure}) { + push(@t,&get_balanced()); + } + warn "Defined token `$pure' found with $args{$pure} arguments @t[1..$#t]\n" + if $debug & $debug_parsing; + $sub=$def{$pure}; + $sub =~ s/(^|[^\\#])#(\d)/$1 . $t[$2]/ge if $args{$pure}; + $par=$sub . $par; + } elsif ($type eq "sub") { + $sub=$contents{$pure}; + index($sub,";")>=0? + (($sub,$arg)=split(";",$sub,2), &$sub($pure,$arg)): + &$sub($pure); + } elsif ($type =~ /^sub(\d+)$/) { + &start($1,"f_$contents{$pure}"); + $tokenByToken[$#level]=1; + } elsif ($type =~ /^get(\d+)$/) { + &start($1+1); + &puts($piece); + $tokenByToken[$#level]=1; + } elsif ($type =~ /^discard(\d+)$/) { + &start($1,"f_discard"); + $tokenByToken[$#level]=1; + } elsif ($type eq "record") { + &commit($contents{$pure}); + } elsif ($type eq "self") { + &puts(substr($pure,1) . ($pure =~ /^\\[a-zA-Z]/ ? " ": "")); + } elsif ($type eq "par_self") { + &finishBuffer; + &commit("1,5,0,0, "); + &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": "")); + } elsif ($type eq "self_par") { + &puts($pure . ($pure =~ /^\\[a-zA-Z]/ ? " ": "")); + &finishBuffer; + &commit("1,5,0,0, ") + unless $par =~ s/^\s*\\noindent(\s+|([^a-zA-Z\s])|$)/\2/; + } elsif ($type eq "string") { + &puts($contents{$pure},1); + } elsif ($type eq "nothing") { + } else { + warn "Error with type `$type' while interpreting `$pure'"; + } + } else { + &puts($piece); + } + } + } + warn "Unrecognized part of input `$par',\n\ttoken-by-token[$#level]=$tokenByToken[$#level]" if $par ne ""; + + &finishBuffer if $#out >= 0; + + 1; # return 0 if eof(); +} + +sub subscript { + &start(1,"f_subscript"); + $tokenByToken[$#level]=1; +} + +sub superscript { + &start(1,"f_superscript"); + $tokenByToken[$#level]=1; +} + + +sub f_subscript { + $wait[$#level]=2; + $action[$#level]="f_subSuper"; + if (($par !~ s/^\s*\^//) && + ($par !~ s:^\s*\\begin\s*\{Sp\}:\\begin\{matrix\}:)) { + &commit(&empty); + } +} + +sub f_overline { + warn "Entering f_overline...\n" if $debug & $debug_flow; + &trim(1); + &collapse(1); + &assertHave(1) || &finish("",1); + warn "Overlining $out[$#out]\n__END__\n" if $debug & $debug_record; + local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); + $out[$#out]=&vStack(&string2record("_" x $len), + $out[$#out]); + $b++; + #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; + &setbaseline($out[$#out],$b); + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(1,1); +} + +sub f_underline { + warn "Entering f_underline...\n" if $debug & $debug_flow; + &trim(1); + &collapse(1); + &assertHave(1) || &finish("",1); + warn "Underlining $out[$#out]\n__END__\n" if $debug & $debug_record; + local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); + $out[$#out]=&vStack($out[$#out],&string2record("_" x $len)); + #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; + &setbaseline($out[$#out],$b); + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(1,1); +} + +sub f_not { + warn "Entering f_not...\n" if $debug & $debug_flow; + &collapse(1); + &assertHave(1) || &finish("",1); + warn "Negating $out[$#out]\n__END__\n" if $debug & $debug_record; + local($str)=(split(/,/,$out[$#out]))[4]; + if ($str eq "=") { + $out[$#out]=$contents{"\\neq"}; + } elsif ($str =~ /^\s*\|\s*$/) { + $out[$#out]=$contents{"\\nmid"}; + } elsif ($out[$#out] eq $contents{"\\in"}) { + $out[$#out]=$contents{"\\notin"}; + } else { + $out[$#out]=&join(&string2record("\\not"),$out[$#out]); + } + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(1,1); +} + +sub f_putunder { + warn "Entering f_putunder...\n" if $debug & $debug_flow; + &trim(1); + &collapse(1); + &assertHave(1) || &finish("",1); + warn "Putting Under $out[$#out]\n__END__\n" if $debug & $debug_record; + local($h,$len,$b)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); + local($l2)=(&length($_[0])); + local($len)=(($l1>$l2 ? $l1: $l2)); + $out[$#out]=&vStack(¢er($len,$out[$#out]),¢er($len,shift)); + #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; + &setbaseline($out[$#out],$b); + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(1,1); +} + +# if has additional true argument will not finish +# Takes record to put over + +sub f_putover { + warn "Entering f_putover...\n" if $debug & $debug_flow; + &trim(1); + &collapse(1); + &assertHave(1) || &finish("",1); + warn "Putting Over $out[$#out]\n__END__\n" if $debug & $debug_record; + local($h,$l1,$b,$b1)=($out[$#out] =~ /^(\d+),(\d+),(\d+)/); + local($l2)=(&length($_[0])); + local($len)=(($l1>$l2 ? $l1: $l2)); + ($b1)=($_[0] =~ /^(\d+)/); + $b+=$b1+1; + $out[$#out]=&vStack(¢er($len,shift),¢er($len,$out[$#out])); + #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$b/; + &setbaseline($out[$#out],$b); + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(1,1) unless shift; +} + +sub f_putpar { + warn "Entering f_putpar...\n" if $debug & $debug_flow; + &trim(1); + local($l,$r)=split(";",shift); + &collapse(1); + &assertHave(1) || &finish("",1); + warn "Putting Parentheses $out[$#out]\n__END__\n" if $debug & $debug_record; + $out[$#out]=&join(&string2record($l), + &join($out[$#out],&string2record($r))); + &finish(1,1); +} + +sub f_putover_string { + &f_putover(&string2record); +} + +sub f_widehat { + &trim(1); + &collapse(1); + local($l)=(&length($out[$#out])); + if ($l<=1) {&f_putover(&string2record("^"));} + else {&f_putover(&string2record("/" . "~" x ($l-2) . "\\"));} +} + +sub f_widetilde { + &trim(1); + &collapse(1); + local($l,$l1)=(&length($out[$#out])); + if ($l<=1) {&f_putover(&string2record("~"));} + elsif ($l<=3) {&f_putover(&string2record("/\\/"));} + else {&f_putover(&string2record("/" . "~" x ($l1=int($l/2-1)) . + "\\" . "_" x ($l-3-$l1) . "/"));} +} + +sub f_superscript { + $wait[$#level]=2; + $action[$#level]="f_superSub"; + if (($par !~ s/^\s*\_//) && + ($par !~ s:^\s*\\begin\s*\{Sb\}:\\begin\{matrix\}:)) { + &commit(&empty); + } +} + +sub let { + $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o; +} + +sub let_exp { + $par =~ s/^($tokenpattern)(= ?)?($tokenpattern)//o; + return if index($&,'@')>=0; + local($what)=$1; + $type{$what}='def'; + $& =~ /($tokenpattern)$/; + $def{$what}=$1; + $args{$what}=0; + warn "Definition of `$what' with $args{$what} args is `$def{$what}'\n" + if $debug & $debug_parsing; +} + + +sub def { + $par =~ s/^[^{]*//; + &start(1,"f_discard"); + $tokenByToken[$#level]=1; +} + +sub def_exp { + return unless $par =~ s:^(([^\\{]|\\.)*)\{:\{:; + local($arg)=($1); + local($def,$act)=(&get_balanced()); + return unless defined $def; + return if index("$arg$def",'@')>=0; + return if $def =~ /\\([egx]?def|fi)([^a-zA-Z]|$)/; + $def .= " " if $def =~ /($macro)$/o; + &define($arg,$def); +} + +# Arguments: Token . Parameters, Expansion + +sub define { + local($arg,$def,$act)=(shift,shift); + return unless $arg =~ /^($active)/o; + $act=$1; + $args{$act}=$'; + return unless $args{$act} =~ /^(#\d)*$/; + $args{$act}=length($args{$act})/2; + $def{$act}=$def; + $type{$act}='def'; + warn "Definition of `$act' with $args{$act} args is `$def'\n" + if $debug & $debug_parsing; +} + +sub defb { + for (@_) { + &define("\\$_","\\begin{$_}");&define("\\end$_","\\end{$_}"); + } +} + +# Discards surrounding {} + +sub get_balanced { + return undef unless $par =~ s/^($tokenpattern)//; + return $1 unless $1 eq '{'; + local($def,$lev)=('',1); + while ($lev) { + last unless $par =~ s/^[^\\{}]|\\.|[{}]//; + $lev++ if $& eq '{'; + $lev-- if $& eq '}'; + $def .= $& if $lev; + } + (warn "Balanced text not finished!",return undef) if $lev; + return $def; +} + + +sub open_curly { + #&puts("{") unless $tokenByToken[$#level]; + &start("}"); +} + +# Deletes extra spaces at the end of a record + +sub trim_end { + local($h,$str)=(split(/,/,$_[0],5))[0,4]; + if (!$h) { + $str =~ s/\s+$//; + $_[0]=&string2record($str); + warn "Trimmed End `$_[0]'\n__END__\n" if $debug & $debug_record; + } +} + +# Deletes extra spaces at the beginning of a record + +sub trim_beg { + local($h,$str)=(split(/,/,$_[0],5))[0,4]; + if (!$h) { + $str =~ s/^\s+//; + $_[0]=&string2record($str); + warn "Trimmed Beg `$_[0]'\n__END__\n" if $debug & $debug_record; + } +} + +# Deletes extra spaces at the ends of a chunk with given number + +sub trim_one { + &trim_beg($out[$chunks[$_[0]]]); + &trim_end($_[0]==$#chunks? $out[$#out]: $out[$chunks[$_[0]+1]-1]); +} + +# Deletes extra spaces at the ends of a given number of chunks + +sub trim { + for ($#chunks-$_[0]+1..$#chunks) {&trim_one($_);} +} + +# ========================== +# Start of inline mode maths +# ========================== +sub dollar { + if ($wait[$#level] eq '$') { # '; + &trim_end($out[$#out]); + &finish('$'); + } + else { + &start('$'); + $par =~ s/^\s+//; + } +} + +# ========================== +# Start of block mode maths +# ========================== +sub ddollar { + if ($wait[$#level] eq '$$') { + &trim_end($out[$#out]); + &finish('$$'); + return unless $#out>=0; + $#chunks=0; + $chunks[0]=0; + &trim(1); + &collapse(1); + &printrecord(¢er($linelength,$out[0])); + @level=(0); + @chunks=(0); + @tokenByToken=(0); + @out=(); + $curlength=0; + # Maybe after \begin{align} + } + else { + &finishBuffer; + &start('$$'); + } + $par =~ s/^\s+//; +} + +sub item { + &finishBuffer; + # To make unexpandable: + &commit("1,11,0,0, (\@) "); +} + +sub bbackslash { + if ($wait[$#level] eq '$$') { + &ddollar(); + &ddollar(); + } elsif ($wait[$#level] eq 'endCell') { + return if $par =~ /^\s*\\end/; # Ignore the last one + &finish('endCell', 1); + &trim(1); + &collapse(1); + &finish('endRow', 1); + &start('endRow'); + &start('endCell'); + } else { + #&puts(" \\\\ "); + ∥ + } +} + +sub ampersand { + if ($wait[$#level] eq 'endCell') { + &finish('endCell',1); + &trim(1); + &collapse(1); + &start('endCell'); + } +} + +sub matrix { + &start('endMatrix'); + &start('endRow'); + &start('endCell'); +} + +sub endmatrix { + &finish('endCell',1); + &trim(1); + &collapse(1); + &finish('endRow',1); + # Now chunks correspond to rows of the matrix, records inside chunks to + # Cells + &halign(split(";",shift)); + &finish('endMatrix',1); +} + +sub endmatrixArg { + &endmatrix(join(";",($_[0],split("",pop(@argStack))))); +} + +# Takes a matrix in the following form: chunks on the last level +# are row of the matrix, records inside chunks are cells. +# Puts the resulting matrix in the first record on the given level +# and truncates the rest + +# I'm trying to add parameters: +# length to insert between columns +# Array of centering options one for a column (last one repeated if needed) +# Currently supported: c for center +# r for right +# l for left + +sub halign { + local($explength)=(shift); + local(@c)=@_; + local($last,$le,$b,$h); + local(@w)=(); + #warn "levels @level, chunks @chunks, records @out\n"; + # Find metrics of cells + for $r (0..$#chunks-$level[$#level]) { + $last= ($r==$#chunks-$level[$#level]) ? $#out: + $chunks[$r+1+$level[$#level]]-1; + warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n" + if $debug & $debug_matrix; + for $c (0..$last-$chunks[$r+$level[$#level]]) { + ($h,$le,$b)= + ($out[$chunks[$r+$level[$#level]]+$c] =~ /(\d+),(\d+),(\d+)/); + # Format is Height:Length:Baseline + $w[$c]=$le unless $w[$c]>$le; + } + } + # expand the height and depth + for $c (0..$#w-1) {$w[$c]+=$explength;} + # Extend the @c array by the last element or "c" if it is empty + @c=("c") x @w unless @c; + @c=(@c,($c[$#c]) x (@w-@c)); + # Now expand the cells + warn "Widths of columns @w\n" if $debug & $debug_matrix; + for $r (0..$#chunks-$level[$#level]) { + $last= ($r==$#chunks-$level[$#level]) ? $#out: + $chunks[$r+1+$level[$#level]]-1; + warn "Row $r: last column " . ($last-$chunks[$r+$level[$#level]]) ."\n" + if $debug & $debug_matrix; + for $c (0..$last-$chunks[$r+$level[$#level]]) { + if ($c[$c] eq "c") { + warn "Centering row $r col $c to width $w[$c]\n" + if $debug & $debug_matrix; + $out[$chunks[$r+$level[$#level]]+$c]= + ¢er($w[$c],$out[$chunks[$r+$level[$#level]]+$c]); + } elsif ($c[$c] eq "l") { + warn "Expanding row $r col $c to width $w[$c]\n" + if $debug & $debug_matrix; + $out[$chunks[$r+$level[$#level]]+$c]= + &join($out[$chunks[$r+$level[$#level]]+$c], + &string2record(" " x + ($w[$c] - &length($out[$chunks[$r+$level[$#level]]+$c])))); + } elsif ($c[$c] eq "r") { + warn "Expanding row $r col $c to width $w[$c] on the left\n" + if $debug & $debug_matrix; + $out[$chunks[$r+$level[$#level]]+$c]= + &join(&string2record(" " x + ($w[$c]-$explength- + &length($out[$chunks[$r+$level[$#level]]+$c]))), + $out[$chunks[$r+$level[$#level]]+$c]); + $out[$chunks[$r+$level[$#level]]+$c]= + &join($out[$chunks[$r+$level[$#level]]+$c], + &string2record(" " x $explength)); + } else {warn "Unknown centering option `$c[$c]' for halign";} + } + } + # Now we creat rows + &collapseAll; + # And stack them vertically + for ($chunks[$level[$#level]]+1..$#out) { + $out[$chunks[$level[$#level]]]=&vStack($out[$chunks[$level[$#level]]], + $out[$_]); + } + &setbaseline($out[$chunks[$level[$#level]]], + int((&height($out[$chunks[$level[$#level]]])-1)/2)); + $#chunks=$level[$#level]; + $#out=$chunks[$level[$#level]]; +} + +sub close_curly { + &finish("}"); + #&puts("}") unless $tokenByToken[$#level]; # well, this can change under our foot... +} + +sub at { + local($c,$first,$second,$t,$m)=($par =~ /^(.)/); + if ($c eq '@') {&puts('@');$par =~ s/^.//;} + elsif (index("<>AV",$c)>=0) { + $m="&" if ($wait[$#level] eq 'endCell'); + $m="&&" if $m eq "&" && index("AV",$c)>=0; + &ersand if $m eq "&"; + $par =~ s/^.//; + $first=$second=""; + while (($t=&get_balanced()) ne $c && defined $t) { + $first .= $t; + } + while (($t=&get_balanced()) ne $c && defined $t) { + $second .= $t; + } + $par="{$first}{$second}$m" . $par; + local($l,$r); + ($l=$c) =~ tr/A>V/^/d; + ($r=$c) =~ tr/",$c)>=0 ? + &start(2,"f_arrow;$l;$r"): + &start(2,"f_arrow_v;$l;$r"); + } + elsif ($c eq "." && $wait[$#level] eq 'endCell') { + &ersand; + &ersand; + $par =~ s/^.//; + } + else {&puts('@');} +} + +# takes two tips of arrow as argument separated by ";", +# we assume that total length is 1 + +sub f_arrow { + warn "Entering f_arrow...\n" if $debug & $debug_flow; + local($l,$r)=split(";",shift); + &trim(2); + &collapse(2); + &assertHave(2) || &finish("",1); + warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record; + local($l1,$l2)=(&length($out[$#out-1]),&length($out[$#out])); + local($len)=(($l1>$l2 ? $l1: $l2)); + $out[$#out-1]=&vStack(&vStack(¢er($len+4,$out[$#out-1]), + &string2record(" $l" ."-" x ($len+1) . "$r ")), + ¢er($len+4,$out[$#out])); + $#chunks--; + $#out--; + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(2,1); +} + +# takes two tips of arrow as argument separated by ";", +# we assume that total length is 1 + +sub f_arrow_v { + warn "Entering f_arrow_v...\n" if $debug & $debug_flow; + local($l,$r)=split(";",shift); + &trim(2); + &collapse(2); + &assertHave(2) || &finish("",1); + warn "Over: $out[$#out-1]\nUnder: $out[$#out]\n__END__\n" if $debug & $debug_record; + local($h1,$b1)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/); + local($h2,$b2)=($out[$#out] =~ /^(\d+),\d+,(\d+)/); + local($b)=(($b1>$b2 ? $b1: $b2)); + local($res)=(&join($out[$#out-1],$out[$#out])); + local($h,$bb)=($res =~ /^(\d+),\d+,(\d+)/); + $bb=$b+1; + $out[$#out-1]=&vStack(&vputs(" " x ($b-$b1+1)), + $out[$#out-1]); + #$out[$#out-1] =~ s/^(\d+,\d+,)(\d+)/\1$bb/; + &setbaseline($out[$#out-1],$bb); + $out[$#out]=&vStack(&vputs(" " x ($b-$b2+1)), + $out[$#out]); + #$out[$#out] =~ s/^(\d+,\d+,)(\d+)/\1$bb/; + &setbaseline($out[$#out],$bb); + $out[$#out-1]=&join(&join($out[$#out-1], + &vputs($l ."|" x ($h+1) . $r,$b+1)), + $out[$#out]); + $#chunks--; + $#out--; + warn "a:Last $#chunks, the first on the last level=$#level is $level[$#level]" if $debug & $debug_flow; + &finish(2,1); +} + +sub noindent { + if ($#out == 0 && $#chunks == 0 && $out[$#out] eq '1,5,0,0, ') { + $#out--; + $#chunks--; + } else { + &puts('\\noindent'); + } +} + +# put strings vertically, returns a record with the second argument as baseline + +sub vputs { + local($b)=($_[1]); + $b=0 unless defined $b; + return length($_[0]) . ",1,$b,0," . join("\n",split('',$_[0])); +} + +sub choose { + if ($wait[$#level] eq '}') { + local($prevw)=($wait[$#level-1]); + $wait[$#level-1]="junk"; + &finish("}",1); + &collapse(1); + &assertHave(1) || &finish("",1); + local($rec)=$out[$#out]; + $#out--; + $#chunks--; + &start(2,"f_choose"); + $wait[$#level-1]=$prevw; + &start("}"); + &commit($rec); + &finish("}",1); + &start("}"); + } else {&puts("\\choose");} +} + +sub over { + if ($wait[$#level] eq '}') { + local($prevw)=($wait[$#level-1]); + $wait[$#level-1]="junk"; + &finish("}", 1); + &collapse(1); + &assertHave(1) || &finish("",1); + local($rec)=$out[$#out]; + $#out--; + $#chunks--; + &start(2,"f_fraction"); + $wait[$#level-1]=$prevw; + &start("}"); + &commit($rec); + &finish("}",1); + &start("}"); + } else {&puts("\\over");} +} + +# Takes a record, height, baseline, spaces_toleft and _toright +# and makes this record this high + +sub makehigh { + local($str)=(split(",",$_[0],5))[4]; + local($h,$b,$d)=($_[1],$_[2]+1); + warn "Entering makehigh(@_)\n" if $debug & $debug_flow; + if ($str eq ".") {$_[0] =~ s/\.$/ /;return;} + #$str="<" if $str eq "\\langle"; + #$str=">" if $str eq "\\rangle"; + $h=1 unless $h; + $d=$h-$b; + return if $h<2 || $h==2 && index("()<>",$str)>=0; + local(@c); + # split pattern: + # 0: base string + # 1: oneside expander + # 2: real expander + # 3: top tip + # 4: bottom top + # 5: mid + if ($str eq "(") {@c=split(":",'(: :│:╭:╰:│');} + elsif ($str eq ")") {@c=split(":",'): :│:╮:╯:│');} + elsif ($str eq "{") {@c=split(":",'{: :│:╭:╰:╡');} + elsif ($str eq "}") {@c=split(":",'}: :│:╮:╯:╞');} + elsif ($str eq "|" && $str eq "||") + {@c=split(":",'|:|:|:|:|:|');} + elsif ($str eq "[") {@c=split(":",'[: :│:┌:└:│');} + elsif ($str eq "]") {@c=split(":",']: :│:┐:┘:│');} + elsif ($str eq "<" || $str eq ">") { + return if $h==2; + local($l)=($b); + $l = $d+1 if $b < $d+1; + for (2..$l) { + $_[0]=&join($_[0], &vputs("⧸" . " " x (2*$_-3) . "⧹",$_-1)) if $str eq "<"; + $_[0]=&join(&vputs("⧹" . " " x (2*$_-3) . "⧸",$_-1), $_[0]) if $str eq ">"; + } + if ($str eq "<") { + $_[0] = &join($_[0], &string2record(" ")); + $_[0] =~ s/< / ⟨/; + } + elsif ($str eq ">") { + $_[0]=&join(&string2record(" "), $_[0]); + $_[0] =~ s/>/⟩/; + } + return; + } + else {return;} + + # form initial typesetting + $_[0]=&vputs(&makecompound($b,$d,@c), $b-1); + + # pad out the shape with spaces + $_[0]=&join($_[0],$_[0]) if length($str)==2; + $_[0]=&join(&string2record(" " x $_[3]),$_[0]) if $_[3]; + $_[0]=&join($_[0],&string2record(" " x $_[4])) if $_[4]; +} + + +sub right { + &finish("LeftRight",1); + &trim(1); + &collapse(1); +} + +sub f_left { + &trim(1); + &collapse(1); + &finish(1); + &start("LeftRight"); +} + +sub left { + &start(3,"f_leftright"); + $tokenByToken[$#level]=1; + &start(1,"f_left"); + $tokenByToken[$#level]=1; +} + +sub f_leftright_go { + &trim(1); + &collapse(1); + local($l,$r)=split(";",shift); + &assertHave(1) || warn "Left-Right not balanced"; + local($rec)=($out[$#out]); + $#out--; + $wait[$#level]="junk"; + &start(3,"f_leftright"); + &puts($l); + &commit($rec); + &puts($r); + &finish("junk"); +} + +sub beg_lr { + &start(1,"f_leftright_go" . ";" . shift); + $tokenByToken[$#level]=1; +} + +sub f_leftright { + &trim(1); + &collapse(1); + &assertHave(3) || warn "Left-Right not balanced"; + local($h,$b)=($out[$#out-1] =~ /^(\d+),\d+,(\d+)/)[0,1]; + &makehigh($out[$#out-2],$h,$b,0,1); + &makehigh($out[$#out],$h,$b,1,0); + &finish(3); +} + +# Arguments from $b/$d: +# +# 0: ascent (number) +# 1: descent (number) +# +# Arguments from @c: +# +# 2: base string +# 3: oneside expander +# 4: real expander +# 5: top tip +# 6: bottom top +# 7: mid +# +# All component should be one character long +sub makecompound { + $ascent = $_[0]; + $descent = $_[1]; + + $base = $_[2]; + $exp_one_side = $_[3]; + $exp_real = $_[4]; + $top = $_[5]; + $bottom = $_[6]; + $middle = $_[7]; + + # Note that this will go wrong for: + # + # = + # \begin{bmatrix} + # 1 & (z \cdot t) & (z \cdot t)^2 + # \end{bmatrix} + # + # where it places the resulting ascii a line too low, + # and I don't know why... + # + # - Pomax + + if ($ascent >= 1 && $descent > 0 && $exp_real eq $middle) { + return $top . $exp_real x ($ascent + $descent - 2) . $bottom; + } + + # No descent: + if ($descent <= 0) { + return $exp_one_side x ($ascent - 1) . $base; + } + + # No ascent: + if ($ascent <= 1) { + return $base . $exp_one_side x ($descent - 0); + } + + $above = ($ascent >= 2) ? $top . $exp_real x ($ascent - 2) : $top; + $below = ($descent > 1) ? $exp_real x ($descent - 1) . $bottom : $bottom; + return $above . $middle . $below; +} + +sub arg2stack {push(@argStack,&get_balanced());} + +sub par {&finishBuffer;&commit("1,5,0,0, ") + unless $par =~ s/^\s*\\noindent\s*(\s+|([^a-zA-Z\s])|$)/\2/;} + +$type{"\\sum"}="record"; +$contents{"\\sum"}="3,3,1,0," . <<'EOF'; +__ +❯ +‾‾ +EOF + +$type{"\\int"}="record"; +$contents{"\\int"}="3,3,1,0," . <<'EOF'; + ╭ + | + ╯ +EOF + +$type{"\\prod"}="record"; +$contents{"\\prod"}="2,3,1,0," . <<'EOF'; +___ +│ │ +EOF + +$type{"\\Sigma"}="record"; +$contents{"\\Sigma"}="3,2,1,0," . <<'EOF'; +__ +❯ +‾‾ +EOF + +$type{"\\textit"}="string"; +$contents{"\\textit"}=" "; + +$type{"\\oplus"}="string"; +$contents{"\\oplus"}="⊕"; + +$type{"\\otimes"}="string"; +$contents{"\\otimes"}="⊗"; + +$type{"\\ominus"}="string"; +$contents{"\\ominus"}="⊖"; + +$type{"\\leq"}="string"; +$contents{"\\leq"}="≤"; + +$type{"\\equiv"}="string"; +$contents{"\\equiv"}="≡"; + +$type{"\\geq"}="string"; +$contents{"\\geq"}="≥"; + +$type{"\\partial"}="string"; +$contents{"\\partial"}="∂"; + +$type{"\\forall"}="string"; +$contents{"\\forall"}="∀"; + +$type{"\\exists"}="string"; +$contents{"\\exists"}="∃"; + +$type{"\\owns"}="string"; +$contents{"\\owns"}="∋"; + +$type{"\\ni"}="string"; +$contents{"\\ni"}="∌"; + +$type{"\\in"}="string"; +$contents{"\\in"}="∈"; + +$type{"\\notin"}="string"; +$contents{"\\notin"}="∉"; + +$type{"\\qed"}="string"; +$contents{"\\qed"}="∎"; + +$type{"\\pm"}="string"; +$contents{"\\pm"}="±"; + +$type{"\\mp"}="string"; +$contents{"\\mp"}="∓"; + +$type{"\\cong"}="string"; +$contents{"\\cong"}="≅"; + +$type{"\\neq"}="string"; +$contents{"\\neq"}="≠"; + +$type{"\\nmid"}="string"; +$contents{"\\nmid"}="∤"; + +$type{"\\subset"}="string"; +$contents{"\\subset"}="⊂"; + +$type{"\\subseteq"}="string"; +$contents{"\\subseteq"}="⊆"; + +$type{"\\supseteq"}="string"; +$contents{"\\subseteq"}="⊇"; + +$type{"\\supset"}="string"; +$contents{"\\supset"}="⊃"; + +$type{"\\sqrt"}="sub1"; +$contents{"\\sqrt"}="radical"; + +$type{"\\buildrel"}="sub3"; +$contents{"\\buildrel"}="buildrel"; + +$type{"\\frac"}="sub2"; +$contents{"\\frac"}="fraction"; + +$type{"\\LITERALnoLENGTH"}="sub1"; +$contents{"\\LITERALnoLENGTH"}="literal_no_length"; + +for ("text","operatorname","operatornamewithlimits","relax","-", + "notag","!","/","protect","mathcal","Bbb","bf","it","em","boldsymbol", + "cal","Cal","goth","ref","maketitle","expandafter","csname","endcsname", + "makeatletter","makeatother","topmatter","endtopmatter","rm", + "NoBlackBoxes","document","TagsOnRight","bold","dsize","roster", + "endroster","endkey","endRefs","enddocument","displaystyle", + "twelverm","tenrm","twelvefm","tenfm","hbox","mbox") { + $type{"\\$_"}="nothing"; +} +for ("par","endtitle","endauthor","endaffil","endaddress","endemail", + "endhead","key","medskip","smallskip","bigskip","newpage", + "vfill","eject","endgraph") { + $type{"\\$_"}="sub"; + $contents{"\\$_"}="par"; +} + +for ("proclaim","demo",) { + $type{"\\$_"}="par_self"; +} + +for ("endproclaim","enddemo",) { + $type{"\\$_"}="self_par"; +} + +#$type{"&"}="nothing"; + +$type{"\\let"}="sub"; +$contents{"\\let"}="let_exp"; + +$type{"\\def"}="sub"; +$contents{"\\def"}="def_exp"; + +$type{"\\item"}="sub"; +$contents{"\\item"}="item"; + +$type{"{"}="sub"; +$contents{"{"}="open_curly"; + +$type{"}"}="sub"; +$contents{"}"}="close_curly"; + +$type{"&"}="sub"; +$contents{"&"}="ampersand"; + +$type{'$'}="sub"; +$contents{'$'}="dollar"; # START OF INLINE PARSING + +$type{'$$'}="sub"; +$contents{'$$'}="ddollar"; # START OF BLOCK PARSING + +$type{'\\\\'}="sub"; +$contents{'\\\\'}="bbackslash"; + +$type{"^"}="sub1"; +$contents{"^"}="superscript"; + +$type{"_"}="sub1"; +$contents{"_"}="subscript"; + +$type{"@"}="sub"; +$contents{"@"}="at"; + +$type{"\\over"}="sub"; +$contents{"\\over"}="over"; + + +$type{"\\choose"}="sub"; +$contents{"\\choose"}="choose"; + +$type{"\\noindent"}="sub"; +$contents{"\\noindent"}="noindent"; + + +$type{"\\left"}="sub"; +$contents{"\\left"}="left"; + +$type{"\\right"}="sub"; +$contents{"\\right"}="right"; + +$type{"\\underline"}="sub1"; +$contents{"\\underline"}="underline"; + +$type{"\\overline"}="sub1"; +$contents{"\\overline"}="overline"; + +$type{"\\bar"}="sub1"; +$contents{"\\bar"}="overline"; + +$type{"\\v"}="sub1"; +$contents{"\\v"}="putover_string;v"; + +$type{"\\widetilde"}="sub1"; +$contents{"\\widetilde"}="widetilde"; + +$type{"\\~"}="sub1"; +$contents{"\\~"}="putover_string;~"; + +$type{"\\tilde"}="sub1"; +$contents{"\\tilde"}="putover_string;~"; + +$type{"\\widehat"}="sub1"; +$contents{"\\widehat"}="widehat"; + +$type{"\\hat"}="sub1"; +$contents{"\\hat"}="putover_string;^"; + +$type{"\\^"}="sub1"; +$contents{"\\^"}="putover_string;^"; + +$type{'\\"'}="sub1"; +$contents{'\\"'}='putover_string;"'; + +$type{'\\dot'}="sub1"; +$contents{'\\dot'}='putover_string;.'; + +$type{"\\not"}="sub1"; +$contents{"\\not"}="not"; + +$type{"\\label"}="sub1"; +$contents{"\\label"}="putpar;(;)"; + +$type{"\\eqref"}="sub1"; +$contents{"\\eqref"}="putpar;(;)"; + +$type{"\\cite"}="sub1"; +$contents{"\\cite"}="putpar;[;]"; + +$type{"\\begin"}="sub1"; +$contents{"\\begin"}="begin"; + +$type{"\\end"}="sub1"; +$contents{"\\end"}="end"; + +for ('@',"_","\$","{","}","#","&","arccos","arcsin","arctan","arg","cos", + "cosh","cot","coth","csc","deg","det","dim","exp","gcd","hom", + "inf","ker","lg","lim","liminf","limsup","ln","log","max","min", + "mod","Pr","sec","sin","sinh","sup","tan","tanh", "%") { + $type{"\\$_"}="self"; +} + +for ("bibliography","myLabel","theoremstyle","theorembodyfont", + "bibliographystyle","hphantom","vphantom","phantom","hspace") { + $type{"\\$_"}="discard1"; +} + +for ("numberwithin","newtheorem","renewcommand","setcounter" + ) { + $type{"\\$_"}="discard2"; +} + +for ("equation","gather","align" + ) {$environment{"$_"}="ddollar,ddollar";} + +for ("matrix","CD","smallmatrix" + ) {$environment{"$_"}="matrix,endmatrix;1;c";} + +for ("document","split","enumerate" + ) {$environment_none{"$_"}++;} + +$environment{"Sb"}="subscript:matrix,endmatrix;1;l"; + +$environment{"Sp"}="superscript:matrix,endmatrix;1;l"; + +$environment{"eqnarray"}="ddollar:matrix,endmatrix;0;r;c;l:ddollar"; +$environment{"split"}="ddollar:matrix,endmatrix;0;r;l:ddollar"; +$environment{"multiline"}="ddollar:matrix,endmatrix;0;r;l:ddollar"; +$environment{"align"}="ddollar:matrix,endmatrix;0;r;l:ddollar"; +$environment{"aligned"}="matrix,endmatrix;0;r;l"; +$environment{"gather"}="ddollar:matrix,endmatrix;0;c:ddollar"; +$environment{"gathered"}="matrix,endmatrix;0;c"; +$environment{"array"}="arg2stack:matrix,endmatrixArg;1"; + +# $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c"; +$environment{"bmatrix"}="beg_lr;[;]:matrix,endmatrix;1;c"; +$environment{"vmatrix"}="beg_lr;|;|:matrix,endmatrix;1;c"; + +$type{"~"}="string"; +$contents{"~"}=" "; + +$type{"\\,"}="string"; +$contents{"\\,"}=" "; + +$type{"\\dots"}="string"; +$contents{"\\dots"}="..."; + +$type{"\\ldots"}="string"; +$contents{"\\ldots"}="..."; + +$type{"\\cdots"}="string"; +$contents{"\\cdots"}="⋯"; + +$type{"\\colon"}="string"; +$contents{"\\colon"}=": "; + +$type{"\\mid"}="string"; +$contents{"\\mid"}=" | "; + +$type{"\\smallsetminus"}="string"; +$contents{"\\smallsetminus"}=" ⧵ "; + +$type{"\\setminus"}="string"; +$contents{"\\setminus"}=" ⧹ "; + +$type{"\\backslash"}="string"; +$contents{"\\backslash"}="\\"; + +$type{"\\approx"}="string"; +$contents{"\\approx"}=" ≅ "; + +$type{"\\simeq"}="string"; +$contents{"\\simeq"}=" ≃ "; + +$type{"\\quad"}="string"; +$contents{"\\quad"}=" "; + +$type{"\\qquad"}="string"; +$contents{"\\qquad"}=" "; + +$type{"\\Delta"}="string"; +$contents{"\\Delta"}="△"; + +$type{"\\Pi"}="string"; +$contents{"\\Pi"}="π"; + +$type{"\\alpha"}="string"; +$contents{"\\alpha"}="α"; + +$type{"\\to"}="string"; +$contents{"\\to"}=" ──> "; + +$type{"\\from"}="string"; +$contents{"\\from"}=" <── "; + +$type{"\\wedge"}="string"; +$contents{"\\wedge"}="∧"; + +$type{"\\Lambda"}="string"; +$contents{"\\Lambda"}="∨"; + +$type{"\\ltimes"}="string"; +$contents{"\\ltimes"}="⋉"; + +$type{"\\lhd"}="string"; +$contents{"\\lhd"}=" ⊲ "; + +$type{"\\rhd"}="string"; +$contents{"\\rhd"}=" ⊳ "; + +$type{"\\cdot"}="string"; +$contents{"\\cdot"}=" · "; + +$type{"\\circ"}="string"; +$contents{"\\circ"}=" o "; + +$type{"\\bullet"}="string"; +$contents{"\\bullet"}="•"; + +$type{"\\infty"}="string"; +$contents{"\\infty"}="∞"; + +$type{"\\rtimes"}="string"; +$contents{"\\rtimes"}=" ⋊ "; + +$type{"\\times"}="string"; +$contents{"\\times"}=" × "; + +$type{"\\hookrightarrow"}="string"; +$contents{"\\hookrightarrow"}=" ↪ "; + +$type{"\\hookleftarrow"}="string"; +$contents{"\\hookleftarrow"}=" ↩ "; + +$type{"\\longleftarrow"}="string"; +$contents{"\\longleftarrow"}=" <──── "; + +$type{"\\longleftrightarrow"}="string"; +$contents{"\\longleftrightarrow"}=" <────> "; + +$type{"\\longrightarrow"}="string"; +$contents{"\\longrightarrow"}=" ────> "; + +$type{"\\rightarrow"}="string"; +$contents{"\\rightarrow"}=" ──> "; + +$type{"\\leftarrow"}="string"; +$contents{"\\leftarrow"}=" <── "; + +$type{"\\mapsto"}="string"; +$contents{"\\mapsto"}=" ├──> "; + +$type{"\\longmapsto"}="string"; +$contents{"\\longmapsto"}=" ├────> "; + +$type{"\\cap"}="string"; +$contents{"\\cap"}=" ∩ "; + +$type{"\\cup"}="string"; +$contents{"\\cup"}=" ∪ "; + +$type{"\\section"}="string"; +$contents{"\\section"}="Section "; + +$type{"\\subsection"}="string"; +$contents{"\\subsection"}="Subsection "; + +$type{"\|"}="string"; +$contents{"\|"}="||"; + +$type{'\;'}="string"; +$contents{'\;'}=" "; + +$type{'\noindent'}="string"; +$contents{'\noindent'}=""; + + +&define('\\define','\\def'); +&define('\\ge','\\geq'); +&define('\\le','\\leq'); +&define('\\ne','\\neq'); +&define('\\langle','<'); +&define('\\rangle','>'); +&define('\\subheading','\\par\\underline'); +&define('\\(','$'); +&define('\\)','$'); + +# Interestingly, since this script was written, LaTeX went +# the opposite direction: rather than the $$ syntax, folks +# are supposed to use \[ and \] +&define('\\[','$$'); +&define('\\]','$$'); + +&define('\\centerline#1','$$#1$$'); +&define('\\eqalign#1','\\aligned #1 \\endaligned'); +&define('\\cr','\\\\'); +&define('\\sb','_'); +&define('\\sp','^'); +&define('\\proclaim','\\noindent '); + +&defb("matrix","vmatrix","Vmatrix","smallmatrix","bmatrix","Sp","Sb","CD","align","aligned","split","multiline","gather","gathered"); + +if ($opt_TeX) { + &define('\pmatrix#1','\left(\begin{matrix}#1\end{matrix}\right)'); +} else { + $environment{"pmatrix"}="beg_lr;(;):matrix,endmatrix;1;c"; + &defb("pmatrix") unless $opt_TeX; +} + +## All the records should be specified before this point +{ + local(@a)=grep("record" eq $type{$_},keys %type); + for (@a) { + chop $contents{$_} if substr($contents{$_},length($contents{$_})-1,1) eq "\n"; + } +} + +for ("oplus","otimes","cup","wedge") { + $type{"\\big$_"}=$type{"\\$_"}; + $contents{"\\big$_"}=$contents{"\\$_"}; +} + + +@level=(0); +@chunks=(0); +@tokenByToken=(0); +@out=(); +$curlength=0; +$debug_flow=1; +$debug_record=2; +$debug_parsing=4; +$debug_length=8; +$debug_matrix=16; + +#$debug |= $debug_flow | $debug_record | $debug_parsing | $debug_length; +#$debug |= $debug_flow; +#$debug |= $debug_record; +#$debug |= $debug_parsing; +#$debug |= $debug_length; +#$debug |= $debug_matrix; + + +# ============================= +# Run the script by looping +# paragraph parsing until there +# is nothing left to parse. +# ============================= + + +$/ = $opt_by_par ? "\n\n" : ''; # whole paragraph mode +while (¶graph()) { } +&finishBuffer; + +__END__ + +# History: Jul 98: \choose added, fixed RE for \noindent, \eqalign and \cr. +# \proclaim and better \noindent added. +# Sep 98: last was used inside an if block, was leaking out. +# Jan 00: \sb \sp +# Feb 00: remove extraneous second EOF needed at end. + remove an empty line at end of output + New option -by_par to support per-paragraph processing + New option -TeX which support a different \pmatrix + New option -ragged to not insert whitespace to align right margin. + New option -noindent to not insert whitespace at beginning. + Ignore \\ and \cr if followed by \end{whatever}. + Ignore \noindent if not important. + Ignore whitespace paragraphs. +# Apr 00: Finishing a level 1 would not merge things into one chunk. +# May 00: Additional argument to finish() to distinguish finishing + things which cannot be broken between lines. +# Sep 00: Add support for new macro for strings with screen escapes sequences: + \LITERALnoLENGTH{escapeseq}. +# Oct 00: \LITERALnoLENGTH can have a chance to work in the baseline only; + in fact the previous version did not work even there... + If the added record is longer than line length, do not try to + break the line before it... diff --git a/test.js b/test.js new file mode 100644 index 00000000..b4c12d8e --- /dev/null +++ b/test.js @@ -0,0 +1,21 @@ +const lookup = {}; + +const arrays = [ + [0, 1, 2, 3, 4, 4, 4, 4], + [5, 6, 7, 8, 9, 10, 11, 11], + [2, 7, 10, 12], + [0, 7, 10, 14] +]; + +const reduced = arrays.map((array, index) => { + for(let i=array.length-1; i>=0; i--) { + let value = array[i]; + let knownIndex = (lookup[value] = lookup[value] ?? index); + if (knownIndex < index) { + array.splice(i,1); + } + } + return array; +}); + +console.log(reduced);