using NLsolve
function nls(func, params...; ini = [0.0])
if typeof(ini) <: Number
r = nlsolve( (vout, vin) -> vout[1] = func(vin[1], params..., [ini]), ftol=big"1e-40")
v = r.zero[1]
else
r = nlsolve( (vout, vin)->vout .= func(vin, params...), ini, ftol=big"1e-40")
v = r.zero
end
return Float64.(v), r.f_converged
end;
using Plots
using Printf
using SymPy
##################
function segment(x1, y1, x2, y2, color=:black; linestyle=:solid, lw=0.5)
plot!([x1, x2], [y1, y2], color=color; linestyle=linestyle, lw=lw)
end;
##################
function abline(x0, y0, slope, minx, maxx, color=:black; lw=0.5)
f(x) = slope * (x - x0) + y0
segment(minx, f(minx), maxx, f(maxx), color; lw=lw)
end;
##################
function intersectionXY(x1, y1, x2, y2, x3, y3, x4, y4)
denominator = (x1*y3 - x1*y4 - x2*y3 + x2*y4 - x3*y1 + x3*y2 + x4*y1 - x4*y2)
X = (x1*x3*y2 - x1*x3*y4 - x1*x4*y2 + x1*x4*y3 - x2*x3*y1 + x2*x3*y4 + x2*x4*y1 - x2*x4*y3) / denominator
Y = (x1*y2*y3 - x1*y2*y4 - x2*y1*y3 + x2*y1*y4 - x3*y1*y4 + x3*y2*y4 + x4*y1*y3 - x4*y2*y3) / denominator
(X, Y)
end
##################
function distance(x1, y1, x2, y2, x0, y0)
p1, p2 = sympy.Point(x1, y1), sympy.Point(x2, y2)
l = sympy.Line(p1, p2)
l.distance(sympy.Point(x0, y0))^2 # 二乗距離を返す!!
end;
function dist(x1, y1, x2, y2, x0, y0; point=false)
# @syms dx, dy, line_length, vx, vy, projection_length, nearest_point_x, nearest_point_y
# 直線の方向ベクトル
dx = x2 - x1
dy = y2 - y1
# 直線の長さ
line_length = sqrt(dx^2 + dy^2)
# 直線上の点までのベクトル
vx = x0 - x1
vy = y0 - y1
# 直線上の点までの射影ベクトルの長さ
projection_length = (vx * dx + vy * dy) / line_length
# 直線上の最近点の座標
nearest_point_x = x1 + (projection_length * dx) / line_length
nearest_point_y = y1 + (projection_length * dy) / line_length
if point
# 直線上の最近点の座標を返す
return (nearest_point_x, nearest_point_y)
else
# 点 (x0, y0) から直線までの二乗距離を返す
return (x0 - nearest_point_x)^2 + (y0 - nearest_point_y)^2
end
end;
function dist2(x1, y1, x2, y2, x0, y0, r)
@syms dummy_temp
return numerator(apart(dist(x1, y1, x2, y2, x0, y0) - r^2, dummy_temp)) |> simplify# |> simplify
end;
#### 垂線の脚の座標
foot(x1, y1, x2, y2, x0, y0) = dist(x1, y1, x2, y2, x0, y0; point=true)
##################
#### 射影(回転)
function transform(x, y; deg=0, dx=0, dy=0)
(x, y) = [cosd(deg) -sind(deg); sind(deg) cosd(deg)] * [x, y]
return (x .+ dx, y .+ dy)
end;
function circle(ox, oy, r, color=:red; beginangle=0, endangle=360, by=0.5, n=0, lw=0.5)
n != 0 && (by = (endangle - beginangle) / n)
θ = beginangle:by:endangle
x = r.*cosd.(θ)
y = r.*sind.(θ)
plot!(ox .+ x, oy .+ y, color=color, linewidth=lw)
end;
#### 回転角度を指定して複数個描く
#### 回転の中心座標 (center_x, center_y) を指定できるようにした 25/07/12
function rotate(ox, oy, r, color=:red; center_x=0, center_y=0, angle=120, beginangle=0, endangle=360, lw=0.5, by=0.5, n=0)
ox -= center_x
oy -= center_y
for deg in 0:angle:360-1
(ox2, oy2) = [cosd(deg) -sind(deg); sind(deg) cosd(deg)] * [ox; oy]
circle(ox2 + center_x, oy2 + center_y, r, color; beginangle, endangle, by, n, lw=0.5)
beginangle += angle
endangle += angle
end
end;
function rotatef(ox, oy, r, color=:red; center_x=0, center_y=0, angle=120, beginangle=0, endangle=360, lw=0.5, by=0.5, n=0)
ox -= center_x
oy -= center_y
for deg in 0:angle:360-1
(ox2, oy2) = [cosd(deg) sind(deg); -sind(deg) cosd(deg)] * [ox; oy]
circlef(ox2 + center_x, oy2 + center_y, r, color; beginangle, endangle, by, n)
end
end;
##### 2 個描く
function circle2(x, y, r, color=:red)
circle(x, y, r, color)
circle(-x, y, r, color)
end;
##### 2 個描く
function circle2f(x, y, r, color=:red)
circlef(x, y, r, color)
circlef(-x, y, r, color)
end;
##### 2 個描く --2
function circle22(x, y, r, color=:red)
circle(x, y, r, color)
circle(x, -y, r, color)
end;
##### 2 個描く --2
function circle22f(x, y, r, color=:red)
circlef(x, y, r, color)
circlef(x, -y, r, color)
end;
##### 4 個描く
function circle4(x, y, r, color=:red)
circle(x, y, r, color)
circle(x, -y, r, color)
circle(-x, y, r, color)
circle(-x, -y, r, color)
end;
##### 4 個描く
function circle4f(x, y, r, color=:red)
circlef(x, y, r, color)
circlef(x, -y, r, color)
circlef(-x, y, r, color)
circlef(-x, -y, r, color)
end;
##### 4 個描く --2
function circle42(x, y, r, color=:red)
circle(x, y, r, color)
circle(x, -y, r, color)
circle(y, -x, r, color)
circle(-y, -x, r, color)
end;
##### 4 個描く --2
function circle42f(x, y, r, color=:red)
circlef(x, y, r, color)
circlef(x, -y, r, color)
circlef(y, -x, r, color)
circlef(-y, -x, r, color)
end;
# 塗りつぶしバージョン
function circlef(ox, oy, r, color=:red; beginangle=0, endangle=360, by=0.5, n=0)
n != 0 && (by = (endangle - beginangle) / n)
θ = beginangle:by:endangle
x = r.*cosd.(θ)
y = r.*sind.(θ)
plot!(ox .+ x, oy .+ y, linecolor=color, linewidth=0.5, seriestype=:shape, fillcolor=color)
end;
# アノテーション
function point(x, y, string="", color=:green, position=:left, vertical=:top; fontsize=10, mark=true, delta=0, deltax=0)
mark && scatter!([x], [y], color=color, markerstrokewidth=0, markersize=3)
annotate!(x + deltax, y + delta, text(string, fontsize, position, color, vertical))
end;
##################
function dimension_line(x1, y1, x2, y2, str="", color=:black, position=:center, vertical=:vcenter; linestyle=:solid, lw=0.5, deltax=0, delta=0)
plot!([x1, x2], [y1, y2], color=color; arrow=:arrow, linestyle=linestyle, lw=lw)
plot!([x2, x1], [y2, y1], color=color; arrow=:arrow, linestyle=linestyle, lw=lw)
annotate!( (x1 + x2)/2 + deltax, (y1 + y2)/2 + delta, text(str, position, color, vertical, 10))
end;
function dimension_line(x1, y1, x2, y2, str="", color=:black, position=:center, vertical=:vcenter; dx=0, dy=0, length=0.2, α=π/12, lw=0.5, deltax=0, delta=0)
# 寸法線(中心の直線部分)
plot!(dx .+ [x1, x2], dy .+ [y1, y2], color=color, lw=lw, label="")
# 矢印の向きを求める
θ = atan(y2 - y1, x2 - x1) # 線分の傾き
# 矢印の端点を計算
arrow1_x = x1 + length * cos(θ - α)
arrow1_y = y1 + length * sin(θ - α)
arrow2_x = x1 + length * cos(θ + α)
arrow2_y = y1 + length * sin(θ + α)
arrow3_x = x2 + length * cos(θ + π - α)
arrow3_y = y2 + length * sin(θ + π - α)
arrow4_x = x2 + length * cos(θ + π + α)
arrow4_y = y2 + length * sin(θ + π + α)
# 矢印を描画
plot!(dx .+ [arrow1_x, x1, arrow2_x], dy .+ [arrow1_y, y1, arrow2_y], color=color, lw=lw, label="")
plot!(dx .+ [arrow3_x, x2, arrow4_x], dy .+ [arrow3_y, y2, arrow4_y], color=color, lw=lw, label="")
# 寸法などを記入
annotate!( (x1 + x2)/2 + dx + deltax, (y1 + y2)/2 + dy + delta, text(str, position, color, vertical, 10))
end;
# 矩形
function rect(x1, y1, x2, y2, color=:pink; fill=false)
if fill == false
plot!([x1, x2, x2, x1, x1], [y1, y1, y2, y2, y1], color=color, linewidth=0.5)
else
plot!([x1, x2, x2, x1, x1], [y1, y1, y2, y2, y1], color=color, linewidth=0.5, seriestype=:shape, fillcolor=color)
end
end;
# 楕円
function ellipse(ox, oy, ra, rb; φ=0, beginangle=0, endangle=360,
color=:black, lty=:solid, lw=0.5, fcolor="")
"""
(ox, oy) を中心,ra, rb を半径とする楕円(楕円弧)。
fcolor を指定すると塗りつぶし。
"""
θ = beginangle:0.1:endangle
if φ == 0
if fcolor == ""
plot!(ra .* cosd.(θ) .+ ox, rb .* sind.(θ) .+ oy,
linecolor=color, linestyle=lty, linewidth=lw)
else
plot!(ra .* cosd.(θ) .+ ox, rb .* sind.(θ) .+ oy,
linecolor=color, linestyle=lty, linewidth=lw,
seriestype=:shape, fillcolor=fcolor)
end
else
x = ra .* cosd.(θ)
y = rb .* sind.(θ)
cosine = cosd(φ)
sine = sind(φ)
if fcolor == ""
plot!(cosine .* x .- sine .* y .+ ox,
sine .* x .+ cosine .* y .+ oy,
linecolor=color, linestyle=lty, linewidth=lw)
else
plot!(cosine .* x .- sine .* y .+ ox,
sine .* x .+ cosine .* y .+ oy,
linecolor=color, linestyle=lty, linewidth=lw,
seriestype=:shape, fillcolor=fcolor)
end
end
end;
#=
引数
楕円の長径 a,短径 b,接線の傾き(符号に注意)
戻り値
接点の座標 (x, y),楕円に外接する円の半径 r
func(a, b, tanθ) = (-a^2*tanθ/sqrt(a^2*tanθ^2 + b^2), b^2/sqrt(a^2*tanθ^2 + b^2), -b + sqrt(a^2*tanθ^2 + b^2));
=#;
##### 多角形の面積
function area(xy)
x = xy[:, 1]
sum( (vcat(x[2:end], x[1]) - vcat(x[end], x[1:end-1])) .* xy[:, 2]) / 2
end;
##### 二直線の交点座標
function intersection(x1, y1, x2, y2, x3, y3, x4, y4)
p1, p2, p3, p4 = sympy.Point(x1, y1), sympy.Point(x2, y2), sympy.Point(x3, y3), sympy.Point(x4, y4)
l1, l2 = sympy.Line(p1, p2), sympy.Line(p3, p4)
a = l1.intersection(l2)[1]
(a.x, a.y)
end;
##### 楕円に内接する円の中心座標
function getd(a, b, r; x0 = 0, y0 = 0)
d = sqrt( (a^2 - b^2)*(b^2 - r^2))/b
x = a^2*d/(a^2 - b^2)
y = sqrt(r^2 - (x - d)^2)
return (d, x, y)
end;
##### 楕円に内接する円の半径
function getr(a, b, d; x0 = 0, y0 = 0)
r = b*sqrt( (a^2 - b^2 - d^2)/( (a^2 - b^2)))
x = a^2*d/(a^2 - b^2)
y = sqrt(r^2 - (x - d)^2)
return (r, x, y)
end;
##### 曲率円の半径
geth(a, b) = b^2/a;
##### 外心を計算する関数
function circumcenter(x1, y1, x2, y2, x3, y3)
D = 2 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2))
x_o = ( (x1^2 + y1^2) * (y2 - y3) + (x2^2 + y2^2) * (y3 - y1) + (x3^2 + y3^2) * (y1 - y2)) / D
y_o = ( (x1^2 + y1^2) * (x3 - x2) + (x2^2 + y2^2) * (x1 - x3) + (x3^2 + y3^2) * (x2 - x1)) / D
r = sqrt( (x1 - x_o)^2 + (y1 - y_o)^2)
return r, x_o, y_o
end;
##### 内心を計算する関数
function incenter(x1, y1, x2, y2, x3, y3)
a = sqrt( (x2 - x3)^2 + (y2 - y3)^2)
b = sqrt( (x1 - x3)^2 + (y1 - y3)^2)
c = sqrt( (x1 - x2)^2 + (y1 - y2)^2)
x_i = (a * x1 + b * x2 + c * x3) / (a + b + c)
y_i = (a * y1 + b * y2 + c * y3) / (a + b + c)
r = sqrt(distance(x1, y1, x2, y2, x_i, y_i))
return r, x_i, y_i
end;
##### 正多角形を描く関数
# (ox, oy) を中心,r を半径とする円に内接する正 n 多角形。fcol を指定すると塗りつぶし。
function polygon(ox, oy, r, n; φ=90, color=:black, lty=:solid, lw=0.5, fcolor="")
θ = range(0, 2π, length=n+1) .+ φ / 180 * π
if fcolor == ""
plot!(r .* cos.(θ) .+ ox, r .* sin.(θ) .+ oy,
linecolor=color, linestyle=lty, linewidth=lw)
else
plot!(r .* cos.(θ) .+ ox, r .* sin.(θ) .+ oy,
linecolor=color, linestyle=lty, linewidth=lw,
seriestype=:shape, fillcolor=fcolor)
end
end;
##### 直線と円の交点座標(2つあることを前提とする)
# 半径が r,中心座標が (x, y) の円と,
# 二点 (x1, y1), (x2, y2) を結ぶ直線が 2 点で交わるとき,
# 交点座標のセット (x3, y3), (x4, y4) を求める関数
function intersection2(r, x, y, x1, y1, x2, y2)
# 直線をベクトル表示
dx = x2 - x1
dy = y2 - y1
# 円の中心を原点に平行移動
fx = x1 - x
fy = y1 - y
# 2次方程式 at² + bt + c = 0 を作る
a = dx^2 + dy^2
b = 2 * (fx * dx + fy * dy)
c = fx^2 + fy^2 - r^2
# 判別式(2点交差前提なので省略してもよい)
D = b^2 - 4a*c
# 解の計算(2点分)
sqrtD = sqrt(D)
t1 = (-b + sqrtD) / (2a)
t2 = (-b - sqrtD) / (2a)
# パラメトリック直線上の点を計算
x3 = x1 + t1 * dx
y3 = y1 + t1 * dy
x4 = x1 + t2 * dx
y4 = y1 + t2 * dy
return (x3, y3, x4, y4)
end;