・問題文は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>計測>角度計算 です。
角度寸法の表示は、勉強中です。

(いつもと違って本日の)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
いつもの? sympyの実行環境と 参考のおすすめです。
いつもと違うおすすめです。
