Le meilleur voyageur qui ne laisse aucune trace
Le meilleur chef qui inspire sans parler
Le plan est parfait, s'il n'y a pas de plan du tout
Et si un sage ferme la porte,
vous ne découvrirez jamais le secret.
Le Grand Livre du Tao - Verset 27 (Traduction par Y. Polezhaeva)
, ! 3D-. 3D. , , - . .
, , CAD-. 3D-. , , . , . , , CAD- 3D " ".
, CAD- OpenCascade. CAD-. , Python.
, . - . - . .
-
, CAD-, . ? , , , 3D-.
, . : " ?" . , , . , , .
. - 3D-. .
1.
OpenCascade . c Win64. , Linux , , .
OpenCascade - Python 3.7 - Win64
, OpenCascade
, conda ( ) , . , . .
2.
. , , .
#initMode = 'screen','web','stl'
def ScInit(initMode, decoration, precision, exportDir):
pass
#default styles
#'stInfo' - for service objects
#'stMain' - for main object of drawing
#'stFocus' - for important details
def ScStyle(styleVal):
pass
#draw objects
def ScPoint(pnt, style):
pass
def ScLine(pnt1, pnt2, style):
pass
def ScCircle(pnt1, pnt2, pnt3, style):
pass
def ScShape(shape, style):
pass
def ScLabel(pnt, text, style):
pass
#start render
def ScStart()
, PythonOCC, OpenCascade (c SWIG) Python-, , , .
3. OpenCASCADE
OpenCascade - . , , . . - . ,
( ) - , , , , .
gp
( - geometry primitives)- , .
Geom
( ) - , , . - (vertex), (edge) , , (wire) - , (face) - , (shell) - , , (solid) - , . , - 3D- . . - , (boundary representation),
BRep
Topo
- , . , , , ,
AIS
).
, .
, . , . Python - . , , , . , , .
OpenCascade OpenCascade . - Google. .
OpenCascade, C++, Tcl, Java. Python.
, . , . , .
. .
4. .
- r
- . . . , - . .
, - , . , . - , . - - , .
( - , , ):
def getPntsBase(r):
r2 = r/2
gpPntMinC = gp_Pnt(0,r2,0)
p0 = gp_Pnt(0,0,0)
p1 = getPntRotate(gpPntMinC , p0, -pi/4)
p2 = gp_Pnt(-r2,r2,0)
p3 = getPntRotate(gpPntMinC , p0, -pi/4*3)
p4 = gp_Pnt(0,r,0)
p5 = gp_Pnt(r,0,0)
p6 = gp_Pnt(0,-r,0)
p7 = gp_Pnt(r2,-r2,0)
return p0, p1, p2, p3, p4, p5, p6, p7
def getWireDaoClassic(ppBase):
p0, p1, p2, p3, p4, p5, p6, p7 = ppBase
arc1 = GC_MakeArcOfCircle(p0,p1,p2).Value()
arc2 = GC_MakeArcOfCircle(p2,p3,p4).Value()
arc3 = GC_MakeArcOfCircle(p4,p5,p6).Value()
arc4 = GC_MakeArcOfCircle(p6,p7,p0).Value()
edge1 = BRepBuilderAPI_MakeEdge(arc1).Edge()
edge2 = BRepBuilderAPI_MakeEdge(arc2).Edge()
edge3 = BRepBuilderAPI_MakeEdge(arc3).Edge()
edge4 = BRepBuilderAPI_MakeEdge(arc4).Edge()
shape = BRepBuilderAPI_MakeWire(edge1, edge2, edge3, edge4).Wire()
return shape
def slide_01_DaoClassic(r):
drawCircle(r, 'stInfo')
pntsBase = getPntsBase(r)
drawPoints(pntsBase, 'stFocus', 'b')
shapeDaoClassic = getWireDaoClassic(pntsBase)
ScShape(shapeDaoClassic, 'stMain')
WebGL-: 01
. 3D- 3D- -. 3D - 1 - - 2 - SideBySide.
- - .
, , 6- , , CAD- . , , - . 3D- , , , .
DegreeToRadian. pi pi, pi/4, -pi/8 . - , , . 9- . - , , - . , .
. 8 , - , . , . - 1 - 1 , 2 - 2 . , , , .
, .
5.
, . . , .
. . Offset
. - .
def getShapeOffset(shape, offset):
tool = BRepOffsetAPI_MakeOffset()
tool.AddWire(shape)
tool.Perform(offset)
shape = tool.Shape()
return shape
def slide_02_DaoConcept(r, offset):
drawCircle(r + offset, 'stInfo')
pntsBase = getPntsBase(r)
wireDaoClassic = getWireDaoClassic(pntsBase)
wireDao0 = getShapeOffset(wireDaoClassic, -offset)
ScShape(wireDao0, 'stMain')
pntsDao0 = getPntsOfShape(wireDao0)
drawPoints(pntsDao0, 'stFocus', 'd')
wireDao1 = getShapeOZRotate(wireDao0, pi)
ScShape(wireDao1, 'stInfo')
WebGL-: 02
, . , . . . - 3D.
6. . .
? , . - . . - , .
, - , . -.
. , , - . . ? , . , Y
-r/4
.
k
. = 0
. k = 1
. . - ( )
def getPntDaoFocus(r):
return gp_Pnt(0,-r/4,0)
def getPntsForDaoSec(pntDaoStart, pntUpLimit, pntDaoEnd, pntDownLimit, pntFocus, k):
angleLimit = 0
pntLimit = getPntScale(pntFocus, pntUpLimit, 1.2)
angleStart = getAngle(pntFocus, pntLimit, pntDaoStart)
angleEnd = getAngle(pntFocus, pntLimit, pntDaoEnd)
kLimit = (angleLimit - angleStart)/(angleEnd - angleStart)
if k < kLimit: #head
kHead = (k - 0) / (kLimit- 0)
xStart = pntUpLimit.X()
xEnd = pntDaoStart.X()
dx = (xEnd-xStart)*(1 - kHead)
pnt0 = getPntTranslate(pntFocus, dx, 0, 0)
pnt1 = getPntTranslate(pntLimit, dx, 0, 0)
else: #tail
kTail = (k - kLimit) / (1 - kLimit)
angle = -angleEnd*kTail
pnt0 = pntFocus
pnt1 = getPntRotate(pntFocus, pntLimit, angle)
return pnt0, pnt1
def getWireDaoSec(shapeDao, pntFocus, k):
pntsDao = getPntsOfShape(shapeDao)
pntDownLimit, pntDaoStart, pntUpLimit, pntDaoEnd = pntsDao
p1, p2 = getPntsForDaoSec(pntDaoStart, pntUpLimit, pntDaoEnd, pntDownLimit,
pntFocus, k)
sectionPlane = getFacePlane(p1, p2, 3)
pnt0, pnt1 = getPntsEdgesFacesIntersect(shapeDao, sectionPlane)
pntUp = getPntSectionUp(pnt0, pnt1)
circle = GC_MakeCircle(pnt0, pntUp, pnt1).Value()
edge = BRepBuilderAPI_MakeEdge(circle).Edge()
wire = BRepBuilderAPI_MakeWire(edge).Wire()
return wire
def slide_03_DaoSecPrincipe(r, offset, k, h):
drawCircle(r + offset, 'stInfo')
pntsBase = getPntsBase(r)
wireDaoClassic = getWireDaoClassic(pntsBase)
wireDao0 = getShapeOffset(wireDaoClassic, -offset)
ScShape(wireDao0, 'stMain')
# for oure goal we need divide Dao on Head and Tail
# Head sections is parallell
# Tail sections is focused on focus point
pntsDao0 = getPntsOfShape(wireDao0)
pntDownLimit, pntDaoStart, pntUpLimit, pntDaoEnd = pntsDao0
# we need focus to determine tail sections
pntFocus = getPntDaoFocus(r)
ScPoint(pntFocus, 'stMain')
ScLabel(pntFocus, 'F' ,'stMain')
# we need two points to determine section
pnt1, pnt2 = getPntsForDaoSec(pntDaoStart, pntUpLimit, pntDaoEnd,
pntDownLimit, pntFocus, k)
ScLine(pnt1, pnt2, 'stFocus')
# !!! we need use plane to detect intercsect (not line) becouse 3D
planeSec = getFacePlane(pnt1, pnt2, h)
ScShape(planeSec, 'stFocus')
pntsSec = getPntsEdgesFacesIntersect(wireDao0, planeSec)
drawPoints(pntsSec, 'stFocus')
wireSec = getWireDaoSec(wireDao0, pntFocus, k)
ScShape(wireSec, 'stFocus')
WebGL-: 03
- . -. , , k
. . , . , .
? - ? , . , 3D . .
2D, . 2D 3D , . , 3D :) 3D .
, 3D-. , - , - , . - .
. . , .
. , , , 3D-. , , , , . , - , , . . 3D- (, ).
( ). ( ), , . , - ( ). . , . . , . . - , - - . . , . , , .
, .
, , . . , k 0 1
c .
def slide_04_DaoManySec(r, offset, kStart, kEnd, cnt):
drawCircle(r + offset, 'stInfo')
pntsBase = getPntsBase(r)
wireDaoClassic = getWireDaoClassic(pntsBase)
wireDao0 = getShapeOffset(wireDaoClassic, -offset)
ScShape(wireDao0, 'stMain')
pntsDao0 = getPntsOfShape(wireDao0)
pntDownLimit, pntDaoStart, pntUpLimit, pntDaoEnd = pntsDao0
pntFocus = getPntDaoFocus(r)
for i in range(cnt+1):
k = i/cnt
kkScale = kEnd - kStart
kk = kStart + k* kkScale
p0,p1 = getPntsForDaoSec(pntDaoStart, pntUpLimit, pntDaoEnd,
pntDownLimit, pntFocus, kk)
ScLine(p0, p1, 'stFocus')
wireSec = getWireDaoSec(wireDao0, pntFocus, kk)
ScShape(wireSec, 'stMain')
WebGL-: 04
. ? ?
, . , . . ( ), ( ).
- , . .
7.
- , . . - . , . - , , , . , .
.
Python , .
, . . .
. , , - . .
def slide_05_DaoSkinning (r, offset):
drawCircle(r + offset, 'stInfo')
pntsBase = getPntsBase(r)
wireDaoClassic = getWireDaoClassic(pntsBase)
wireDao0 = getShapeOffset(wireDaoClassic, -offset)
ScShape(wireDao0, 'stMain')
pntsDao0 = getPntsOfShape(wireDao0)
pntDownLimit, pntDaoStart, pntUpLimit, pntDaoEnd = pntsDao0
pntFocus = getPntDaoFocus(r)
drawPoints(pntFocus, 'stMain')
ks = [ 3, 9 , 16, 24, 35, 50, 70, 85]
wiresSec = []
for k in ks:
wireSec = getWireDaoSec(wireDao0, pntFocus, k/100)
ScShape(wireSec, 'stMain')
wiresSec += [wireSec]
solidDao0 = getShapeSkin(pntDaoStart, wiresSec, pntDaoEnd)
ScShape(solidDao0, 'stFocus')
WebGL-: 05
, . , , . , . - . . - .
. . OpenCascade gp_Trsf
. . . , . . . .
. OpenCascade . . gp_GTrsf
. .
180 ... , pi
... , ... pi
:) .
def getSolidDao(r, offset):
pntsBase = getPntsBase(r)
wireDaoClassic = getWireDaoClassic(pntsBase)
wireDao = getShapeOffset(wireDaoClassic, -offset)
pntsDao = getPntsOfShape(wireDao)
pntDownLimit, pntDaoStart, pntUpLimit, pntDaoEnd = pntsDao
pntFocus = getPntDaoFocus(r)
ks = [ 3, 9 , 16, 24, 35, 50, 70, 85]
wiresSec = []
for k in ks:
wireSec = getWireDaoSec(wireDao, pntFocus, k/100)
wiresSec += [wireSec]
solidDao = getShapeSkin(pntDaoStart, wiresSec, pntDaoEnd)
solidDao = getShapeZScale(solidDao, 0.7)
return solidDao
def slide_06_DaoComplete (r, offset):
solidDao0 = getSolidDao(r, offset)
ScShape(solidDao0, stDao0)
solidDao1 = getShapeOZRotate(solidDao0, pi)
ScShape(solidDao1, stDao1)
WebGL-: 06
8.
, , . .
- . , - . Open Source.
, . , , gap
- - - 1 .
def getDaoCase(r, offset, h):
r2 = r*2
h2 = h/2
rTop = r + offset
rSphere = gp_Vec(0,rTop,h2).Magnitude()
sphere = BRepPrimAPI_MakeSphere(rSphere).Shape()
limit = BRepPrimAPI_MakeBox( gp_Pnt(-r2, -r2, -h2), gp_Pnt(r2, r2, h2) ).Shape()
case = BRepAlgoAPI_Common(sphere, limit).Shape()
case = getShapeTranslate(case, 0,0,-h2)
solidDao0 = getSolidDao(r, offset)
solidDao1 = getShapeOZRotate(solidDao0, pi)
case = BRepAlgoAPI_Cut(case, solidDao0).Shape()
case = BRepAlgoAPI_Cut(case, solidDao1).Shape()
return case
def slide_07_DaoWithCase (r, offset, caseH, caseZMove ,gap):
solidDao0 = getSolidDao(r, offset+gap)
ScShape(solidDao0, stDao0)
solidDao1 = getShapeOZRotate(solidDao0, pi)
ScShape(solidDao1, stDao1)
case = getDaoCase(r, offset, caseH)
case = getShapeTranslate(case, 0,0, caseZMove)
ScShape(case, stCase)
WebGL-: 07
, , - . , , . , .
Open Source
3D--. . :
GitHub - - , .
, OpenCascade. , . . , . . .
Nous devons savoir quand arrêter le
navire ne peut pas être trop rempli des
valeurs grandes sont plus difficiles à garder
et une épée qui est trop forte endommageront plus vite avec un
bon rang trop fier
pour appeler
votre maison à votre maison Votre travail est terminé, donc pouvoir quitter
Tel est le sens de la force, la vie et le chemin.
Le Grand Livre du Tao - Verset 9 (Traduit par Y. Polezhaeva)