diff --git a/frontend/deps.edn b/frontend/deps.edn index 51d43a0f6..313e8db1a 100644 --- a/frontend/deps.edn +++ b/frontend/deps.edn @@ -11,7 +11,7 @@ danlentz/clj-uuid {:mvn/version "0.1.9"} frankiesardo/linked {:mvn/version "1.3.0"} - funcool/beicon {:mvn/version "2021.04.09-1"} + funcool/beicon {:mvn/version "2021.04.12-1"} funcool/cuerdas {:mvn/version "2020.03.26-3"} funcool/okulary {:mvn/version "2020.04.14-0"} funcool/potok {:mvn/version "3.2.0"} diff --git a/frontend/src/app/main/data/workspace/path/edition.cljs b/frontend/src/app/main/data/workspace/path/edition.cljs index 4f723b8fb..afc98af60 100644 --- a/frontend/src/app/main/data/workspace/path/edition.cljs +++ b/frontend/src/app/main/data/workspace/path/edition.cljs @@ -129,7 +129,8 @@ (rx/of (selection/select-node position shift?))) ;; This stream checks the consecutive mouse positions to do the draging - (->> (streams/position-stream points) + (->> points + (streams/move-points-stream start-position selected-points) (rx/take-until stopper) (rx/map #(move-selected-path-point start-position %))) (rx/of (apply-content-modifiers))) @@ -168,7 +169,7 @@ (streams/drag-stream (rx/concat - (->> (streams/position-stream points) + (->> (streams/move-handler-stream start-point handler points) (rx/take-until (->> stream (rx/filter ms/mouse-up?))) (rx/map (fn [{:keys [x y alt? shift?]}] diff --git a/frontend/src/app/main/data/workspace/path/streams.cljs b/frontend/src/app/main/data/workspace/path/streams.cljs index 2f5c27a85..9dfd011f4 100644 --- a/frontend/src/app/main/data/workspace/path/streams.cljs +++ b/frontend/src/app/main/data/workspace/path/streams.cljs @@ -10,13 +10,16 @@ (ns app.main.data.workspace.path.streams (:require [app.main.data.workspace.path.helpers :as helpers] + [app.main.data.workspace.path.state :as state] [app.common.geom.point :as gpt] [app.main.store :as st] [app.main.streams :as ms] [beicon.core :as rx] [potok.core :as ptk] [app.common.math :as mth] - [app.main.snap :as snap])) + [app.main.snap :as snap] + [okulary.core :as l] + [app.util.geom.path :as ugp])) (defonce drag-threshold 5) @@ -54,17 +57,55 @@ (let [k 50] (* (mth/floor (/ num k)) k))) -(defn position-stream - ([points] - (position-stream points #{})) +(defn move-points-stream + [start-point selected-points points] - ([points selected-points] - (let [zoom (get-in @st/state [:workspace-local :zoom] 1)] - (->> (snap/path-snap ms/mouse-position points selected-points zoom) - (rx/with-latest vector ms/mouse-position) - (rx/map (fn [[{[x] :x [y] :y} position]] - (cond-> position - (some? x) (assoc :x x) - (some? y) (assoc :y y)))) - (rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %)))) - (rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %)))))))) + (let [zoom (get-in @st/state [:workspace-local :zoom] 1) + ranges (snap/create-ranges selected-points points) + d-pos (/ snap/snap-accuracy zoom)] + (->> ms/mouse-position + (rx/map (fn [position] + (let [delta (gpt/subtract position start-point) + moved-points (->> selected-points (mapv #(gpt/add % delta)))] + (gpt/add + position + (snap/get-snap-delta moved-points ranges d-pos))))))) + ) + +(defn move-handler-stream + [start-point handler points] + + (let [zoom (get-in @st/state [:workspace-local :zoom] 1) + ranges (snap/create-ranges points) + d-pos (/ snap/snap-accuracy zoom)] + (->> ms/mouse-position + (rx/map (fn [position] + (let [delta (gpt/subtract position start-point) + handler-position (gpt/add handler delta)] + (gpt/add + position + (snap/get-snap-delta [handler-position] ranges d-pos)))))))) + +(defn position-stream + [points] + (let [zoom (get-in @st/state [:workspace-local :zoom] 1) + ranges (snap/create-ranges points) + d-pos (/ snap/snap-accuracy zoom) + get-content (fn [state] (get-in state (state/get-path state :content))) + + content-stream (-> (l/derived get-content st/state) + (rx/from-atom)) + ] + + (->> content-stream + (rx/map ugp/content->points) + (rx/subs #(prn "????" %))) + + + (->> ms/mouse-position + (rx/tap #(prn "pos" %)) + (rx/map #(let [snap (snap/get-snap-delta [%] ranges d-pos)] + (prn ">>>" snap) + (gpt/add % snap))) + (rx/with-latest merge (->> ms/mouse-position-shift (rx/map #(hash-map :shift? %)))) + (rx/with-latest merge (->> ms/mouse-position-alt (rx/map #(hash-map :alt? %))))))) diff --git a/frontend/src/app/main/snap.cljs b/frontend/src/app/main/snap.cljs index 36570576e..3831fb4f6 100644 --- a/frontend/src/app/main/snap.cljs +++ b/frontend/src/app/main/snap.cljs @@ -241,7 +241,118 @@ (rx/reduce gpt/min) (rx/map #(or % (gpt/point 0 0)))))) -(defn path-snap [position-stream points selected-points zoom] + +;;; PATH SNAP + +(defn create-ranges + ([points] + (create-ranges points #{})) + + ([points selected-points] + (let [selected-points (or selected-points #{}) + + into-tree + (fn [coord] + (fn [tree point] + (rt/insert tree (get point coord) point))) + + make-ranges + (fn [coord] + (->> points + (filter (comp not selected-points)) + (reduce (into-tree coord) (rt/make-tree))))] + + {:x (make-ranges :x) + :y (make-ranges :y)}))) + +(defn query-delta-point [ranges point precision] + (let [query-coord + (fn [coord] + (let [pval (get point coord)] + #_(prn "..." (rt/range-query (get ranges coord) (- pval precision) (+ pval precision))) + + (->> (rt/range-query (get ranges coord) (- pval precision) (+ pval precision)) + + ;; We save the distance to the point and add the matching point to the points + (mapv (fn [[value points]] + #_(prn "!! " value [(mth/abs (- value pval)) + (->> points (mapv #(vector point %)))]) + [(mth/abs (- value pval)) + (->> points (mapv #(vector point %)))])))))] + + {:x (query-coord :x) + :y (query-coord :y)})) + +(defn merge-matches [matches other] + (let [merge-coord + (fn [matches other] + (prn "merge-coord" matches other) + (into {} + (map (fn [key] [key (d/concat [] (get matches key) (get other key))])) + (set/union (keys matches) (keys other))))] + + (-> matches + (update :x merge-matches (:x other)) + (update :y merge-matches (:y other))))) + +(defn min-match + [default matches] + (let [get-min + (fn [[cur-val :as current] [other-val :as other]] + (if (< cur-val other-val) + current + other)) + + min-match-coord + (fn [matches] + (if (and (seq matches) (not (empty? matches))) + (->> matches (reduce get-min)) + default))] + + (-> matches + (update :x min-match-coord) + (update :y min-match-coord)))) + +(defn get-snap-delta-match + [points ranges accuracy] + (assert vector? points) + + (->> points + (mapv #(query-delta-point ranges % accuracy)) + (reduce merge-matches) + (min-match [0 nil]))) + +(defn get-snap-delta + [points ranges accuracy] + (-> (get-snap-delta-match points ranges accuracy) + (update :x first) + (update :y first) + (gpt/point))) + +#_(defn path-snap-points-delta [points-stream selected-points points zoom] + + (let [ranges (create-ranges points selected-points) + d-pos (/ snap-accuracy zoom)] + + (->> points-stream + (rx/map (fn [points] + (get-snap-delta points ranges d-pos))))) + + + ) + +#_(defn path-snap [position-stream points selected-points zoom] + (let [ranges (create-ranges points selected-points) + d-pos (/ snap-accuracy zoom)] + + (->> position-stream + (rx/map (fn [position] + (gpt/add + position + (get-snap-delta position ranges d-pos))))))) + + +#_(defn path-snap [position-stream points selected-points zoom] (let [selected-points (or selected-points #{}) into-tree (fn [coord] (fn [tree point] diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index 66fcdf63f..4299e681b 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -199,7 +199,7 @@ (fn [position] (reset! hover-point (gshp/path-closest-point shape position)))) - (hooks/use-stream + #_(hooks/use-stream (mf/use-memo (mf/deps base-content selected-points zoom) #(snap/path-snap ms/mouse-position points selected-points zoom))