1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

math: add a pure V math.mathutil, with generic min, max and abs functions (#9176), and use it consistently

This commit is contained in:
Lukas Neubert 2021-03-12 10:28:04 +01:00 committed by GitHub
parent 530b981765
commit a67d49050c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 193 additions and 125 deletions

View File

@ -1,6 +1,7 @@
import gg
import gx
import math
import math.mathutil as mu
import os
import rand
import time
@ -200,33 +201,6 @@ enum Direction {
}
// Utility functions
[inline]
fn min(a int, b int) int {
if a < b {
return a
} else {
return b
}
}
[inline]
fn max(a int, b int) int {
if a > b {
return a
} else {
return b
}
}
[inline]
fn abs(a int) int {
if a < 0 {
return -a
} else {
return a
}
}
[inline]
fn avg(a int, b int) int {
return (a + b) / 2
@ -591,7 +565,7 @@ fn (mut app App) resize() {
window_size := gg.window_size()
w := window_size.width
h := window_size.height
m := f32(min(w, h))
m := f32(mu.min(w, h))
app.ui.dpi_scale = s
app.ui.window_width = w
app.ui.window_height = h
@ -615,7 +589,7 @@ fn (app &App) draw() {
xpad, ypad := app.ui.x_padding, app.ui.y_padding
ww := app.ui.window_width
wh := app.ui.window_height
m := min(ww, wh)
m := mu.min(ww, wh)
labelx := xpad + app.ui.border_size
labely := ypad + app.ui.border_size / 2
app.draw_tiles()
@ -649,7 +623,7 @@ fn (app &App) draw_tiles() {
xstart := app.ui.x_padding + app.ui.border_size
ystart := app.ui.y_padding + app.ui.border_size + app.ui.header_size
toffset := app.ui.tile_size + app.ui.padding_size
tiles_size := min(app.ui.window_width, app.ui.window_height) - app.ui.border_size * 2
tiles_size := mu.min(app.ui.window_width, app.ui.window_height) - app.ui.border_size * 2
// Draw the padding around the tiles
app.gg.draw_rounded_rect(xstart, ystart, tiles_size / 2, tiles_size / 2, tiles_size / 24,
app.theme.padding_color)
@ -711,8 +685,8 @@ fn (app &App) draw_tiles() {
fn (mut app App) handle_touches() {
s, e := app.touch.start, app.touch.end
adx, ady := abs(e.pos.x - s.pos.x), abs(e.pos.y - s.pos.y)
if max(adx, ady) < 10 {
adx, ady := mu.abs(e.pos.x - s.pos.x), mu.abs(e.pos.y - s.pos.y)
if mu.max(adx, ady) < 10 {
app.handle_tap()
} else {
app.handle_swipe()
@ -722,7 +696,7 @@ fn (mut app App) handle_touches() {
fn (mut app App) handle_tap() {
_, ypad := app.ui.x_padding, app.ui.y_padding
w, h := app.ui.window_width, app.ui.window_height
m := min(w, h)
m := mu.min(w, h)
s, e := app.touch.start, app.touch.end
avgx, avgy := avg(s.pos.x, e.pos.x), avg(s.pos.y, e.pos.y)
// TODO: Replace "touch spots" with actual buttons
@ -760,12 +734,12 @@ fn (mut app App) handle_swipe() {
s, e := app.touch.start, app.touch.end
w, h := app.ui.window_width, app.ui.window_height
dx, dy := e.pos.x - s.pos.x, e.pos.y - s.pos.y
adx, ady := abs(dx), abs(dy)
dmin := if min(adx, ady) > 0 { min(adx, ady) } else { 1 }
dmax := if max(adx, ady) > 0 { max(adx, ady) } else { 1 }
adx, ady := mu.abs(dx), mu.abs(dy)
dmin := if mu.min(adx, ady) > 0 { mu.min(adx, ady) } else { 1 }
dmax := if mu.max(adx, ady) > 0 { mu.max(adx, ady) } else { 1 }
tdiff := int(e.time.unix_time_milli() - s.time.unix_time_milli())
// TODO: make this calculation more accurate (don't use arbitrary numbers)
min_swipe_distance := int(math.sqrt(min(w, h) * tdiff / 100)) + 20
min_swipe_distance := int(math.sqrt(mu.min(w, h) * tdiff / 100)) + 20
if dmax < min_swipe_distance {
return
}

View File

@ -9,6 +9,7 @@ import sokol.sapp
import sokol.sgl
import sokol.gfx
import math
import math.mathutil as mu
// import time
pub type FNCb = fn (x voidptr)
@ -538,13 +539,6 @@ pub fn (gg &Context) end() {
*/
}
fn abs(a f32) f32 {
if a >= 0 {
return a
}
return -a
}
pub fn (mut ctx Context) resize(width int, height int) {
ctx.width = width
ctx.height = height
@ -556,8 +550,8 @@ pub fn (ctx &Context) draw_line(x f32, y f32, x2 f32, y2 f32, c gx.Color) {
}
if ctx.scale > 1 {
// Make the line more clear on hi dpi screens: draw a rectangle
mut width := abs(x2 - x)
mut height := abs(y2 - y)
mut width := mu.abs(x2 - x)
mut height := mu.abs(y2 - y)
if width == 0 {
width = 1
} else if height == 0 {

View File

@ -232,4 +232,4 @@ fn test_proj() {
assert m4.mul_vec(ort, m4.Vec4{[ f32(150), 100, 0, 1]!}) == m4.Vec4{[ f32(0), 0, 0, 1]!}
assert m4.mul_vec(ort, m4.Vec4{[ f32(0), 0, 0, 1]!}) == m4.Vec4{[ f32(-1), -1, 0, 1]!}
assert m4.mul_vec(ort, m4.Vec4{[ f32(300), 200, 0, 1]!}) == m4.Vec4{[ f32(1), 1, 0, 1]!}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module mathutil
[inline]
pub fn min<T>(a T, b T) T {
if a < b {
return a
} else {
return b
}
}
[inline]
pub fn max<T>(a T, b T) T {
if a > b {
return a
} else {
return b
}
}
[inline]
pub fn abs<T>(a T) T {
if a > 0 {
return a
} else {
return -a
}
}

View File

@ -0,0 +1,22 @@
import math.mathutil as mu
fn test_min() {
assert mu.min(42, 13) == 13
assert mu.min(5, -10) == -10
assert mu.min(7.1, 7.3) == 7.1
assert mu.min(u32(32), u32(17)) == 17
}
fn test_max() {
assert mu.max(42, 13) == 42
assert mu.max(5, -10) == 5
assert mu.max(7.1, 7.3) == 7.3
assert mu.max(u32(60), u32(17)) == 60
}
fn test_abs() {
assert mu.abs(99) == 99
assert mu.abs(-10) == 10
assert mu.abs(1.2345) == 1.2345
assert mu.abs(-5.5) == 5.5
}

82
vlib/math/util/util.v Normal file
View File

@ -0,0 +1,82 @@
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license
// that can be found in the LICENSE file.
module util
// imin returns the smallest of two integer values
[inline]
pub fn imin(a int, b int) int {
return if a < b { a } else { b }
}
// imin returns the biggest of two integer values
[inline]
pub fn imax(a int, b int) int {
return if a > b { a } else { b }
}
// iabs returns an integer as absolute value
[inline]
pub fn iabs(v int) int {
return if v > 0 { v } else { -v }
}
// umin returns the smallest of two u32 values
[inline]
pub fn umin(a u32, b u32) u32 {
return if a < b { a } else { b }
}
// umax returns the biggest of two u32 values
[inline]
pub fn umax(a u32, b u32) u32 {
return if a > b { a } else { b }
}
// uabs returns an u32 as absolute value
[inline]
pub fn uabs(v u32) u32 {
return if v > 0 { v } else { -v }
}
// fmin_32 returns the smallest `f32` of input `a` and `b`.
// Example: assert fmin_32(2.0,3.0) == 2.0
[inline]
pub fn fmin_32(a f32, b f32) f32 {
return if a < b { a } else { b }
}
// fmax_32 returns the largest `f32` of input `a` and `b`.
// Example: assert fmax_32(2.0,3.0) == 3.0
[inline]
pub fn fmax_32(a f32, b f32) f32 {
return if a > b { a } else { b }
}
// fabs_32 returns the absolute value of `a` as a `f32` value.
// Example: assert fabs_32(-2.0) == 2.0
[inline]
pub fn fabs_32(v f32) f32 {
return if v > 0 { v } else { -v }
}
// fmin_64 returns the smallest `f64` of input `a` and `b`.
// Example: assert fmin_64(2.0,3.0) == 2.0
[inline]
pub fn fmin_64(a f64, b f64) f64 {
return if a < b { a } else { b }
}
// fmax_64 returns the largest `f64` of input `a` and `b`.
// Example: assert fmax_64(2.0,3.0) == 3.0
[inline]
pub fn fmax_64(a f64, b f64) f64 {
return if a > b { a } else { b }
}
// fabs_64 returns the absolute value of `a` as a `f64` value.
// Example: assert fabs_64(-2.0) == f64(2.0)
[inline]
pub fn fabs_64(v f64) f64 {
return if v > 0 { v } else { -v }
}

View File

@ -254,9 +254,3 @@ pub fn (mut ctx Context) horizontal_separator(y int) {
ctx.set_cursor_position(0, y)
ctx.write(strings.repeat(/* `⎽` */`-`, ctx.window_width))
}
[inline]
fn abs(a int) int {
return if a < 0 { -a } else { a }
}

View File

@ -1,5 +1,6 @@
module doc
import math.mathutil as mu
import strings
import v.ast
import v.util
@ -93,11 +94,11 @@ fn (mut d Doc) convert_pos(filename string, pos token.Position) DocPos {
d.sources[filename] = util.read_file(os.join_path(d.base_path, filename)) or { '' }
}
source := d.sources[filename]
mut p := util.imax(0, util.imin(source.len - 1, pos.pos))
column := util.imax(0, pos.pos - p - 1)
mut p := mu.max(0, mu.min(source.len - 1, pos.pos))
column := mu.max(0, pos.pos - p - 1)
return DocPos{
line: pos.line_nr + 1
col: util.imax(1, column + 1)
col: mu.max(1, column + 1)
len: pos.len
}
}

View File

@ -3,6 +3,7 @@
// that can be found in the LICENSE file.
module fmt
import math.mathutil as mu
import v.ast
import v.table
import strings
@ -70,7 +71,7 @@ pub fn fmt(file ast.File, table &table.Table, pref &pref.Preferences, is_debug b
if res.len == 1 {
return f.out_imports.str().trim_space() + '\n'
}
bounded_import_pos := util.imin(res.len, f.import_pos)
bounded_import_pos := mu.min(res.len, f.import_pos)
return res[..bounded_import_pos] + f.out_imports.str() + res[bounded_import_pos..]
}

View File

@ -3,9 +3,9 @@
// that can be found in the LICENSE file.
module fmt
import math.mathutil as mu
import strings
import v.ast
import v.util
const (
threshold_to_align_struct = 8
@ -75,8 +75,7 @@ fn (mut list []CommentAndExprAlignInfo) add_info(attrs_len int, type_len int, li
list.add_new_info(attrs_len, type_len, line)
return
}
d_len := util.iabs(list[i].max_attrs_len - attrs_len) +
util.iabs(list[i].max_type_len - type_len)
d_len := mu.abs(list[i].max_attrs_len - attrs_len) + mu.abs(list[i].max_type_len - type_len)
if !(d_len < fmt.threshold_to_align_struct) {
list.add_new_info(attrs_len, type_len, line)
return
@ -167,15 +166,15 @@ pub fn (mut f Fmt) struct_decl(node ast.StructDecl) {
// keep one empty line between fields (exclude one after mut:, pub:, ...)
mut before_last_line := node.fields[i - 1].pos.line_nr
if node.fields[i - 1].comments.len > 0 {
before_last_line = util.imax(before_last_line, node.fields[i - 1].comments.last().pos.last_line)
before_last_line = mu.max(before_last_line, node.fields[i - 1].comments.last().pos.last_line)
}
if node.fields[i - 1].has_default_expr {
before_last_line = util.imax(before_last_line, node.fields[i - 1].default_expr.position().last_line)
before_last_line = mu.max(before_last_line, node.fields[i - 1].default_expr.position().last_line)
}
mut next_first_line := field.pos.line_nr
if field.comments.len > 0 {
next_first_line = util.imin(next_first_line, field.comments[0].pos.line_nr)
next_first_line = mu.min(next_first_line, field.comments[0].pos.line_nr)
}
if next_first_line - before_last_line > 1 {
f.writeln('')

View File

@ -3,6 +3,7 @@
// that can be found in the LICENSE file.
module scanner
import math.mathutil as mu
import os
import v.token
import v.pref
@ -1057,7 +1058,7 @@ fn (mut s Scanner) text_scan() token.Token {
fn (mut s Scanner) invalid_character() {
len := utf8_char_len(s.text[s.pos])
end := util.imin(s.pos + len, s.text.len)
end := mu.min(s.pos + len, s.text.len)
c := s.text[s.pos..end]
s.error('invalid character `$c`')
}

View File

@ -3,6 +3,7 @@
// that can be found in the LICENSE file.
module util
import math.mathutil as mu
import os
import strings
import term
@ -81,7 +82,7 @@ pub fn formatted_error(kind string, omsg string, filepath string, pos token.Posi
}
//
source, column := filepath_pos_to_source_and_column(filepath, pos)
position := '$path:${pos.line_nr + 1}:${imax(1, column + 1)}:'
position := '$path:${pos.line_nr + 1}:${mu.max(1, column + 1)}:'
scontext := source_context(kind, source, column, pos).join('\n')
final_position := bold(position)
final_kind := bold(color(kind, kind))
@ -95,7 +96,7 @@ pub fn filepath_pos_to_source_and_column(filepath string, pos token.Position) (s
// TODO: optimize this; may be use a cache.
// The column should not be so computationally hard to get.
source := read_file(filepath) or { '' }
mut p := imax(0, imin(source.len - 1, pos.pos))
mut p := mu.max(0, mu.min(source.len - 1, pos.pos))
if source.len > 0 {
for ; p >= 0; p-- {
if source[p] == `\n` || source[p] == `\r` {
@ -103,7 +104,7 @@ pub fn filepath_pos_to_source_and_column(filepath string, pos token.Position) (s
}
}
}
column := imax(0, pos.pos - p - 1)
column := mu.max(0, pos.pos - p - 1)
return source, column
}
@ -113,13 +114,13 @@ pub fn source_context(kind string, source string, column int, pos token.Position
return clines
}
source_lines := source.split_into_lines()
bline := imax(0, pos.line_nr - util.error_context_before)
aline := imax(0, imin(source_lines.len - 1, pos.line_nr + util.error_context_after))
bline := mu.max(0, pos.line_nr - util.error_context_before)
aline := mu.max(0, mu.min(source_lines.len - 1, pos.line_nr + util.error_context_after))
tab_spaces := ' '
for iline := bline; iline <= aline; iline++ {
sline := source_lines[iline]
start_column := imax(0, imin(column, sline.len))
end_column := imax(0, imin(column + imax(0, pos.len), sline.len))
start_column := mu.max(0, mu.min(column, sline.len))
end_column := mu.max(0, mu.min(column + mu.max(0, pos.len), sline.len))
cline := if iline == pos.line_nr {
sline[..start_column] + color(kind, sline[start_column..end_column]) +
sline[end_column..]

View File

@ -372,21 +372,6 @@ pub fn skip_bom(file_content string) string {
return raw_text
}
[inline]
pub fn imin(a int, b int) int {
return if a < b { a } else { b }
}
[inline]
pub fn imax(a int, b int) int {
return if a > b { a } else { b }
}
[inline]
pub fn iabs(v int) int {
return if v > 0 { v } else { -v }
}
pub fn replace_op(s string) string {
if s.len == 1 {
last_char := s[s.len - 1]

View File

@ -133,24 +133,6 @@ pub fn (mut bmp BitMap) save_raw_data(file_name string) {
//
// Math functions
//
[inline]
fn abs(a int) int {
if a < 0 {
return -a
} else {
return a
}
}
[inline]
fn fabs(a f32) f32 {
if a < 0 {
return -a
} else {
return a
}
}
// integer part of x
[inline]
fn ipart(x f32) f32 {

View File

@ -10,11 +10,12 @@ module ttf
*
* Note:
*
* TODO:
* - manage text directions R to L
* TODO:
* - manage text directions R to L
**********************************************************************/
import encoding.utf8
import math
import math.mathutil as mu
pub struct BitMap {
pub mut:
@ -226,7 +227,7 @@ pub fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
dist := f32(0.4)
if fabs(dx) > fabs(dy) {
if mu.abs(dx) > mu.abs(dy) {
if x1 < x0 {
tmp = x0
x0 = x1
@ -246,18 +247,18 @@ pub fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
mut x := x0
for x <= x1 + 0.5 {
y := m * (x - x0) + y0
e := 1 - fabs(y - 0.5 - int(y))
e := 1 - mu.abs(y - 0.5 - int(y))
bmp.plot(int(x), int(y), color_multiply_alpha(c, e * 0.75))
ys1 := y + dist
if int(ys1) != int(y) {
v1 := fabs(ys1 - y) / dist * (1 - e)
v1 := mu.abs(ys1 - y) / dist * (1 - e)
bmp.plot(int(x), int(ys1), color_multiply_alpha(c, v1))
}
ys2 := y - dist
if int(ys2) != int(y) {
v2 := fabs(y - ys2) / dist * (1 - e)
v2 := mu.abs(y - ys2) / dist * (1 - e)
bmp.plot(int(x), int(ys2), color_multiply_alpha(c, v2))
}
@ -283,18 +284,18 @@ pub fn (mut bmp BitMap) aline(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
mut y := y0
for y <= y1 + 0.5 {
x := n * (y - y0) + x0
e := f32(1 - fabs(x - 0.5 - int(x)))
e := f32(1 - mu.abs(x - 0.5 - int(x)))
bmp.plot(int(x), int(y), color_multiply_alpha(c, f32(e * 0.75)))
xs1 := x + dist
if int(xs1) != int(x) {
v1 := fabs(xs1 - x) / dist * (1 - e)
v1 := mu.abs(xs1 - x) / dist * (1 - e)
bmp.plot(int(xs1), int(y), color_multiply_alpha(c, f32(v1)))
}
xs2 := x - dist
if int(xs2) != int(x) {
v2 := fabs(x - xs1) / dist * (1 - e)
v2 := mu.abs(x - xs1) / dist * (1 - e)
bmp.plot(int(xs2), int(y), color_multiply_alpha(c, f32(v2)))
}
y += 1.0
@ -335,9 +336,9 @@ pub fn (mut bmp BitMap) line(in_x0 int, in_y0 int, in_x1 int, in_y1 int, c u32)
mut x := x0
mut y := y0
dx := abs(x1 - x0)
dx := mu.abs(x1 - x0)
sx := if x0 < x1 { 1 } else { -1 }
dy := -abs(y1 - y0)
dy := -mu.abs(y1 - y0)
sy := if y0 < y1 { 1 } else { -1 }
// verical line
@ -411,8 +412,8 @@ pub fn (mut bmp BitMap) quadratic(in_x0 int, in_y0 int, in_x1 int, in_y1 int, in
cy := int(in_cy)
mut division := f64(1.0)
dx := abs(x0 - x1)
dy := abs(y0 - y1)
dx := mu.abs(x0 - x1)
dy := mu.abs(y0 - y1)
// if few pixel draw a simple line
// if dx == 0 && dy == 0 {
@ -520,10 +521,10 @@ pub fn (mut bmp BitMap) get_chars_bbox(in_string string) []int {
x_min, x_max, _, _ := bmp.tf.read_glyph_dim(c_index)
//-----------------
width := int((abs(x_max + x_min) + ax) * bmp.scale)
width := int((mu.abs(x_max + x_min) + ax) * bmp.scale)
// width := int((cw+ax) * bmp.scale)
w += width + div_space_cw
h := int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
h := int(mu.abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
res << w
res << h
@ -591,7 +592,7 @@ pub fn (mut bmp BitMap) get_bbox(in_string string) (int, int) {
// x_max := 2
//-----------------
width := int((abs(x_max + x_min) + ax) * bmp.scale)
width := int((mu.abs(x_max + x_min) + ax) * bmp.scale)
// width := int((cw+ax) * bmp.scale)
w += width + div_space_cw
@ -600,7 +601,7 @@ pub fn (mut bmp BitMap) get_bbox(in_string string) (int, int) {
// dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
// buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
return w, int(mu.abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
}
/******************************************************************************
@ -620,7 +621,7 @@ fn (mut bmp BitMap) draw_notdef_glyph(in_x int, in_w int) {
bmp.ch_matrix[7] = int(y1)
x, y := bmp.trf_ch(p)
y_h := fabs(bmp.tf.y_max - bmp.tf.y_min) * bmp.scale * 0.5
y_h := mu.abs(bmp.tf.y_max - bmp.tf.y_min) * bmp.scale * 0.5
bmp.box(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color)
bmp.line(int(x), int(y), int(x - in_w), int(y - y_h), bmp.color)
@ -689,7 +690,7 @@ pub fn (mut bmp BitMap) draw_text(in_string string) (int, int) {
// x_max := 2
//-----------------
mut width := int((abs(x_max + x_min) + ax) * bmp.scale)
mut width := int((mu.abs(x_max + x_min) + ax) * bmp.scale)
if bmp.use_font_metrics {
width = int((cw + ax) * bmp.scale)
}
@ -699,7 +700,7 @@ pub fn (mut bmp BitMap) draw_text(in_string string) (int, int) {
// dprintln("y_min: $bmp.tf.y_min y_max: $bmp.tf.y_max res: ${int((bmp.tf.y_max - bmp.tf.y_min)*buf.scale)} width: ${int( (cw) * buf.scale)}")
// buf.box(0,y_base - int((bmp.tf.y_min)*buf.scale), int( (x_max) * buf.scale), y_base-int((bmp.tf.y_max)*buf.scale), u32(0xFF00_0000) )
return w, int(abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
return w, int(mu.abs(int(bmp.tf.y_max - bmp.tf.y_min)) * bmp.scale)
}
pub fn (mut bmp BitMap) draw_glyph(index u16) (int, int) {
@ -798,7 +799,7 @@ pub fn (mut bmp BitMap) draw_glyph(index u16) (int, int) {
// (prev.y + point.y) / 2 + y);
// bmp.line(x0, y0, start_point.x, start_point.y, u32(0x00FF0000)
// u32(0xFF000000))
// u32(0xFF000000))
bmp.quadratic(x0, y0, start_point.x, start_point.y, (point.x +
start_point.x) / 2, (point.y + start_point.y) / 2, color)
}