From 0f68210a16cd3aeed1acfe02654709bff5646d6b Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 12 Jan 2022 20:25:32 +0100 Subject: [PATCH] WIP --- backend/dev/java/app/Experiments.java | 133 ++++++++++++++++++++++ common/src/app/common/geom/impl/matrix.js | 65 +++++++++++ common/src/app/common/namedtuple.cljc | 111 ++++++++++++++++++ frontend/dev/user.clj | 12 ++ frontend/src/app/util/namedtuple.cljc | 107 +++++++++++++++++ 5 files changed, 428 insertions(+) create mode 100644 backend/dev/java/app/Experiments.java create mode 100644 common/src/app/common/geom/impl/matrix.js create mode 100644 common/src/app/common/namedtuple.cljc create mode 100644 frontend/dev/user.clj create mode 100644 frontend/src/app/util/namedtuple.cljc diff --git a/backend/dev/java/app/Experiments.java b/backend/dev/java/app/Experiments.java new file mode 100644 index 000000000..24ed30d8e --- /dev/null +++ b/backend/dev/java/app/Experiments.java @@ -0,0 +1,133 @@ +package app; + +import clojure.lang.Seqable; +import clojure.lang.RT; +import clojure.lang.ISeq; +import clojure.lang.ILookup; +import clojure.lang.Keyword; + + + // static public double[] multiply(final double[] m1, final double m2[]) { + // var result = new double[6]; + // result[0] = (m1[0] * m2[0]) + (m1[2] * m2[1]); + // result[1] = (m1[1] * m2[0]) + (m1[3] * m2[1]); + // result[2] = (m1[0] * m2[2]) + (m1[2] * m2[3]); + // result[3] = (m1[1] * m2[2]) + (m1[3] * m2[3]);o + + // result[4] = (m1[0] * m2[4]) + (m1[2] * m2[5]) + m1[4]; + // result[5] = (m1[1] * m2[4]) + (m1[3] * m2[5]) + m1[5]; + // return result; + // } + + +public class Experiments { + static public class Matrix implements Seqable, ILookup { + public final double[] buff; + + public Matrix(double a, double b, double c, double d, double e, double f) { + buff = new double[6]; + buff[0] = a; + buff[1] = b; + buff[2] = c; + buff[3] = d; + buff[4] = e; + buff[5] = f; + } + + public Matrix(final double [] otherBuffer) { + buff = otherBuffer; + } + + public ISeq seq() { + return RT.seq(this.buff); + } + + public Double valAt(final Object key) { + var name = ((Keyword) key).getName(); + switch(name) { + case "a": return this.buff[0]; + case "b": return this.buff[1]; + case "c": return this.buff[2]; + case "d": return this.buff[3]; + case "e": return this.buff[4]; + default: return this.buff[5]; + } + } + + public Double valAt(final Object key, Object notFound) { + throw new IllegalArgumentException("not supported"); + } + } + + static public Matrix create(double a, double b, double c, double d, double e, double f) { + var buff = new double[6]; + buff[0] = a; + buff[1] = b; + buff[2] = c; + buff[3] = d; + buff[4] = e; + buff[5] = f; + return new Matrix(buff); + } + + static public Matrix multiply(final Matrix mt1, final Matrix mt2) { + var result = new double[6]; + var m1 = mt1.buff; + var m2 = mt1.buff; + + result[0] = (m1[0] * m2[0]) + (m1[2] * m2[1]); + result[1] = (m1[1] * m2[0]) + (m1[3] * m2[1]); + result[2] = (m1[0] * m2[2]) + (m1[2] * m2[3]); + result[3] = (m1[1] * m2[2]) + (m1[3] * m2[3]); + result[4] = (m1[0] * m2[4]) + (m1[2] * m2[5]) + m1[4]; + result[5] = (m1[1] * m2[4]) + (m1[3] * m2[5]) + m1[5]; + return new Matrix(result); + } + + static private void multiplyMutating(final double[] m1, final double[] m2) { + + var m1a = m1[0]; + var m1b = m1[1]; + var m1c = m1[2]; + var m1d = m1[3]; + var m1e = m1[4]; + var m1f = m1[5]; + + double[] result = m1; + result[0] = (m1a * m2[0]) + (m1c * m2[1]); + result[1] = (m1b * m2[0]) + (m1d * m2[1]); + result[2] = (m1a * m2[2]) + (m1c * m2[3]); + result[3] = (m1b * m2[2]) + (m1d * m2[3]); + result[4] = (m1a * m2[4]) + (m1c * m2[5]) + m1e; + result[5] = (m1b * m2[4]) + (m1d * m2[5]) + m1f; + } + + static public Matrix multiplyBulk(final Matrix m1) { + return m1; + } + + static public Matrix multiplyBulk(final Matrix m1, final Matrix m2) { + return multiply(m1, m2); + } + + static public Matrix multiplyBulk(final Matrix m1, final Matrix m2, final Matrix m3) { + var result = multiply(m1, m2); + multiplyMutating(result.buff, m3.buff); + return result; + } + + static public Matrix multiplyBulk(final Matrix m1, final Matrix m2, final Matrix m3, final Matrix m4) { + var result = multiply(m1, m2); + multiplyMutating(result.buff, m3.buff); + multiplyMutating(result.buff, m4.buff); + return result; + }; + + static public Matrix multiplyBulk(final Matrix m1, final Matrix m2, final Matrix m3, final Matrix m4, final Matrix m5) { + var result = multiply(m1, m2); + multiplyMutating(result.buff, m3.buff); + multiplyMutating(result.buff, m4.buff); + multiplyMutating(result.buff, m5.buff); + return result; + } +} diff --git a/common/src/app/common/geom/impl/matrix.js b/common/src/app/common/geom/impl/matrix.js new file mode 100644 index 000000000..2e437a2b0 --- /dev/null +++ b/common/src/app/common/geom/impl/matrix.js @@ -0,0 +1,65 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) UXBOX Labs SL + */ +"use strict"; + +goog.require("cljs.core"); +goog.provide("app.common.geom.impl.matrix"); + +goog.scope(function() { + const self = app.common.geom.impl.matrix; + + self.create = function(a, b, c, d, e, f) { + const matrix = new Float64Array(6); + matrix[0] = a; + matrix[1] = b; + matrix[2] = c; + matrix[3] = d; + matrix[4] = e; + matrix[5] = f; + + return matrix; + } + + + // result[0] = (m1[0] * m2[0]) + (m1[2] * m2[1]); + // result[1] = (m1[1] * m2[0]) + (m1[3] * m2[1]); + // result[2] = (m1[0] * m2[2]) + (m1[2] * m2[3]); + // result[3] = (m1[1] * m2[2]) + (m1[3] * m2[3]); + // result[4] = (m1[0] * m2[4]) + (m1[2] * m2[5]) + m1[4]; + // result[5] = (m1[1] * m2[4]) + (m1[3] * m2[5]) + m1[5]; + + + self.multiply = function(m1, m2) { + // var result = new Float64Array(6); + + // var m1a = m1[0]; + // var m1b = m1[1]; + // var m1c = m1[2]; + // var m1d = m1[3]; + // var m1e = m1[4]; + // var m1f = m1[5]; + + // var m2a = m2[0]; + // var m2b = m2[1]; + // var m2c = m2[2]; + // var m2d = m2[3]; + // var m2e = m2[4]; + // var m2f = m2[5]; + + // result[0] = (m1a * m2a) + (m1c * m2b); + // result[1] = (m1b * m2a) + (m1d * m2b); + // result[2] = (m1a * m2c) + (m1c * m2d); + // result[3] = (m1b * m2c) + (m1d * m2d); + // result[4] = (m1a * m2e) + (m1c * m2f) + m1e; + // result[5] = (m1b * m2e) + (m1d * m2f) + m1f; + + // return result; + return m1; + } + +}); diff --git a/common/src/app/common/namedtuple.cljc b/common/src/app/common/namedtuple.cljc new file mode 100644 index 000000000..b34958bdd --- /dev/null +++ b/common/src/app/common/namedtuple.cljc @@ -0,0 +1,111 @@ +(ns app.common.namedtuple + "General purpose small immutable colections backed by native arrays." + (:require + #?(:cljs [cljs.core :as c] + :clj [clojure.core :as c]) + [clojure.string :as str])) + +(defmacro deftuple + [nsym fields] + (let [sbuff (symbol "buff") + sfields (symbol "fields") + smeta (symbol "meta") + params (into [] (comp (map name) + (map gensym)) + fields) + tmpbuf (gensym "buff") + f1name (symbol (str "make-" (str/lower-case (name nsym))))] + `(do + (deftype ~nsym [~sbuff ~smeta] + ;; Object + ;; (toString [_#] (pr-str ~sbuff)) + ;; (equiv [_# other#] false) + + c/ICloneable + (~'-clone [_#] (new ~nsym (aclone ~sbuff) ~smeta)) + + c/IWithMeta + (~'-with-meta [this# new-meta#] + (if (identical? new-meta# ~smeta) + this# + (new ~nsym ~sbuff new-meta#))) + + c/IMeta + (~'-meta [_#] ~smeta) + + c/ICollection + (~'-conj [_# entry#] + (conj (vec ~sbuff) entry#)) + + c/IEmptyableCollection + (~'-empty [_#] + (let [len# (alength ~sbuff) + buff# (make-array len#)] + (dotimes [i# len#] + (aset buff# i# nil)) + (new ~nsym buff# ~smeta))) + + c/ISeqable + (~'-seq [_#] (seq ~sbuff)) + + c/IAssociative + (~'-assoc [this# k# v#] + (let [index# (case k# + ~@(mapcat (fn [i n] [i n]) + fields + (range (count fields))) + (throw (ex-info "invalid key" {}))) + buff# (aclone ~sbuff)] + (aset buff# index# v#) + (new ~nsym buff# ~smeta))) + + (~'-contains-key? [_# k#] + (case k# + ~@(mapcat (fn [n] [n true]) fields) + false)) + + c/ICounted + (~'-count [_#] + (alength ~sbuff)) + + c/ILookup + (~'-lookup [_# k#] + (case k# + ~@(mapcat (fn [n i] [n `(aget ~sbuff ~i)]) + fields + (range (count fields))) + nil)) + + (~'-lookup [this# k# not-found#] + (or (case k# + ~@(mapcat (fn [n i] [n `(aget ~sbuff ~i)]) + fields + (range (count fields))) + nil) + not-found#)) + + c/IPrintWithWriter + (~'-pr-writer [this# writer# _#] + (c/-write writer# (str "#penpot/namedtuple" + (pr-str (into {} [~@(map (fn [k i] + [k `(aget ~sbuff ~i)]) + fields + (range (count fields)))]))))) + + + c/IFn + (~'-invoke [this# k#] + (c/-lookup this# k#)) + + (~'-invoke [this# k# not-found#] + (c/-lookup this# k# not-found#))) + + (defn ~f1name ~params + (let [~tmpbuf (js/Float64Array. 6)] + ~@(map-indexed (fn [i x] `(aset ~tmpbuf ~i ~x)) params) + ;; (js/console.log buff#) + (new ~nsym ~tmpbuf nil))) + + ))) + + diff --git a/frontend/dev/user.clj b/frontend/dev/user.clj new file mode 100644 index 000000000..f2a210157 --- /dev/null +++ b/frontend/dev/user.clj @@ -0,0 +1,12 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) UXBOX Labs SL + +(ns user + (:require + [clojure.pprint :refer [pprint print-table]] + [clojure.repl :refer :all] + [clojure.tools.namespace.repl :as repl] + [clojure.walk :refer [macroexpand-all]])) diff --git a/frontend/src/app/util/namedtuple.cljc b/frontend/src/app/util/namedtuple.cljc new file mode 100644 index 000000000..f0615937a --- /dev/null +++ b/frontend/src/app/util/namedtuple.cljc @@ -0,0 +1,107 @@ +(ns app.util.namedtuple + "General purpose small immutable colections backed by native arrays." + (:require + [cljs.core :as c] + [clojure.string :as str])) + +(defmacro deftuple + [nsym fields] + (let [sbuff (symbol "buff") + sfields (symbol "fields") + smeta (symbol "meta") + params (into [] (comp (map name) + (map gensym)) + fields) + f1name (symbol (str "make-" (str/lower-case (name nsym))))] + `(do + (deftype ~nsym [~sbuff ~smeta] + ;; Object + ;; (toString [_#] (pr-str ~sbuff)) + ;; (equiv [_# other#] false) + + c/ICloneable + (~'-clone [_#] (new ~nsym (aclone ~sbuff) ~smeta)) + + c/IWithMeta + (~'-with-meta [this# new-meta#] + (if (identical? new-meta# ~smeta) + this# + (new ~nsym ~sbuff new-meta#))) + + c/IMeta + (~'-meta [_#] ~smeta) + + c/ICollection + (~'-conj [_# entry#] + (conj (vec ~sbuff) entry#)) + + c/IEmptyableCollection + (~'-empty [_#] + (let [len# (alength ~sbuff) + buff# (make-array len#)] + (dotimes [i# len#] + (aset buff# i# nil)) + (new ~nsym buff# ~smeta))) + + c/ISeqable + (~'-seq [_#] (seq ~sbuff)) + + c/IAssociative + (~'-assoc [this# k# v#] + (let [index# (case k# + ~@(mapcat (fn [i n] [i n]) + fields + (range (count fields))) + (throw (ex-info "invalid key" {}))) + buff# (aclone ~sbuff)] + (aset buff# index# v#) + (new ~nsym buff# ~smeta))) + + (~'-contains-key? [_# k#] + (case k# + ~@(mapcat (fn [n] [n true]) fields) + false)) + + c/ICounted + (~'-count [_#] + (alength ~sbuff)) + + c/ILookup + (~'-lookup [_# k#] + (case k# + ~@(mapcat (fn [n i] [n `(aget ~sbuff ~i)]) + fields + (range (count fields))) + nil)) + + (~'-lookup [this# k# not-found#] + (or (case k# + ~@(mapcat (fn [n i] [n `(aget ~sbuff ~i)]) + fields + (range (count fields))) + nil) + not-found#)) + + c/IPrintWithWriter + (~'-pr-writer [this# writer# _#] + (c/-write writer# (str "#penpot/namedtuple" + (pr-str (into {} [~@(map (fn [k i] + [k `(aget ~sbuff ~i)]) + fields + (range (count fields)))]))))) + + + c/IFn + (~'-invoke [this# k#] + (c/-lookup this# k#)) + + (~'-invoke [this# k# not-found#] + (c/-lookup this# k# not-found#))) + + (defn ~f1name ~params + (let [buff# (c/array ~@params)] + ;; (js/console.log buff#) + (new ~nsym buff# nil))) + + ))) +