From 2c3a5a31ce5a423232fec1edc58c4031c65f767c Mon Sep 17 00:00:00 2001 From: worthant Date: Tue, 12 Nov 2024 04:04:51 +0300 Subject: [PATCH] :hammer: feat(lib): Working interpolation TODO: work on edge cases and formatting --- lib/cli.ex | 2 ++ lib/input_handler.ex | 7 +++---- lib/linear_interpolator.ex | 25 ++++++++++++++++++++----- lib/output_handler.ex | 10 +++++++--- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/cli.ex b/lib/cli.ex index bcba28f..e65fe0f 100644 --- a/lib/cli.ex +++ b/lib/cli.ex @@ -20,6 +20,8 @@ defmodule InterpolationCli.CLI do end defp read_input do + # IO.write("> ") + case IO.gets("") do :eof -> :ok diff --git a/lib/input_handler.ex b/lib/input_handler.ex index 8d4ab40..6baeb7b 100644 --- a/lib/input_handler.ex +++ b/lib/input_handler.ex @@ -25,11 +25,10 @@ defmodule InterpolationCli.InputHandler do def handle_cast({:add_point, point}, state) do new_state = [point | state] |> Enum.sort_by(fn {x, _y} -> x end) - # Проверяем, есть ли достаточно точек для интерполяции + # Передаём последние две точки для интерполяции if length(new_state) >= 2 do - # Отправляем последние две точки для линейной интерполяции - [p1, p2 | _] = new_state - InterpolationCli.LinearInterpolator.interpolate([p1, p2]) + last_two_points = Enum.take(new_state, -2) + InterpolationCli.LinearInterpolator.interpolate(last_two_points) end {:noreply, new_state} diff --git a/lib/linear_interpolator.ex b/lib/linear_interpolator.ex index 3db6ed4..c2949b6 100644 --- a/lib/linear_interpolator.ex +++ b/lib/linear_interpolator.ex @@ -23,14 +23,29 @@ defmodule InterpolationCli.LinearInterpolator do end @impl true - def handle_cast({:interpolate, [{x1, y1}, {x2, y2}]}, frequency) do - # Генерируем промежуточные точки - step = (x2 - x1) / frequency - xs = Enum.map(0..frequency, fn i -> x1 + i * step end) + def handle_cast({:interpolate, points}, frequency) do + # Получаем последние две точки для интерполяции + [{x1, y1}, {x2, y2}] = Enum.take(points, -2) + + # Шаг интерполяции + step = 1.0 + + # Диапазон интерполяции от x1 до x2 с заданным шагом + xs = Stream.iterate(x1, &(&1 + step)) |> Enum.take_while(&(&1 <= x2 + step)) ys = Enum.map(xs, fn x -> y1 + (y2 - y1) / (x2 - x1) * (x - x1) end) results = Enum.zip(xs, ys) - # Отправляем результаты в OutputHandler + + # Форматированный вывод диапазона с округлением + range_start = Float.round(x1, 2) + range_end = Float.round(x2 + step, 2) + + IO.puts("") + IO.puts( + "Линейная (идем от точки #{range_start} с шагом #{step}, покрывая все введенные X (#{range_end} < #{Float.round(x2, 2)})):" + ) + InterpolationCli.OutputHandler.output(results) + {:noreply, frequency} end diff --git a/lib/output_handler.ex b/lib/output_handler.ex index a01fdeb..86c628d 100644 --- a/lib/output_handler.ex +++ b/lib/output_handler.ex @@ -23,9 +23,13 @@ defmodule InterpolationCli.OutputHandler do @impl true def handle_cast({:output, results}, state) do - Enum.each(results, fn {x, y} -> - IO.puts("#{Float.round(x, 3)}\t#{Float.round(y, 3)}") - end) + xs = Enum.map_join(results, "\t", fn {x, _} -> Float.round(x, 2) end) + ys = Enum.map_join(results, "\t", fn {_, y} -> Float.round(y, 2) end) + + # Вывод X и Y координат + IO.puts(xs) + IO.puts(ys) + IO.puts("") {:noreply, state} end