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?

メネラウスの定理。大人用「2024 青森公立大学前期【4】」(その3/4)をAI先生へ。sympyのいつもの方法で。

0
Last updated at Posted at 2025-11-06

(その1/4)
(その2/4)
(その3/4) 本ページ
(その4/4)

・問題文は2次元ですが、3次元FreeCADのマクロで、XY平面に作図しました。

(再出)オリジナル

(再出)web

数学入試問題 様へ。いつもお世話になっております。
https://kamelink.com/blog/2024/04/18/4-6-24-aomorikoritsudai-4/

sympyで(webオリジナル 様の方法を参考に)

ver2.0

・自力で?力技?
・>△ABC でチェバの定理を用いると... 
・>△AFC と直線 PE でメネラウスの定理を用いると...

# ver2.0
from sympy import *
var('BF_FC,AP_PF')
var('S,SA,SB,SC')
AB,CA=8,5
AD,CE=3,2
EA   =CA-CE
DB   =AB-AD
BF_FC=solve(Eq(BF_FC*CE/EA*AD/DB                                   ,1),BF_FC)[0]              #;print(BF_FC)
AP_PF=solve(Eq(AP_PF*numer(BF_FC)/(numer(BF_FC)+denom(BF_FC))*CE/EA,1),AP_PF)[0]               ;print("#",AP_PF)
DEF  =(S-(SA+SB+SC)).subs({SA:Rational(AD,AB)*Rational(AD,CA)                         *S, \
                           SB:Rational(CA,AB)*numer(BF_FC)/(numer(BF_FC)+denom(BF_FC))*S, \
                           SC:Rational(denom(BF_FC),denom(BF_FC)+numer(BF_FC))*Rational(CE,CA)                         *S  \
                          })                                                                
print("#",DEF.subs({S:Rational(1,2)*AB*CA*sin(60*pi/180)}))
# 21/10
# 15*sqrt(3)/7

sympyで(いつもの方法で)

ver3.0

・自力で?力技?
・trABCのBCを水平になるように回転して、trBCAを再定義しています。

# ver3.0
from sympy import *
AB,CA=8,5
AD,CE=3,2
trABC=Triangle(sas=(CA,60,AB))                   #;print(trABC)
BC   =trABC.args[1].distance(trABC.args[2])      #;print(BC)
trBCA=Triangle(sss=(BC,CA,AB))                   #;print(trBCA)
A,B,C=trBCA.args[2],trBCA.args[0],trBCA.args[1]
D    =A+AD*(B-A).unit
E    =C+CE*(A-C).unit
P    =Line(B,E).intersection(Line(C,D))[0]       #;print(P)
F    =Line(A,P).intersection(Line(B,C))[0]       #;print(F)
print("#",A.distance(P)/P.distance(F))
print("#",abs(Triangle(D,E,F).area))
# 21/10
# 15*sqrt(3)/7

(いつもの)FreeCADのマクロで作図

・自力で?力技?
・問題文は2次元ですが、3次元FreeCADのマクロで、XY平面に作図しました。
・計算部分は、Ver.3.0 のコピー貼り付けです。

# 以下でます。 
# この機能は非推奨です。この機能を直接使用しないでください。
#   「make_linear_dimension」または「make_linear_dimension_obj」のいずれかを使用してください。
import FreeCAD
import Part
import DraftTools
import Draft
import Mesh
############################################################################
# ver3.0
from sympy import *
AB,CA=8,5
AD,CE=3,2
trABC=Triangle(sas=(CA,60,AB))                   #;print(trABC)
BC   =trABC.args[1].distance(trABC.args[2])      #;print(BC)
trBCA=Triangle(sss=(BC,CA,AB))                   #;print(trBCA)
A,B,C=trBCA.args[2],trBCA.args[0],trBCA.args[1]
D    =A+AD*(B-A).unit
E    =C+CE*(A-C).unit
P    =Line(B,E).intersection(Line(C,D))[0]       #;print(P)
F    =Line(A,P).intersection(Line(B,C))[0]       #;print(F)
print("#",A.distance(P)/P.distance(F))
print("#",abs(Triangle(D,E,F).area))
# 21/10
# 15*sqrt(3)/7
############################################################################
#B,C,A=BCA.args[0],BCA.args[1],BCA.args[2]
#E,D   =                   BED.args[1],BED.args[2]  
#F      =BCA.intersection(BED) [2]       ;print(F)
# F=Point(0,0)
############################################################################
# 3D作図 z=0 XY平面に作図しました。
# 2024-10-08 fontsize 追加しました。従来と互換性がありません。 
# 2024-10-20 HR 
# 2025-03-27 HL
# 2025-10-09 ChatGPT先生より\\\\\
#    dimension.ViewObject.ShowUnit     = False   # プロパティで単位を表示しないように設定
#    dimension.ViewObject.Decimals     = 0 
############################################################################
def myDimension(fontsize,myExtOvershoot,start_point, end_point,HVP):
    x1, y1 = start_point.args
    x2, y2 = end_point.args
    myFlipText = True
    if HVP=="PL":
       myP1  =Point(float(x1),float(y1))
       myP2  =Point(float(x2),float(y2))
       myFlipText = False
       myExtOvershoot1=abs(myExtOvershoot)
    elif HVP=="PR":
       myP1  =Point(float(x1),float(y1))
       myP2  =Point(float(x2),float(y2))
       myFlipText = False
       myExtOvershoot1=-abs(myExtOvershoot)
    elif HVP=="VL":
       if x1<x2 and y1<y2:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x1),float(y2))
          myExtOvershoot1= abs(myExtOvershoot)
          myFlipText = False
       elif x1<x2 and y1>y2:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x1),float(y2))
          myExtOvershoot1=-abs(myExtOvershoot)
       elif x1>x2 and y1<y2:
          myP1  =Point(float(x2),float(y1))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1= abs(myExtOvershoot)
          myFlipText = False
       else:
          myP1  =Point(float(x2),float(y1))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1=-abs(myExtOvershoot)
    elif HVP=="VR":
       if x1<x2 and y1<y2:
          myP1  =Point(float(x2),float(y1))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1=-abs(myExtOvershoot)
          myFlipText = False
       elif x1<x2 and y1>y2:
          myP1  =Point(float(x2),float(y1))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1= abs(myExtOvershoot)
       elif x1>x2 and y1<y2:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x1),float(y2))
          myExtOvershoot1=-abs(myExtOvershoot)
       else:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x1),float(y2))
          myExtOvershoot1= abs(myExtOvershoot)
    elif HVP=="HL":
       if x1 < x2 and y1<y2:
          myP1  =Point(float(x1),float(y2))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1= abs(myExtOvershoot)
          myFlipText = False
       elif x1 < x2 and y1>=y2:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x2),float(y1))
          myExtOvershoot1= abs(myExtOvershoot)
          myFlipText = False
          #myFlipText = True
       elif x1 > x2 and y1<y2:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x2),float(y1))
          myExtOvershoot1= abs(myExtOvershoot)
       else:
          myP1  =Point(float(x1),float(y2))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1= abs(myExtOvershoot)
    elif HVP=="HR":
       #if x1<x2 and y1<y2: # 2024-10-20 HR
       if x1<x2 and y1<=y2:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x2),float(y1))
          myExtOvershoot1=-abs(myExtOvershoot)
          myFlipText = False
       elif x1<x2 and y1>y2:
          myP1  =Point(float(x1),float(y2))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1=-abs(myExtOvershoot)
          myFlipText = False
       elif x1>x2 and y1<y2:
          myP1  =Point(float(x1),float(y2))
          myP2  =Point(float(x2),float(y2))
          myExtOvershoot1=-abs(myExtOvershoot)
       else:
          myP1  =Point(float(x1),float(y1))
          myP2  =Point(float(x2),float(y1))
          myExtOvershoot1=-abs(myExtOvershoot)
    else:  
      print("")
    myM   =myP1.midpoint(myP2)
    myT   =myM+myExtOvershoot1*((myP1-myM).unit).rotate( -pi/2 )
    dimension = Draft.makeDimension(
        FreeCAD.Vector(myP1.x, myP1.y, 0),           # 点1の座標
        FreeCAD.Vector(myP2.x, myP2.y, 0),           # 点2の座標
        FreeCAD.Vector(float(myT.x),float(myT.y),0)  # 矢印の位置を中央に設定
    )
    # Ext Overshootを設定
    dimension.ViewObject.ExtOvershoot = -float(myExtOvershoot)
    dimension.ViewObject.FlipText     = myFlipText

    # 矢印のスタイルを設定
    dimension.ViewObject.ArrowType    = "Arrow"  # 矢印のタイプを "Arrow" に設定
    dimension.ViewObject.ArrowSize    = fontsize/5
    dimension.ViewObject.TextSpacing  = 0
    dimension.ViewObject.LineColor    = (0.0, 1.0, 0.0)  # 緑色
    dimension.ViewObject.FontSize     = fontsize  # フォントサイズを指定
 
    # 2025-10-09 ChatGPT先生より
    dimension.ViewObject.ShowUnit     = False   # プロパティで単位を表示しないように設定
    dimension.ViewObject.Decimals     = 0
    return
def myXYZ2Txt_2D(A):
    return ""
def myXYZ2Txt_XY_2D(A):
    return '(' + str(A.x) + ',' + str(A.y) +  ')'
def myTxtXYZ_2D(fontsize,A,myWedgei):
    P5x=float(A.x)
    P5y=float(A.y)
    P5z=0.0
    p5 = FreeCAD.Vector(P5x, P5y, P5z)
    myText = Draft.makeText(myWedgei, p5)
    myText.Label = myWedgei
    FreeCADGui.ActiveDocument.ActiveObject.FontSize = str(fontsize,)+' mm'
    return
def myTxtXYZ_S_2D(fontsize,*xy_tx):
    for i in range(1,int(len(xy_tx)/2)+1):
        myTxtXYZ_2D(fontsize,xy_tx[2*i-2],xy_tx[2*i-1]+myXYZ2Txt_2D(xy_tx[2*i-2]) )
    return
def myTxtXYZ_XY_S_2D(fontsize,*xy_tx):
    for i in range(1,int(len(xy_tx)/2)+1):
        myTxtXYZ_2D(fontsize,xy_tx[2*i-2],xy_tx[2*i-1]+myXYZ2Txt_XY_2D(xy_tx[2*i-2]) )
    return
def myTxtXYZ_MoveY_2D(fontsize,MoveY,A,myWedgei):
    P5x=float(A.x)
    P5y=float(A.y)+MoveY
    P5z=0.0
    p5 = FreeCAD.Vector(P5x, P5y, P5z)
    myText = Draft.makeText(myWedgei, p5)
    myText.Label = myWedgei
    FreeCADGui.ActiveDocument.ActiveObject.FontSize = str(fontsize,)+' mm'
    return
def myTxtXYZ_XY_S_MoveY_2D(fontsize,MoveY,*xy_tx):
    for i in range(1,int(len(xy_tx)/2)+1):
        myTxtXYZ_MoveY_2D(fontsize,MoveY,xy_tx[2*i-2],xy_tx[2*i-1]+myXYZ2Txt_XY_2D(xy_tx[2*i-2]) )
    return
############################################################################
# 3D作図 z=0 XY平面に作図しました。
############################################################################
def myLine_2D(A,B):
    Ax,Ay,Az=float(A.x),float(A.y),0.0
    Bx,By,Bz=float(B.x),float(B.y),0.0
    pl = FreeCAD.Placement()
    pl.Rotation.Q = (0.4247081540122249, 0.17592004639554645, 0.33985110062924484, 0.8204732460821097)
    pl.Base = FreeCAD.Vector(-3.9166066876399563, -2.1670824762243774, 1.7495260956243028)
    points = [FreeCAD.Vector(Ax,Ay,Az), FreeCAD.Vector(Bx,By,Bz)]
    line = Draft.make_wire(points, placement=pl, closed=False, face=True, support=None)
    Draft.autogroup(line)
    return
def myLine_S_2D(*args):
    for i in range(1,len(args)):
        myLine_2D(args[i-1],args[i])
    return
def myLine_C_2D(*args):
    for i in range(1,len(args)):
        myLine_2D(args[i-1],args[i])
    myLine_2D(args[i],args[0])
    return
def myLine_H_2D(*args):
    for i in range(1,len(args)):
        myLine_2D(args[0],args[i])
    return
##################################################################################
myLine_C_2D(A,D,B,F,C,E)
myLine_S_2D(A,P,F)
myLine_S_2D(C,P,D)
myLine_S_2D(B,P,E)
myFontsize =0.3
myTxtXYZ_XY_S_2D(myFontsize,A,"A",B,"B",C,"C",D,"D",E,"E",F,"F",P,"P")
myOvershoot=myFontsize*9
myDimension(myFontsize,myOvershoot                  ,B,A,"PL")
myDimension(myFontsize,myOvershoot-myFontsize,D,A,"PL")
myDimension(myFontsize,myOvershoot                  ,A,C,"PL")
myDimension(myFontsize,myOvershoot-myFontsize,E,C,"PL")
####################################################################################
doc = App.activeDocument()
#
# 2025-03-27 なんだか調子が悪い
# App.ActiveDocument.addObject("App::Origin", "Origin")
# App.ActiveDocumen!t.getObject('Origin').Visibility = True
origin = doc.addObject("App::Origin", "Origin")
# origin.Visibility = True
#
App.ActiveDocument.recompute()
Gui.activeDocument().activeView().viewAxonometric()
Gui.SendMsgToActiveView("ViewFit")

・(青色の)角度寸法は、CADの操作で追加。Part>計測>角度計算 です。
 角度寸法の表示は、勉強中です。
000.png

(いつもと違って本日の)ChatGPT先生へ。FreeCADのマクロのコンバートを教えて下さい。

質問

以下を作図するFreeCADのマクロを教えて下さい。
(ver3.0ソースコードを省略)

回答

# -*- coding: utf-8 -*-
# ver3.0 FreeCADマクロ
# SymPy版の構成:
# AB=8, CA=5, ∠A=60°, AD=3, CE=2
# P = BE ∩ CD, F = AP ∩ BC

import FreeCAD as App
import Draft, math

doc = App.newDocument("Triangle_Construction")

# --- 与条件 ---
AB, CA = 8, 5
AD, CE = 3, 2
angA = math.radians(60)

# --- 点A, B, C ---
A = App.Vector(0, 0, 0)
B = App.Vector(AB, 0, 0)
# Aから角60°でCA=5の位置にC
C = App.Vector(CA * math.cos(angA), CA * math.sin(angA), 0)

# --- 点D, E ---
D = A + (B - A).normalize().multiply(AD)
E = C + (A - C).normalize().multiply(CE)

# --- 点P = BE ∩ CD ---
def intersection(p1, p2, p3, p4):
    """2直線 p1p2, p3p4 の交点を求める"""
    x1, y1, x2, y2 = p1.x, p1.y, p2.x, p2.y
    x3, y3, x4, y4 = p3.x, p3.y, p4.x, p4.y
    den = (x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)
    if abs(den) < 1e-10:
        return None
    px = ((x1*y2 - y1*x2)*(x3 - x4) - (x1 - x2)*(x3*y4 - y3*x4)) / den
    py = ((x1*y2 - y1*x2)*(y3 - y4) - (y1 - y2)*(x3*y4 - y3*x4)) / den
    return App.Vector(px, py, 0)

P = intersection(B, E, C, D)

# --- 点F = AP ∩ BC ---
F = intersection(A, P, B, C)

# --- 作図 ---
# 三角形ABC
Draft.makeLine(A, B)
Draft.makeLine(B, C)
Draft.makeLine(C, A)

# 補助線
Draft.makeLine(A, P)
Draft.makeLine(B, E)
Draft.makeLine(C, D)

# 点
for p, name in zip([A, B, C, D, E, P, F], ["A", "B", "C", "D", "E", "P", "F"]):
    Draft.makePoint(p)
    Draft.makeText([name], point=p + App.Vector(0.2, 0.2, 0))

App.ActiveDocument.recompute()

# --- 計算出力 ---
AP = (A - P).Length
PF = (P - F).Length
ratio = AP / PF

# 三角形DEFの面積
def tri_area(p1, p2, p3):
    return abs(0.5 * ((p2 - p1).x*(p3 - p1).y - (p2 - p1).y*(p3 - p1).x))

area_DEF = tri_area(D, E, F)

print("# AP/PF =", ratio)
print("# area(DEF) =", area_DEF)

# 結果(理論値):
# AP/PF ≈ 21/10 = 2.1
# 面積 ≈ 15*sqrt(3)/7 ≈ 3.708

・ここであきらめました。続けて、質問すべきでした。
000.png

いつもの? sympyの実行環境と 参考のおすすめです。

(テンプレート)

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

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?