A Collection of Code Snippets in as Many Programming Languages as Possible
This project is maintained by TheRenegadeCoder
Welcome to the Convex Hull in M4 page! Here, you'll find the source code for this program as well as a description of how the program works.
divert(-1)
define(`show_usage',
`Usage: please provide at least 3 x and y coordinates as separate lists (e.g. "100, 440, 210")
m4exit(`1')')
dnl Reference: https://www.gnu.org/software/m4/manual/m4.html#index-array
dnl array_get(var_name, idx)
define(`array_get', `defn(format(``%s[%s]'', `$1', `$2'))')
dnl array_set(var_name, idx, value)
define(`array_set', `define(format(``%s[%s]'', `$1', `$2'), `$3')')
dnl 2D versions of "array_get" and "array_set"
dnl array2_get(varname, idx1, idx2)
define(`array2_get', `defn(format(``%s[%s][%s]'', `$1', `$2', `$3'))')
dnl array2_set(varname, idx1, idx2, value)
define(`array2_set', `define(format(``%s[%s][%s]'', `$1', `$2', `$3'), `$4')')
dnl is_valid(n)
define(`is_valid', `eval(regexp(`$1', `^\s*-?[0-9]+\s*$') >= 0)')
dnl parse_int_list(varname, args):
dnl varname[length] = 0
dnl foreach arg in args:
dnl if not is_valid(arg):
dnl Return 0
dnl varname[varname[length]] = arg
dnl varname[length] = varname[length] + 1
dnl Return 1
define(`parse_int_list',
`array_set(`$1', `length', 0)dnl
_parse_int_list(`$1', $2)'dnl
)
define(`_parse_int_list',
`ifelse(is_valid(`$2'), 0, `0',
`array_set(`$1', array_get(`$1', `length'), `$2')dnl
array_set(`$1', `length', incr(array_get(`$1', `length')))dnl
ifelse(eval($# > 2), 1, `_parse_int_list(`$1', shift(shift($@)))', `1')'dnl
)'dnl
)
dnl form_points(x_varname, y_varname, points_varname):
dnl points_varname["length"] = x_varname["length"]
dnl for i = 0 to points_varname["length"] - 1:
dnl points_varname[i]["x"] = x_varname[i]
dnl points_varname[i]["y"] = y_varname[i]
define(`form_points',
`array_set(`$3', `length', array_get(`$1', `length'))dnl
_form_points(`$1', `$2', `$3', 0)dnl
'dnl
)
dnl x_varname=$1, y_varname=$2, points_varname=$3, i=$4
define(`_form_points',
`ifelse(eval($4 < array_get(`$1', `length')), 1,
`array2_set(`$3', `$4', `x', array_get(`$1', `$4'))dnl
array2_set(`$3', `$4', `y', array_get(`$2', `$4'))dnl
_form_points(`$1', `$2', `$3', incr($4))dnl
'dnl
)'dnl
)
dnl show_points(points_varname):
dnl for i = 0 to points_varname["length"] - 1
dnl Output "(" + points_varname[i]["x"] + ", " + points_varname[i]["y"] + ")"
define(`show_points', `_show_points(`$1', 0)')
dnl points_varname=$1, i=$2
define(`_show_points',
`ifelse(eval($2 < array_get(`$1', `length')), 1,
`(array2_get(`$1', `$2', `x'), array2_get(`$1', `$2', `y'))
_show_points(`$1', incr($2))dnl
'dnl
)'dnl
)
dnl Find Convex Hull using Jarvis' algorithm
dnl Source: https://www.geeksforgeeks.org/convex-hull-using-jarvis-algorithm-or-wrapping/
dnl convex_hull(points_varname, hull_points_varname):
dnl // The first point is the leftmost point with the highest y-coord in the
dnl // event of a tie
dnl l = find_leftmost_point(points_varname)
dnl
dnl // Repeat until wrapped around to first hull point
dnl p = l
dnl i = 0
dnl do
dnl // Store convex hull point
dnl hull_points_varname[i]["x"] = points_varname[p]["x"]
dnl hull_points_varname[i]["y"] = points_varname[p]["y"]
dnl i = i + 1
dnl hull_points_varname["length"] = i
dnl
dnl q = (p + 1) % points_varname["length"]
dnl for j = 0 to points_varname["length"] - 1:
dnl // If point j is counter-clockwise, then update end point (q)
dnl if orientation(points_varname, p, j, q) < 0:
dnl q = j
dnl
dnl p = q
dnl while p != l
define(`convex_hull',
`pushdef(`l', `find_leftmost_point(`$1')')dnl
pushdef(`p', l)dnl
pushdef(`q', `')dnl
_convex_hull_outer(`$1', `$2', 0)dnl
popdef(`q')dnl
popdef(`p')dnl
popdef(`l')dnl
'dnl
)
dnl points_varname=$1, hull_points_varname=$2, i=$3
define(`_convex_hull_outer',
`array2_set(`$2', `$3', `x', array2_get(`$1', p, `x'))dnl
array2_set(`$2', `$3', `y', array2_get(`$1', p, `y'))dnl
array_set(`$2', `length', incr($3))dnl
define(`q', eval((p + 1) % array_get(`$1', `length')))dnl
_convex_hull_inner(`$1', 0)dnl
define(`p', q)dnl
ifelse(eval(p != l), 1, `_convex_hull_outer(`$1', `$2', incr($3))')dnl
'dnl
)
dnl points_varname=$1, j=$2
define(`_convex_hull_inner',
`ifelse(eval($2 < array_get(`$1', `length')), 1,
`ifelse(eval(orientation(`$1', p, `$2', q) < 0), 1, `define(`q', `$2')')dnl
_convex_hull_inner(`$1', incr($2))dnl
'dnl
)'dnl
)
dnl Get orientation of three points
dnl
dnl 0 = points are in a line
dnl > 0 = points are clockwise
dnl < 0 = points are counter-clockwise
dnl orientation(points_varname, p, q, r):
dnl return (points_varname[q]["y"] - points_varname[p]["y"]) *
dnl (points_varname[r]["x"] - points_varname[q]["x"]) -
dnl (points_varname[q]["x"] - points_varname[p]["x"]) *
dnl (points_varname[r]["y"] - points_varname[q]["y"])
define(`orientation',
`eval(
(array2_get(`$1', `$3', `y') - array2_get(`$1', `$2', `y')) *
(array2_get(`$1', `$4', `x') - array2_get(`$1', `$3', `x')) -
(array2_get(`$1', `$3', `x') - array2_get(`$1', `$2', `x')) *
(array2_get(`$1', `$4', `y') - array2_get(`$1', `$3', `y'))
)'dnl
)
dnl M4 does not have infinity so choose smallest integer value as minus infinity
dnl and the largest integer value for infinity
define(`MINUS_INF', -2147483648)
define(`INF', 2147483647)
dnl find_leftmost_point(points_varname):
dnl x_min = INF
dnl y_max = MINUS_INF
dnl min_idx = -1
dnl for i = 0 to points_varname["length"] - 1:
dnl if points_varname[i]["x"] < x_min or
dnl (points_varname[i]["x"] == x_min and points_varname[i]["y"] > y_max):
dnl x_min = points_varname[i]["x"]
dnl y_max = points_varname[i]["y"]
dnl min_idx = i
dnl return min_idx
define(`find_leftmost_point', `_find_leftmost_point(`$1', INF, MINUS_INF, -1, 0)')
dnl points_varname=$1, x_min=$2, y_max=$3, min_idx=$4, i=$5
define(`_find_leftmost_point',
`ifelse(eval($5 >= array_get(`$1', `length')), 1, `$4',
`ifelse(eval(array2_get(`$1', `$5', `x') < $2 ||
(array2_get(`$1', `$5', `x') == $2 && array2_get(`$1', `$5', `y') > $3)), 1,
`_find_leftmost_point(`$1', array2_get(`$1', `$5', `x'), array2_get(`$1', `$5', `y'), $5, incr($5))',
`_find_leftmost_point(`$1', `$2', `$3', `$4', incr($5))'dnl
)'dnl
)'dnl
)
divert(0)dnl
ifelse(eval(ARGC < 2 ||
!parse_int_list(`x_values', ARGV1) ||
!parse_int_list(`y_values', ARGV2)
), 1, `show_usage()')dnl
ifelse(eval(array_get(`x_values', `length') < 3 ||
array_get(`y_values', `length') < 3 ||
array_get(`x_values', `length') != array_get(`y_values', `length')
), 1, `show_usage()')dnl
form_points(`x_values', `y_values', `points')dnl
convex_hull(`points', `hull_points')dnl
show_points(`hull_points')dnl
Convex Hull in M4 was written by:
If you see anything you'd like to change or update, please consider contributing.
No 'How to Implement the Solution' section available. Please consider contributing.
No 'How to Run the Solution' section available. Please consider contributing.