Integrate engine into application prototype #15

Merged
glen merged 24 commits from engine-integration into main 2024-11-12 00:46:16 +00:00
5 changed files with 49 additions and 13 deletions
Showing only changes of commit e0880d2ad2 - Show all commits

View File

@ -26,6 +26,7 @@ console_error_panic_hook = { version = "0.1.7", optional = true }
version = "0.3.69" version = "0.3.69"
features = [ features = [
'HtmlCanvasElement', 'HtmlCanvasElement',
'HtmlInputElement',
'Performance', 'Performance',
'WebGl2RenderingContext', 'WebGl2RenderingContext',
'WebGlBuffer', 'WebGlBuffer',

View File

@ -93,7 +93,7 @@ details[open]:has(li) .elt-switch::after {
display: flex; display: flex;
} }
.elt-rep > div, .cst-rep { .elt-rep > div {
padding: 2px 0px 0px 0px; padding: 2px 0px 0px 0px;
font-size: 10pt; font-size: 10pt;
text-align: center; text-align: center;
@ -104,10 +104,17 @@ details[open]:has(li) .elt-switch::after {
font-style: italic; font-style: italic;
} }
.cst > input { .cst > input[type=checkbox] {
margin: 0px 8px 0px 0px; margin: 0px 8px 0px 0px;
} }
.cst > input[type=number] {
color: #fcfcfc;
background-color: inherit;
border: 1px solid #555;
border-radius: 2px;
}
/* display */ /* display */
canvas { canvas {

View File

@ -214,11 +214,14 @@ pub fn AddRemove() -> View {
(arg_vec[0].clone(), arg_vec[1].clone()) (arg_vec[0].clone(), arg_vec[1].clone())
} }
); );
let rep = create_signal(0.0);
let active = create_signal(true); let active = create_signal(true);
state.assembly.insert_constraint(Constraint { state.assembly.insert_constraint(Constraint {
args: args, args: args,
rep: 0.0, rep: rep,
active: active rep_text: create_signal(String::new()),
rep_valid: create_signal(false),
active: active,
}); });
state.assembly.realize(); state.assembly.realize();
state.selection.update(|sel| sel.clear()); state.selection.update(|sel| sel.clear());
@ -233,13 +236,19 @@ pub fn AddRemove() -> View {
&JsValue::from(cst.args.0), &JsValue::from(cst.args.0),
&JsValue::from(cst.args.1), &JsValue::from(cst.args.1),
&JsValue::from(":"), &JsValue::from(":"),
&JsValue::from(cst.rep) &JsValue::from(cst.rep.get_untracked())
); );
} }
}); });
// make constraint activation trigger a realization update // update the realization when the constraint activated, or
// edited while active
create_effect(move || { create_effect(move || {
rep.track();
console::log_2(
&JsValue::from("Constraint rep updated to"),
&JsValue::from(rep.get_untracked())
);
if active.get() { if active.get() {
state.assembly.realize(); state.assembly.realize();
} }

View File

@ -22,7 +22,9 @@ pub struct Element {
#[derive(Clone)] #[derive(Clone)]
pub struct Constraint { pub struct Constraint {
pub args: (usize, usize), pub args: (usize, usize),
glen marked this conversation as resolved Outdated
Outdated
Review
  • Name choice? These are the two elements constrained by the constraint? We should prefer an entire word or short phrase that makes it clear. constrains would work for me, as would appliesTo. Totally open to other choices.
  • How are constraints that only constrain one element, such as 'the radius of this sphere is 1', represented? This seems to assume that there will be two elements constrained. And as food for thought, we will surely ultimately have user-facing constraints that involve three (maybe more) elements, e.g. 'these three points make an angle of τ/6 radians'. But maybe all such things will be implemented by multiple internal 2-element constraints. Not sure that there is anything to do on that point at the moment, but just wanted to raise the thought.
  • I assume the two usizes are some sort of references to elements. If a primitive type is being used with semantic baggage, typedef it or something like that so that you can write e.g.,

pub constrains: (ElementHandle, ElementHandle)

Again, I am open to other options for the name to use; "ElementRef" would be fine, or you may have another idea. A big part of why to do this is to make development easier should it become convenient to use a different primitive type to encode a reference to an element.

* Name choice? These are the two elements constrained by the constraint? We should prefer an entire word or short phrase that makes it clear. `constrains` would work for me, as would `appliesTo`. Totally open to other choices. * How are constraints that only constrain one element, such as 'the radius of this sphere is 1', represented? This seems to assume that there will be two elements constrained. And as food for thought, we will surely ultimately have user-facing constraints that involve three (maybe more) elements, e.g. 'these three points make an angle of τ/6 radians'. But maybe all such things will be implemented by multiple internal 2-element constraints. Not sure that there is anything to do on that point at the moment, but just wanted to raise the thought. * I assume the two `usize`s are some sort of references to elements. If a primitive type is being used with semantic baggage, typedef it or something like that so that you can write e.g., `pub constrains: (ElementHandle, ElementHandle)` Again, I am open to other options for the name to use; "ElementRef" would be fine, or you may have another idea. A big part of why to do this is to make development easier should it become convenient to use a different primitive type to encode a reference to an element.

Name choice? These are the two elements constrained by the constraint? We should prefer an entire word or short phrase that makes it clear. constrains would work for me, as would appliesTo. Totally open to other choices.

I've switched to subjects (in commit ed1890b), as in the phrase "[...] subject to the constraint that [...]." Is that a fitting name? I like to name non-boolean variables with nouns, rather than prepositional verbs like "applies to."

> Name choice? These are the two elements constrained by the constraint? We should prefer an entire word or short phrase that makes it clear. constrains would work for me, as would appliesTo. Totally open to other choices. I've switched to `subjects` (in commit ed1890b), as in the phrase "[...] subject to the constraint that [...]." Is that a fitting name? I like to name non-boolean variables with nouns, rather than prepositional verbs like "applies to."

This seems to assume that there will be two elements constrained.

Right now, there's only one kind of element (a sphere) and one kind of constraint (fixing the generalized angle between two spheres), so the Element and Constraint structures are written pretty narrowly. As we extend dyna3 to more general problems, I'm planning to generalize Element and Constraint as needed—maybe by turning each of them into a trait implemented by a bunch of different structures.

> This seems to assume that there will be two elements constrained. Right now, there's only one kind of element (a sphere) and one kind of constraint (fixing the generalized angle between two spheres), so the `Element` and `Constraint` structures are written pretty narrowly. As we extend dyna3 to more general problems, I'm planning to generalize `Element` and `Constraint` as needed—maybe by turning each of them into a trait implemented by a bunch of different structures.

I assume the two usizes are some sort of references to elements. If a primitive type is being used with semantic baggage, typedef it or something like that so that you can write e.g.,

pub constrains: (ElementHandle, ElementHandle)

Done as soon as I update the PR (in commit ced001b). I've chosen ElementKey and ConstraintKey, since the Rust collections I've seen tend to use the language of keys and values.

> I assume the two `usize`s are some sort of references to elements. If a primitive type is being used with semantic baggage, typedef it or something like that so that you can write e.g., > > `pub constrains: (ElementHandle, ElementHandle)` Done as soon as I update the PR (in commit ced001b). I've chosen `ElementKey` and `ConstraintKey`, since the Rust collections I've seen tend to use the language of keys and values.
pub rep: f64, pub rep: Signal<f64>,
glen marked this conversation as resolved Outdated
Outdated
Review

Let's get into a habit of using full words in interfaces/public property names. Looking at this, I don't know if "rep" is a representation, the number of repetitions, something that is being reported, or what... Please rename this suite of properties. Thanks!

Let's get into a habit of using full words in interfaces/public property names. Looking at this, I don't know if "rep" is a representation, the number of repetitions, something that is being reported, or what... Please rename this suite of properties. Thanks!

I've replaced rep with lorentz_prod in all the Constraint field names (commit 5839882). We can streamline the names later if they get too unwieldy.

I've replaced `rep` with `lorentz_prod` in all the `Constraint` field names (commit 5839882). We can streamline the names later if they get too unwieldy.
pub rep_text: Signal<String>,
pub rep_valid: Signal<bool>,
pub active: Signal<bool> pub active: Signal<bool>
} }
@ -116,11 +118,11 @@ impl Assembly {
let mut gram_to_be = PartialMatrix::new(); let mut gram_to_be = PartialMatrix::new();
self.constraints.with_untracked(|csts| { self.constraints.with_untracked(|csts| {
for (_, cst) in csts { for (_, cst) in csts {
if cst.active.get_untracked() { if cst.active.get_untracked() && cst.rep_valid.get_untracked() {
let args = cst.args; let args = cst.args;
let row = elts[args.0].index; let row = elts[args.0].index;
let col = elts[args.1].index; let col = elts[args.1].index;
gram_to_be.push_sym(row, col, cst.rep); gram_to_be.push_sym(row, col, cst.rep.get_untracked());
} }
} }
}); });

View File

@ -1,6 +1,7 @@
use itertools::Itertools; use itertools::Itertools;
glen marked this conversation as resolved
Review

Definitely at some point we are going to need to separate the src directory into parts for the Assembly/Engine and for each of the views, but fine if you don't think that's warranted yet. On the other hand, if you just want to set up a reasonable hierarchy now and see how it works, that's fine too.

Definitely at some point we are going to need to separate the src directory into parts for the Assembly/Engine and for each of the views, but fine if you don't think that's warranted yet. On the other hand, if you just want to set up a reasonable hierarchy now and see how it works, that's fine too.
Review

Definitely at some point we are going to need to separate the src directory into parts for the Assembly/Engine [...]

Yeah, I think we'll probably want separate modules for "front of house" and "back of house" code at some point. Right now it does seem like the engine and assembly modules should go together in the "back of house" module, but I could imagine that changing, since the assembly structure is pretty tailored to the needs of the user interface.

[...] and for each of the views

Note that the Display and Outline views each have their own module already: that's why the expressions mod display; and mod outline; appear at the top of main.rs.

> Definitely at some point we are going to need to separate the src directory into parts for the Assembly/Engine [...] Yeah, I think we'll probably want separate modules for "front of house" and "back of house" code at some point. Right now it does seem like the `engine` and `assembly` modules should go together in the "back of house" module, but I could imagine that changing, since the assembly structure is pretty tailored to the needs of the user interface. > [...] and for each of the views Note that the `Display` and `Outline` views each have their own module already: that's why the expressions `mod display;` and `mod outline;` appear at the top of `main.rs`.
Review

I was commenting on the fact that outline is in the same directory as assembly and engine. I guess the module structure may not be immediately clear to the untrained eye; but directory structure is.

Also be cautious about the notion that "assembly is tailored to needs of UI". The driver for what goes in Assembly is the facts of the platonic universe we are observing. So color and label are OK because the sphere labeled George is red in the platonic universe. But unless "hidden" means that an entity must be hidden in all possible views -- and I doubt it should -- that should not be part of Assembly. (That's just an example, I know there is not a "hidden" property yet.)

I was commenting on the fact that outline is in the same directory as assembly and engine. I guess the module structure may not be immediately clear to the untrained eye; but directory structure is. Also be cautious about the notion that "assembly is tailored to needs of UI". The driver for what goes in Assembly is the facts of the platonic universe we are observing. So color and label are OK because the sphere labeled George is red in the platonic universe. But unless "hidden" means that an entity must be hidden in all possible views -- and I doubt it should -- that should not be part of Assembly. (That's just an example, I know there is not a "hidden" property yet.)
use sycamore::{prelude::*, web::tags::div}; use sycamore::{prelude::*, web::tags::div};
use web_sys::{Element, KeyboardEvent, MouseEvent, wasm_bindgen::JsCast}; use web_sys::{Element, Event, HtmlInputElement, KeyboardEvent, MouseEvent, wasm_bindgen::JsCast};
use web_sys::{console, wasm_bindgen::JsValue}; /* DEBUG */
use crate::AppState; use crate::AppState;
@ -51,8 +52,6 @@ pub fn Outline() -> View {
let constrained = elt.constraints.len() > 0; let constrained = elt.constraints.len() > 0;
let details_node = create_node_ref(); let details_node = create_node_ref();
view! { view! {
/* [TO DO] switch to integer-valued parameters whenever
that becomes possible again */
li { li {
details(ref=details_node) { details(ref=details_node) {
summary( summary(
@ -138,7 +137,25 @@ pub fn Outline() -> View {
li(class="cst") { li(class="cst") {
input(r#type="checkbox", bind:checked=cst.active) input(r#type="checkbox", bind:checked=cst.active)
div(class="cst-label") { (other_arg_label) } div(class="cst-label") { (other_arg_label) }
div(class="cst-rep") { (cst.rep) } input(
r#type="number",
step="0.01",
bind:value=cst.rep_text,
on:change=move |event: Event| {
let target: HtmlInputElement = event.target().unwrap().unchecked_into();
let rep_valid = target.check_validity() && !target.value().is_empty();
batch(|| {
cst.rep_valid.set(rep_valid);
if rep_valid {
console::log_2(
&JsValue::from("Constraint rep parsed to"),
&JsValue::from(target.value_as_number())
);
cst.rep.set(target.value_as_number());
}
});
}
)
} }
} }
}, },