・私は、今まで意識していなかったのが、不思議?でした。
(本日の)Gemini先生へ
Sympy で線分のオフセットのユーザー定義関数を教えて下さい。おすすめで。
(途中省略。最後の Point2D. rotate() がおすすめです。)
# SymPy を用いた 2D 線分のオフセット計算関数
from sympy import Point2D, Segment2D, symbols, simplify
def offset_segment(segment: Segment2D, d):
"""
2次元線分を指定した距離 d だけ垂直方向に平行移動(オフセット)します。
Parameters:
-----------
segment : Segment2D
対象の線分
d : int | float | Symbol
オフセット距離(正の数: 進行方向に対して左側、負の数: 右側)
Returns:
--------
Segment2D
オフセット後の線分
"""
p1, p2 = segment.p1, segment.p2
dx = p2.x - p1.x
dy = p2.y - p1.y
length = segment.length
# 進行方向から90度左に回転させた法線単位ベクトル (-dy/L, dx/L)
nx = -dy / length
ny = dx / length
# 各端点を法線方向に d 移動
p1_off = Point2D(simplify(p1.x + d * nx), simplify(p1.y + d * ny))
p2_off = Point2D(simplify(p2.x + d * nx), simplify(p2.y + d * ny))
return Segment2D(p1_off, p2_off)
使用例 1. 数値座標での使用
# 数値での実行例
p1 = Point2D(0, 0)
p2 = Point2D(4, 0)
seg = Segment2D(p1, p2)
# 左側に距離 2 だけオフセット
seg_off = offset_segment(seg, 2)
print("元の線分:", seg)
print("オフセット後の線分:", seg_off)
# 出力: Segment2D(Point2D(0, 2), Point2D(4, 2))
使用例 2. 記号(シンボル)を使った計算
# 文字変数を含めた計算例
x, y, d = symbols('x y d')
seg_sym = Segment2D(Point2D(0, 0), Point2D(x, y))
seg_sym_off = offset_segment(seg_sym, d)
print("始点:", seg_sym_off.p1)
print("終点:", seg_sym_off.p2)
おすすめのユーザー定義関数
# SymPy を用いた 2D 線分(点 p1, p2)のオフセット計算関数
from sympy import Point2D, simplify
def offset_segment_points(p1, p2, d):
"""
点 p1 から p2 への線分を指定した距離 d だけ垂直方向に平行移動(オフセット)します。
Parameters:
-----------
p1, p2 : Point2D | tuple | list
始点と終点((x, y) 形式のタプルや Point2D)
d : int | float | Symbol
オフセット距離(正の数: 進行方向に対して左側、負の数: 右側)
Returns:
--------
tuple[Point2D, Point2D]
オフセット後の (始点, 終点)
"""
# tuple や list が渡された場合も Point2D に変換
p1, p2 = Point2D(p1), Point2D(p2)
dx = p2.x - p1.x
dy = p2.y - p1.y
length = p1.distance(p2)
# 進行方向から90度左に回転させた法線単位ベクトル (-dy/L, dx/L)
nx = -dy / length
ny = dx / length
# 各端点を法線方向に d 移動
p1_off = Point2D(simplify(p1.x + d * nx), simplify(p1.y + d * ny))
p2_off = Point2D(simplify(p2.x + d * nx), simplify(p2.y + d * ny))
return p1_off, p2_off
使用例
from sympy import Point2D, symbols
# 1. タプルで渡す場合
p1_off, p2_off = offset_segment_points((0, 0), (4, 0), 2)
print("オフセット後 p1:", p1_off) # Point2D(0, 2)
print("オフセット後 p2:", p2_off) # Point2D(4, 2)
# 2. Point2D で渡す場合
p1 = Point2D(0, 0)
p2 = Point2D(0, 5)
p1_off, p2_off = offset_segment_points(p1, p2, 1)
print("オフセット後 p1:", p1_off) # Point2D(-1, 0)
print("オフセット後 p2:", p2_off) # Point2D(-1, 5)
# 3. 記号(シンボル)を含める場合
x, y, d = symbols('x y d')
p1_off, p2_off = offset_segment_points((0, 0), (x, y), d)
print("記号での結果:", p1_off)
SymPy の Point2D.angle() と rotate() を使用した線分オフセット計算関数
# 1行目に適切なコメントを配置
# SymPy の Point2D.angle() と rotate() を使用した線分オフセット計算関数
from sympy import Point2D, pi, simplify
def offset_segment_points(p1, p2, d):
"""
点 p1 から p2 への線分を指定した距離 d だけ垂直方向に平行移動(オフセット)します。
Parameters:
-----------
p1, p2 : Point2D | tuple | list
始点と終点((x, y) 形式のタプルや Point2D)
d : int | float | Symbol
オフセット距離(正の数: 進行方向に対して左側、負の数: 右側)
Returns:
--------
tuple[Point2D, Point2D]
オフセット後の (始点, 終点)
"""
# tuple や list が渡された場合も Point2D に変換
p1, p2 = Point2D(p1), Point2D(p2)
# p1 から p2 への方向ベクトルとその角度 (angle) を取得
vec = p2 - p1
theta = vec.angle()
# 進行方向から 90度 (pi/2) 回転させた方向への移動オフセット点を作成
# 原点 (0, 0) から 角度 (theta + pi/2) 方向に 距離 d 進んだ点
offset_vec = Point2D(d, 0).rotate(theta + pi/2)
# 各端点にオフセットベクトルを加算
p1_off = Point2D(simplify(p1.x + offset_vec.x), simplify(p1.y + offset_vec.y))
p2_off = Point2D(simplify(p2.x + offset_vec.x), simplify(p2.y + offset_vec.y))
return p1_off, p2_off
使用例
from sympy import Point2D
# (0, 0) から (4, 0) への線分を左側に 2 オフセット
p1_off, p2_off = offset_segment_points((0, 0), (4, 0), 2)
print("オフセット後 p1:", p1_off) # Point2D(0, 2)
print("オフセット後 p2:", p2_off) # Point2D(4, 2)
履歴
1. Sympy で線分のオフセットのユーザー定義関数を教えて下さい。おすすめで。
2. Segment じゃなくp1,p2でお願いします。
3. ありがとうございました。
4. ソースコードを法線の単位ベクトルでなく、Pointのangleオプションに変更して下さい。
5. Rotateでした。ありがとうございました。
6. 上記の私の質問すべてから、Markdownのテキスト形式で、質問リストを出力して。追番を追加して。本質問も含めて。コピーできる形式で。空白行不要です。
7. コピーできる様式で