Skip to content

Commit

Permalink
feat(draw_primitive): add filled arrow, triangle
Browse files Browse the repository at this point in the history
  • Loading branch information
kakoc committed Sep 11, 2023
1 parent 2b1a3a4 commit 7a5c597
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 25 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Hotkeys:
f - take a screenshot where selected area is focused, save to a clipboard and exit
a - draw an arrow
z - draw a filled arrow
l - draw a line
r - draw a rectangular border
p - draw a filled rectangle
Expand Down
49 changes: 32 additions & 17 deletions src/arrow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::line::draw_line;
use crate::{line::draw_line, triangle::draw_triangle_filled};

pub fn draw_arrow(
pub fn draw_arrow_bordered(
canvas: &mut [u8],
x0: usize,
y0: usize,
Expand All @@ -13,15 +13,8 @@ pub fn draw_arrow(
return;
}

let angle_in_deg = 30.0;
let tip_length = 50.0;

let (arrow_head_a, arrow_head_b) = calculate_arrow_head(
(x0 as f64, y0 as f64),
(x1 as f64, y1 as f64),
angle_in_deg,
tip_length,
);
let (arrow_head_a, arrow_head_b) =
calculate_arrow_head((x0 as f64, y0 as f64), (x1 as f64, y1 as f64));

if !arrow_head_a.0.is_nan() && !arrow_head_a.1.is_nan() {
draw_line(
Expand Down Expand Up @@ -50,12 +43,34 @@ pub fn draw_arrow(
draw_line(canvas, x0, y0, x1, y1, width, color);
}

pub fn calculate_arrow_head(
start: (f64, f64),
end: (f64, f64),
angle_in_deg: f64,
tip_length: f64,
) -> ((f64, f64), (f64, f64)) {
pub fn draw_arrow_filled(
canvas: &mut [u8],
x0: usize,
y0: usize,
x1: usize,
y1: usize,
width: usize,
color: (u8, u8, u8, u8),
) {
draw_arrow_bordered(canvas, x0, y0, x1, y1, width, color);

let (arrow_head_a, arrow_head_b) =
calculate_arrow_head((x0 as f64, y0 as f64), (x1 as f64, y1 as f64));

draw_triangle_filled(
canvas,
(x1, y1),
(arrow_head_a.0 as usize, arrow_head_a.1 as usize),
(arrow_head_b.0 as usize, arrow_head_b.1 as usize),
width,
color,
);
}

pub fn calculate_arrow_head(start: (f64, f64), end: (f64, f64)) -> ((f64, f64), (f64, f64)) {
let angle_in_deg: f64 = 30.0;
let tip_length = 50.0;

let (x1, y1) = end;
let (x2, y2) = start;
let alpha = angle_in_deg.to_radians();
Expand Down
53 changes: 46 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use std::{env, process};
#[cfg(target_os = "linux")]
use arboard::SetExtLinux;
use arboard::{Clipboard, ImageData};
use arrow::draw_arrow;
use arrow::draw_arrow_bordered;
use arrow::draw_arrow_filled;
use error_iter::ErrorIter as _;
use line::draw_line;
use log::error;
use pixels::{Error, Pixels, SurfaceTexture};
use rectangle::draw_rect_borders;
use rectangle::draw_rect_bordered;
use rectangle::draw_rect_filled;
use screenshots::Screen;
use serde::{Deserialize, Serialize};
Expand All @@ -29,7 +30,9 @@ mod arrow;
mod blend;
mod circle;
mod line;
mod point;
mod rectangle;
mod triangle;

const DAEMONIZE_ARG: &str = "__internal_daemonize";

Expand Down Expand Up @@ -59,6 +62,7 @@ Hotkeys:
f - take a screenshot where selected area is focused, save to a clipboard and exit
a - draw an arrow
z - draw a filled arrow
l - draw a line
r - draw a rectangular border
p - draw a filled rectangle
Expand Down Expand Up @@ -190,6 +194,9 @@ Hotkeys:
if let Some(VirtualKeyCode::A) = virtual_keycode {
screenshot.draw_mode = Some(DrawMode::Arrow);
}
if let Some(VirtualKeyCode::Z) = virtual_keycode {
screenshot.draw_mode = Some(DrawMode::ArrowFilled);
}
if let Some(VirtualKeyCode::L) = virtual_keycode {
screenshot.draw_mode = Some(DrawMode::Line);
}
Expand Down Expand Up @@ -370,7 +377,18 @@ impl Screenshot {
fn draw_draw_item(&mut self, draw_item: &DrawnItem) {
match draw_item {
DrawnItem::Arrow((x0, y0), (x1, y1)) => {
draw_arrow(
draw_arrow_bordered(
&mut self.modified_screenshot,
*x0,
*y0,
*x1,
*y1,
self.width,
BORDER_COLOR,
);
}
DrawnItem::ArrowFilled((x0, y0), (x1, y1)) => {
draw_arrow_filled(
&mut self.modified_screenshot,
*x0,
*y0,
Expand All @@ -392,7 +410,7 @@ impl Screenshot {
);
}
DrawnItem::RectBorder((x0, y0), (x1, y1)) => {
draw_rect_borders(
draw_rect_bordered(
&mut self.modified_screenshot,
*x0,
*y0,
Expand All @@ -417,7 +435,7 @@ impl Screenshot {
}

fn draw_boundaries(&mut self) {
draw_rect_borders(
draw_rect_bordered(
&mut self.modified_screenshot,
self.p0.0,
self.p0.1,
Expand Down Expand Up @@ -447,8 +465,8 @@ impl Screenshot {

pub fn toggle_item_filling(&mut self, draw_item: &DrawnItem) -> DrawnItem {
match draw_item {
// TODO(kakoc): implement toggle state for arrow
DrawnItem::Arrow(..) => *draw_item,
DrawnItem::Arrow(p0, p1) => DrawnItem::ArrowFilled(*p0, *p1),
DrawnItem::ArrowFilled(p0, p1) => DrawnItem::Arrow(*p0, *p1),
DrawnItem::Line(..) => *draw_item,
DrawnItem::RectBorder(p0, p1) => DrawnItem::RectFilled(*p0, *p1),
DrawnItem::RectFilled(p0, p1) => DrawnItem::RectBorder(*p0, *p1),
Expand All @@ -475,6 +493,13 @@ impl Screenshot {
*p1 = (x as usize, y as usize);
}
}
Some(DrawMode::ArrowFilled) => {
if let (Some(DrawnItem::ArrowFilled(_, p1)), Some(PhysicalPosition { x, y })) =
(&mut self.drawing_item, self.mouse_coordinates)
{
*p1 = (x as usize, y as usize);
}
}
Some(DrawMode::Line) => {
if let (Some(DrawnItem::Line(_, p1)), Some(PhysicalPosition { x, y })) =
(&mut self.drawing_item, self.mouse_coordinates)
Expand Down Expand Up @@ -545,6 +570,9 @@ impl Screenshot {
Some(DrawMode::Arrow) => {
self.drawing_item = Some(DrawnItem::Arrow((x, y), (x, y)));
}
Some(DrawMode::ArrowFilled) => {
self.drawing_item = Some(DrawnItem::ArrowFilled((x, y), (x, y)));
}
Some(DrawMode::Line) => {
self.drawing_item = Some(DrawnItem::Line((x, y), (x, y)));
}
Expand Down Expand Up @@ -577,6 +605,15 @@ impl Screenshot {
self.drawing_item = None;
}
}
Some(DrawMode::ArrowFilled) => {
if let (Some(DrawnItem::ArrowFilled(p0, _)), Some(PhysicalPosition { x, y })) =
(self.drawing_item, self.mouse_coordinates)
{
self.drawn_items
.push(DrawnItem::ArrowFilled(p0, (x as usize, y as usize)));
self.drawing_item = None;
}
}
Some(DrawMode::Line) => {
if let (Some(DrawnItem::Line(p0, _)), Some(PhysicalPosition { x, y })) =
(self.drawing_item, self.mouse_coordinates)
Expand Down Expand Up @@ -613,6 +650,7 @@ impl Screenshot {

enum DrawMode {
Arrow,
ArrowFilled,
Line,
RectBorder,
RectFilled,
Expand All @@ -621,6 +659,7 @@ enum DrawMode {
#[derive(Clone, Copy)]
enum DrawnItem {
Arrow((usize, usize), (usize, usize)),
ArrowFilled((usize, usize), (usize, usize)),
Line((usize, usize), (usize, usize)),
RectBorder((usize, usize), (usize, usize)),
RectFilled((usize, usize), (usize, usize)),
Expand Down
137 changes: 137 additions & 0 deletions src/point.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use std::ops::{Add, Mul, Sub};

#[derive(Clone, Copy, Default, Debug)]
pub struct Point<T> {
pub x: T,
pub y: T,
}

impl<T: Add<Output = T>> Add for Point<T> {
type Output = Self;

fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}

impl<T: Sub<Output = T>> Sub for Point<T> {
type Output = Self;

fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}

impl<T> Mul<T> for Point<T>
where
T: Mul<Output = T> + Copy,
{
type Output = Point<T>;
fn mul(self, rhs: T) -> Self::Output {
Point {
x: self.x * rhs,
y: self.y * rhs,
}
}
}

impl From<Point<f64>> for Point<i32> {
fn from(v: Point<f64>) -> Self {
Point {
x: v.x as i32,
y: v.y as i32,
}
}
}

impl From<Point<i32>> for Point<f64> {
fn from(v: Point<i32>) -> Self {
Point {
x: v.x as f64,
y: v.y as f64,
}
}
}

#[derive(Clone, Copy, Default, Debug)]
pub struct Vec3<T> {
pub x: T,
pub y: T,
pub z: T,
}

impl<T: Add<Output = T>> Add for Vec3<T> {
type Output = Self;

fn add(self, other: Self) -> Self {
Self {
x: self.x + other.x,
y: self.y + other.y,
z: self.z + other.z,
}
}
}

impl<T: Sub<Output = T>> Sub for Vec3<T> {
type Output = Self;

fn sub(self, other: Self) -> Self {
Self {
x: self.x - other.x,
y: self.y - other.y,
z: self.z - other.z,
}
}
}

impl<T> Mul<T> for Vec3<T>
where
T: Mul<Output = T> + Copy,
{
type Output = Vec3<T>;
fn mul(self, rhs: T) -> Self::Output {
Vec3 {
x: self.x * rhs,
y: self.y * rhs,
z: self.z * rhs,
}
}
}

impl<T: Mul<Output = T>> Mul for Vec3<T> {
type Output = Vec3<T>;

fn mul(self, rhs: Vec3<T>) -> Self::Output {
Vec3 {
x: self.x * rhs.x,
y: self.y * rhs.y,
z: self.z * rhs.z,
}
}
}

impl From<Vec3<f64>> for Vec3<i32> {
fn from(v: Vec3<f64>) -> Self {
Vec3 {
x: v.x as i32,
y: v.y as i32,
z: v.z as i32,
}
}
}

impl From<Vec3<i32>> for Vec3<f64> {
fn from(v: Vec3<i32>) -> Self {
Vec3 {
x: v.x as f64,
y: v.y as f64,
z: v.z as f64,
}
}
}
2 changes: 1 addition & 1 deletion src/rectangle.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::line::draw_line;

pub fn draw_rect_borders(
pub fn draw_rect_bordered(
canvas: &mut [u8],
x0: usize,
y0: usize,
Expand Down
Loading

0 comments on commit 7a5c597

Please sign in to comment.