0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オフセット「Sympy で線分のオフセットのユーザー定義関数を教えて下さい。おすすめで。」をsympyでAI先生に教えてもらいました。

0
Posted at

・私は、今まで意識していなかったのが、不思議?でした。

(本日の)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. コピーできる様式で

いつもと違うおすすめです。

wikipedia

Qiita内

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?