Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive tools for drawing geometric items #9

Open
3 tasks
Michael-F-Bryan opened this issue Jan 27, 2020 · 4 comments
Open
3 tasks

Interactive tools for drawing geometric items #9

Michael-F-Bryan opened this issue Jan 27, 2020 · 4 comments

Comments

@Michael-F-Bryan
Copy link
Owner

Michael-F-Bryan commented Jan 27, 2020

To be a CAD program our WebAssembly demo actually needs to draw things.

There should be a toolbar with buttons to enter specific "drawing modes". When you are in a mode the corresponding button stays pressed (letting the user know which mode they're in) and things like click events get passed to that mode.

For now we'll want to implement a formal mode system, with modes for:

  • Drawing points
    • Clicking on the canvas adds a point where the user clicked
  • Drawing lines
    • Clicking on the canvas once will set the line's start point
    • Once the start point is selected, moving the mouse around will draw a line from the start point to the cursor which follows the cursor as it moves, providing the user with visual feedback on the line they're in the middle of drawing
    • Clicking again will select the line's end point and add it to the drawing
  • Drawing arcs
    • I'm not 100% sure how we want to implement this one

The standard way to implement these modes is with some sort of state machine. I prefer trait objects over enums or strongly typed state machines because they scale more easily and are easier to work with.

pub trait Mode {
  fn on_mouse_down(&mut self, args: MouseDownArgs, world: &mut World) -> Transition { 
    Transition::DoNothing
  }

  fn on_mouse_move(&mut self, args: MouseMoveArgs, world: &mut World) -> Transition { 
    Transition::DoNothing
  }
}

pub enum Transition {
  DoNothing,
  ChangeState(Box<dyn Mode>),
}

(note: this is a big task and will probably require breaking into a dozen smaller issues along the way)

@DerLando
Copy link
Contributor

I would like to add to this another mode for selecting or picking already drawn geometry.

This is probably the most used functionality and can probably also be implemented as a mode.

As an algorithm for finding things under the mouse cursor we have the most important thing already, as we can do a quick sort of all DrawingObjects whose BoundingBox contains the MousePosition in WorldSpace and do some fine-grained checks afterwards

@Michael-F-Bryan
Copy link
Owner Author

Michael-F-Bryan commented Jan 28, 2020

Good idea @DerLando, I've pulled select mode out into its own issue.

Something we'll need to keep in mind is the distinction between UI code/concepts (e.g. the modes) and things which are inherent to the CAD engine (e.g. a Selected component and rendering). End users will probably want to implement interactions specific to their own application so AddPointMode and friends will be part of the WebAssembly demo, but things like rendering and geometry primitives are pretty universal and are best placed in arcs itself... How does that sound?

@DerLando
Copy link
Contributor

Ok so the idea is to make a clear distinction between the geometric backend and the ui/application frontend.
Sounds good to me as we show one possible implementation via the wasm demo.

Although I think providing an easy-to-use abstraction for the most basic building blocks of any commands/modes could be implemented by us, like f.e.:

  • Picking Points on the canvas
  • Selecting existing geometry

@Michael-F-Bryan
Copy link
Owner Author

Michael-F-Bryan commented Jan 29, 2020

Yeah, arcs should provide all the building blocks you need to build your own application, but the actual behaviour should be left up to consumers.

I imagine we'd expose helper functions like

fn select(world: &World, entity: Entity) { 
  world.write_storage::<Selected>().insert(entity, Selected);
}

/// Look up entities using their location in *Drawing Space*.
fn entities_under_point(
    world: &World, 
    location: Vector, 
    tolerance: f64) -> impl Iterator<Item = (Entity, &DrawingObject)> {
  ...
}

/// Look up entities based on their location on a canvas.
fn entities_under_cursor(
    world: &World, 
    viewport: &Viewport,
    window_dimensions: kurbo::Size,
    location: kurbo::Point, 
    tolerance: f64) -> impl Iterator<Item = (Entity, &DrawingObject)> {
  ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants