~raph/interp-toy

045a92e61ac06c1545ed3b085a83671e29f4e505 — Raph Levien 2 years ago 5cb0e35
Very basic interpolation working

But there are lots of flaws. Biggest is that it's very hard to keep
points sparse, when you move the sliders it almost always wants to
add a new sample. Also, there may be numerical stability issues.
5 files changed, 294 insertions(+), 9 deletions(-)

M Cargo.lock
M Cargo.toml
M src/app_state.rs
M src/interp_pane.rs
M src/main.rs
M Cargo.lock => Cargo.lock +194 -0
@@ 1,6 1,25 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "alga"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "approx"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "arrayvec"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 84,6 103,14 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "cocoa"
version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 234,6 261,14 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "generic-array"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "heck"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 246,6 281,8 @@ name = "interp-toy"
version = "0.1.0"
dependencies = [
 "druid 0.3.0 (git+https://github.com/xi-editor/druid?rev=3df5e4da7475706e380973230913828149b5b91e)",
 "nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "rbf-interp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]


@@ 275,6 312,11 @@ version = "0.2.60"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "libm"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 291,11 333,34 @@ dependencies = [
]

[[package]]
name = "matrixmultiply"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "memchr"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "nalgebra"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "matrixmultiply 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 343,6 408,15 @@ dependencies = [
]

[[package]]
name = "num-complex"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "num-integer"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 478,6 552,33 @@ dependencies = [
]

[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 491,6 592,75 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rawpointer"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "rbf-interp"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 550,6 720,11 @@ dependencies = [
]

[[package]]
name = "typenum"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "unicode-segmentation"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"


@@ 675,6 850,8 @@ dependencies = [
]

[metadata]
"checksum alga 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d708cb68c7106ed1844de68f50f0157a7788c2909a6926fad5a87546ef6a4ff8"
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b"
"checksum backtrace 0.3.33 (registry+https://github.com/rust-lang/crates.io-index)" = "88fb679bc9af8fa639198790a77f52d345fe13656c08b43afa9424c206b731c6"


@@ 687,6 864,7 @@ dependencies = [
"checksum cairo-sys-rs 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "90a1ec04603a78c111886a385edcec396dbfbc57ea26b9e74aeea6a1fe55dcca"
"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf79daa4e11e5def06e55306aa3601b87de6b5149671529318da048f67cdd77b"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"


@@ 703,19 881,24 @@ dependencies = [
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum js-sys 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "da3ea71161651a4cd97d999b2da139109c537b15ab33abc8ae4ead38deac8a03"
"checksum kurbo 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0caeb26248a62abf92dea93aad4f8244f54668e2f1060ed9cd9fd1d5545723"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
"checksum libm 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
"checksum matrixmultiply 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfed72d871629daa12b25af198f110e8095d7650f5f4c61c5bac28364604f9b"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum nalgebra 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e12856109b5cb8e2934b5e45e4624839416e1c6c1f7d286711a7a66b79db29d"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
"checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1"
"checksum num-complex 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656"
"checksum num-complex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e"
"checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"


@@ 730,8 913,18 @@ dependencies = [
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rawpointer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019"
"checksum rbf-interp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76ce54ac73ddb1145d1788a831006b8108acf1f0f99265ea8b23a06f21c9c5a4"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"


@@ 740,6 933,7 @@ dependencies = [
"checksum syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)" = "eadc09306ca51a40555dd6fc2b415538e9e18bc9f870e47b1a524a79fe2dcf5e"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"

M Cargo.toml => Cargo.toml +2 -0
@@ 8,3 8,5 @@ edition = "2018"

[dependencies]
druid = {git = "https://github.com/xi-editor/druid", rev = "3df5e4da7475706e380973230913828149b5b91e" }
rbf-interp = "0.1.1"
nalgebra = "0.18"

M src/app_state.rs => src/app_state.rs +74 -1
@@ 1,15 1,22 @@
use std::sync::Arc;

use nalgebra::DVector;

use rbf_interp::{Basis, Scatter};

use druid::kurbo::Point;

use druid::Data;

#[derive(Clone, Default)]
pub struct AppState {
    // TODO: increasingly aware that we're hardcoding two parameters,
    // this needs to be a variable number, but we're trying to keep
    // complexity down for now.
    pub width: f64,
    pub weight: f64,

    pub pts: Arc<Vec<Point>>,
    pub pts: Arc<Vec<InterpPt>>,
}

impl Data for AppState {


@@ 18,6 25,18 @@ impl Data for AppState {
    }
}

#[derive(Clone)]
pub struct InterpPt {
    samples: Vec<InterpSample>,
}

#[derive(Clone)]
pub struct InterpSample {
    pub pt: Point,
    pub width: f64,
    pub weight: f64,
}

// All this should be produced by a derive macro.
pub mod lenses {
    // Discussion: if the inner type were listed first, then


@@ 49,3 68,57 @@ pub mod lenses {
        }
    }
}

impl InterpPt {
    pub fn new(pt: Point, width: f64, weight: f64) -> InterpPt {
        let sample = InterpSample { pt, width, weight };
        InterpPt {
            samples: vec![sample],
        }
    }

    pub fn eval(&self, width: f64, weight: f64) -> Point {
        let len = self.samples.len();
        if len == 1 {
            // TODO: I think rbf-interp should handle this case, but since
            // it tries to invert a non-invertible matrix, we work around
            // it here.
            return self.samples[0].pt;
        }
        if len == 2 {
            // TODO: RBF-interp should deal with this too.
            let dot = width * (self.samples[1].width - self.samples[0].width)
                + weight * (self.samples[1].weight - self.samples[0].weight);
            let scale = (self.samples[1].width - self.samples[0].width).powi(2) +
                (self.samples[1].weight - self.samples[0].weight).powi(2);
            let t = dot / scale;
            return self.samples[0].pt.lerp(self.samples[1].pt, t);
        }
        let mut centers = Vec::with_capacity(len);
        let mut vals = Vec::with_capacity(len);
        for sample in &self.samples {
            centers.push(DVector::from_vec(vec![sample.width, sample.weight]));
            vals.push(DVector::from_vec(vec![sample.pt.x, sample.pt.y]));
        }
        let scatter = Scatter::create(centers, vals, Basis::PolyHarmonic(2), 2);
        let params = DVector::from_vec(vec![width, weight]);
        let interp = scatter.eval(params);
        Point::new(interp[0], interp[1])
    }

    /// Update a point, either by adding a new sample or updating an existing
    /// sample that's "close" to the specific params.
    pub fn update(&mut self, pt: Point, width: f64, weight: f64) {
        // Try to find an existing sample to update.
        for sample in &mut self.samples {
            if (sample.width - width).powi(2) + (sample.weight - weight).powi(2) < 0.001 {
                sample.width = width;
                sample.weight = weight;
                sample.pt = pt;
                return;
            }
        }
        let sample = InterpSample { pt, width, weight };
        self.samples.push(sample);
    }
}

M src/interp_pane.rs => src/interp_pane.rs +23 -7
@@ 9,6 9,8 @@ use druid::{

use crate::AppState;

use crate::InterpPt;

#[derive(Default)]
pub struct InterpPane {
    drag_ix: Option<usize>,


@@ 22,14 24,17 @@ impl Widget<AppState> for InterpPane {
        data: &AppState,
        _env: &Env,
    ) {
        let width = data.width;
        let weight = data.weight;
        for pt in data.pts.deref() {
            let circle = Circle::new(*pt, 5.0);
            let interp = pt.eval(width, weight);
            let circle = Circle::new(interp, 5.0);
            let brush = paint_ctx.render_ctx.solid_brush(Color::WHITE);
            paint_ctx.render_ctx.fill(circle, &brush, FillRule::NonZero);
        }
    }

     fn layout(
    fn layout(
        &mut self,
        _layout_ctx: &mut LayoutCtx,
        bc: &BoxConstraints,


@@ 39,26 44,30 @@ impl Widget<AppState> for InterpPane {
        bc.constrain((100.0, 100.0))
    }

     fn event(
    fn event(
        &mut self,
        event: &Event,
        ctx: &mut EventCtx,
        data: &mut AppState,
        _env: &Env,
    ) -> Option<Action> {
        let width = data.width;
        let weight = data.weight;
        match event {
            Event::MouseDown(e) => {
                println!("mouse down {:?}!", e);
                let pos = e.pos;
                let mut pts = data.pts.deref().clone();
                for (i, pt) in pts.iter().enumerate() {
                    if pt.distance(pos) < 5.0 {
                    let interp = pt.eval(width, weight);
                    if interp.distance(pos) < 5.0 {
                        self.drag_ix = Some(i);
                        return None;
                    }
                }
                self.drag_ix = Some(pts.len());
                pts.push(pos);
                let pt = InterpPt::new(pos, width, weight);
                pts.push(pt);
                data.pts = Arc::new(pts);
                ctx.invalidate();
            }


@@ 68,7 77,7 @@ impl Widget<AppState> for InterpPane {
            Event::MouseMoved(e) => {
                if let Some(drag_ix) = self.drag_ix {
                    let mut pts = data.pts.deref().clone();
                    pts[drag_ix] = e.pos;
                    pts[drag_ix].update(e.pos, data.width, data.weight);
                    data.pts = Arc::new(pts);
                    ctx.invalidate();
                }


@@ 78,5 87,12 @@ impl Widget<AppState> for InterpPane {
        None
    }

     fn update(&mut self, _ctx: &mut UpdateCtx, _old_data: Option<&AppState>, _data: &AppState, _env: &Env) {}
    fn update(
        &mut self,
        _ctx: &mut UpdateCtx,
        _old_data: Option<&AppState>,
        _data: &AppState,
        _env: &Env,
    ) {
    }
}

M src/main.rs => src/main.rs +1 -1
@@ 5,7 5,7 @@ use druid::{LensWrap, UiMain, UiState};
mod app_state;
mod interp_pane;

use app_state::{AppState, lenses};
use app_state::{lenses, AppState, InterpPt};
use interp_pane::InterpPane;

fn main() {