wiki:salome

Version 18 (modified by brankm, 6 years ago) (diff)

Vnos slik za primer grafičnega vmesnika.

SALOME

Namestitev

Za namestitev SALOME-a shranite Windows paket SALOME-8.3.0-WIN64.exe ki se nahaja na spodnji povezavi:

http://www.salome-platform.org/downloads/current-version

Odpakirajte Windows paket SALOME-8.3.0-WIN64.exe kot administrator (desni klik --> Run as Administrator) v C:\Program Files.

Program SALOME se zažene s skriptom run_salome.bat ki se nahaja v C:\Program Files\SALOME-8.3.0-WIN64\WORK.

Struktura programa v programskem jeziku Python

Uporabljali bomo navodila za Salome 8.3. Za programiranje v geometrijskem modulu si poglejte Geometry module Python Interface.

V glavi programa je potrebno inicializirati knjižnico salome, ki nam omogoči preprosto manipulacijo predstavljenega objekta (glava dokumenta):

import salome
salome.salome_init()

Nato je potrebno uvoziti python-ov modul GEOM, ki vsebuje funkcije, s katerimi izdelujemo geometrijske modele.

import GEOM
from salome.geom import geomBuilder
geompy = geomBuilder.New(salome.myStudy)

Osnovni program - Izdelava skatle

Funkcija geompy.MakeBox() sprejme koordinate dveh tock, ki lezita na diagonali.

import salome
import GEOM
from salome.geom import geomBuilder
geompy = geomBuilder.New(salome.myStudy)
box =  geompy.MakeBox(10.0,10.0,10.0, 20, 20, 20)
# Dodamo novo spremenljivko v studijo
geompy.addToStudy(box, 'Skatla')
salome.sg.updateObjBrowser(True)

Osnovni program - Primer izdelave izvleka v prostor (Extrusion)

Postopek modeliranja v komercialnih modelirnikih (SolidWorks?, Creo, Catia, NX, ProEngineer?, Inventor,...) je sledeči:

  • izbira ravnine, na katero se nariše skica
  • izris oblike skice (kvadrat)
  • definiranje skice (dimenzije, geometrijske relacije, pozicija v prostoru)
  • izbira ustrezne značilke za izdelavo 3D objekta (Izvlek- Extrude)
  • določitev parametrov izvleka (smer, dolžina izvleka)
  • model je zmodeliran

V okolju Salome poteka izris objekta nekoliko drugače. Razložen je preprosti postopek izdelave kocke, ki poteka v večih korakih. Pri izdelavi je potrebno manualno določiti vse parametre, ki jih komercialni modelirnik običajno določi namesto nas.

Korak 1: Uvoz knjiznic

Z uvozom knjiznic je omogocena uporaba vseh funkcij, ki jih potrebujemo za izdelavo kocke.

import salome
salome.salome_init()
import GEOM
from salome.geom import geomBuilder
geompy = geomBuilder.New(salome.myStudy)
gg = salome.ImportComponentGUI("GEOM")

Korak 2: Izdelava tock

V prostoru je potrebno definirati tocke. Definiramo jih s funkcijo geompy.MakeVertex().

Slika, ki prikazuje točke, ki definirajo kvadrat.

p1 = geompy.MakeVertex(   0.,   0.,   0.)
p2 = geompy.MakeVertex( 100.,   0.,   0.)
p3 = geompy.MakeVertex( 100., 100.,   0.)
p4 = geompy.MakeVertex(   0., 100.,   0.)

Za prikaz objektov v modulu Geometry v okolju Salome uporabimo naslednje ukaze

# Dodamo nove tocke v studijo
geompy.addToStudy(p1,"point1")
geompy.addToStudy(p2,"point2")
geompy.addToStudy(p3,"point3")
geompy.addToStudy(p4,"point4")
salome.sg.updateObjBrowser(True)

Korak 3: Izdelava krivulje, ki povezuje vse tocke

Z ukazom geompy.MakePolyline() izdelamo krivuljo, ki je sestavljena iz stirih daljic.

Slika, ki prikazuje kvadrat za izvlek.

polyline = geompy.MakePolyline([p1, p2, p3, p4, p1])
# Dodamo novo krivuljo v studijo
geompy.addToStudy(polyline,"polyline")
# Posodobimo drevesno strukturo
salome.sg.updateObjBrowser(True)







Korak 4: Izdelava povrsine.

Sedaj je potrebno izdelati povrsino, ki bo omejena s prej izdelano krivuljo. To storimo z ukazom geompy.MakeFace(). Ta funkcija sprejme zaprto krivuljo (polyline). Nato je spremenljivko potrebno dodati v studijo modula GEOM z ukazom addToStudy().

Slika, ki prikazuje površino kvadrata.

face = geompy.MakeFace(polyline, True)
# Dodamo novo povrsino v studijo
geompy.addToStudy(face, "face")
# Posodobimo drevesno strukturo
salome.sg.updateObjBrowser(True)

Drevesno strukturo posodobimo, ce zelimo prikazati nove geometrijske elemente v modelnem oknu.









Korak 5: Izvlek povrsine

Izvlek povrsine izvedemo z ukazom geompy.MakePrism(). Omenjeni ukaz sprejme tri argumente(povrsina, tocka1, tocka2), pri cemer sta tocka1 in tocka2 tocki, ki definirata vektor. Slika, ki prikazuje izvlek kvadrata v prostor (kocka).

p5 = geompy.MakeVertex(0.,0.,100.)
prism1 = geompy.MakePrism(face, p1, p5)
# Dodamo nov izvlek v studijo
geompy.addToStudy(prism1, "prism1")
# Posodobimo drevesno strukturo
salome.sg.updateObjBrowser(True)

Celoten postopek izdelave izvleka je v priponki (salomePrismExample.py).








Primer izdelave panela v fuzijskem reaktorju ITER

V tem primeru bo prikazana izdelava krivulj v 3D prostoru in izvlek krivulj, s katerim generiramo površino v prostoru. Končni cilj je izdelava panela, prikazanega na sliki. V datoteki data.txt imamo podane koordinate točk (x, y in z), iz katerih bomo generirali krivujo. To krivuljo bomo nato izvlekli v prostor s pomočjo daljic, ki so prav tako definirana s točkami (xe, ye in ze). Podatki so podani v formatu Slika, ki prikazuje model panela.

x1 y1 z1
x2 y2 z2
x3 y3 z3
...
xn yn zn

Korak 1: Uvoz modulov

Najprej je potrebno v python uvoziti vse knjižnice, ki jih bomo uporabili v Salome okolju. Nato pa je potrebno definirati novo študijo.

# Uvoz knjiznic
import salome
import GEOM
from salome.geom import geomBuilder
geompy = geomBuilder.New(salome.myStudy)






Korak 2: Uvoz podatkov v Python

Podatke v stolpcih v tekstovnem formatu lahko preberemo na vec načinov, v tem primeru smo uporabili funkcijo open. Podatke za krivuljo shranimo v spremenljivko tipa list z imenoma coord_x in coord_y. Nato te točke zrcalimo preko ravnine y-z, da dobimo krivuljo še za levo stran panela, in jih shranimo v spremenljivki coord_x_mirror in coord_y_mirror. Nato izvedemo iteracijo s for zanko in shranimo točke kot geompy.MakeVertex() ter jih shranimo v python-ov seznam. Slika, ki prikazuje krivulji za primer izdelave panela.

# Load data
# If file is not opened, determine path with os library
# import os
# os.chdir(os.path.expanduser('~/'))
with open('data.txt','r') as f:
    fileread = f.readlines()
    content = [x.strip() for x in fileread]
    # Define data list
    data = []
    for coord in content:
        data.append([x.strip() for x in coord.split(" ")])
f.close()

coord_x = []
coord_y = []
# convert coordinates to mm and to float type
for i in range(len(data)):
    data[i][0] = float(data[i][0])*(1000)
    data[i][1] = float(data[i][1])*(1000)
    data[i][2] = float(data[i][1])*(1000)
    coord_x.append(data[i][0])
    coord_y.append(data[i][1])


# mirror x coordinatex over yz - plane
coord_mirror_x = coord_x[::-1]
for n in range(len(coord_mirror_x)):
    coord_mirror_x[n] = coord_mirror_x[n]*(-1)
coord_mirror_y = coord_y[::-1]

# Iterate over coord_x and create geompy vertices and store those
# vertices into python list.
points_x = []
for i in range(len(coord_x)):
    point_x = geompy.MakeVertex(coord_x[i],coord_y[i],0)
    points_x.append(point_x)

points_y = []
for i in range(len(coord_x)):
    point_y = geompy.MakeVertex(coord_mirror_x[i],coord_mirror_y[i],0)
    points_y.append(point_y)

Korak 3: Izdelava krivulj

Nato generiramo B-zlepek krivuljo s pomočjo metode geompy.MakeInterpol(), ki sprejme seznam točk, na katerih izvede interpolacijo. Rezultat je polinom, ki predstavlja podano krivuljo. Nato izračunano krivuljo dodamo v študijo.

# Create B-Spline curve on the set of points with
# geompy.MakeInterpol() and add curve to Salome study.
b_spline = geompy.MakeInterpol(points_x)
b_splineID = geompy.addToStudy(b_spline,"b_spline_ft")
b_spline_mirror = geompy.MakeInterpol(points_y)
b_splineID_mirror = geompy.addToStudy(b_spline_mirror,"b_spline_ft_mirrored")

Sedaj je potrebno kreirati še daljico, s katero bomo povezali obe krivulji (na sliki označena z rumeno barvo).

# Create line between both curves.
ml_point1 = geompy.MakeVertex(-coord_x[0],coord_y[0],0)
ml_point2 = geompy.MakeVertex(coord_x[0],coord_y[0],0)
middle_line = geompy.MakeLineTwoPnt(ml_point1,ml_point2)
middle_lineID = geompy.addToStudy(middle_line,"middle_line")

Nato je potrebno vse tri komponente združiti v skupen objekt, ki ga bomo izvlekli v prostor. To storimo z metodo geompy.MakeWire(), ki sprejme seznam krivulj, robov in daljic, ki jih želimo združiti v en objekt.

# Create wire out of all three components
wire = geompy.MakeWire([b_spline_mirror,middle_line,b_spline])
wireID = geompy.addToStudy(wire,"wire")

Korak 4: Izdelava krivulje za izvlek

Nato izdelamo še krivuljo za izvlek, ki je prikazana na sliki. Ponovno uvozimo točke in jih shranimo v spremenljivke tipa list.

Prikaz krivulje za izvlek pri izdelavi panela.

# Load data for extrusion
dataExtrusion = []
with open('dataPolyline.txt','r') as f:
    fileread = f.readlines()
    content = [x.strip() for x in fileread]
    # Define data list
    for coord in content:
        dataExtrusion.append([x.strip() for x in coord.split(" ")])
f.close()

# Read data for extrusion
coord_xe = []
coord_ye = []
coord_ze = []
for n in range(len(dataExtrusion)):
    coord_xe.append(float(dataExtrusion[n][0]))
    coord_ye.append(float(dataExtrusion[n][1]))
    coord_ze.append(float(dataExtrusion[n][2]))

Koordinate ponovno pretvorimo v točke tipa geompy z ukazom geompy.MakeVertex() ter nato generiramo polyline.

# Convert data to geompy point and store it in a list.
points_e = []
for point_e in range(len(coord_xe)):
    point_e = geompy.MakeVertex(coord_xe[point_e],coord_ye[point_e],coord_ze[point_e])
    points_e.append(point_e)
# Create polyline for extrusion and add it to study.
polylineVert = geompy.MakePolyline(points_e)
polylineVertID = geompy.addToStudy(polylineVert,"b_spline_ft_vert")

Korak 5: Izvlek iz krivulj

Na koncu ustvarimo izvlek iz obeh danih krivulj. Izvlek dodamo v študijo in posodobimo drevesno strukturo.

# Create panel shape
panel_FW = geompy.MakePipe(polylineVert, wire)
geompy.addToStudy(panel_FW,'Panel')
salome.sg.updateObjBrowser(True)

Celoten postopek izdelave izvleka je v priponki (salomePanelExample.py).

Razširitev programa panela na grafični vmesnik

Celoten program lahko razširimo na grafični vmesnik, da bo lahko uporabnik lažje uporabljal napisani program. Grafični vmesnik je napisan s pomočjo knjižnice PyQt5. Vmesnik bo uporabljal vertikalno razporeditev grafičnih elementov, ki so QPushButton, QLineEdit in QLabel.

  • QPushButton predstavlja gumb. S klikom nanj se izvede funkcija, ki opravi določeno nalogo.
  • QLineEdit omogoča vnos teksta v program.
  • QLabel služi za prikaz besedila in je statični element, ki podaja neko informacijo.

Opis uporabe programa

Na sliki je prikazan primer izgleda uporabniškega vmesnika, ki ga bomo napisali v tem poglavju. Ta vmesnik grafične elemente razporedi v vertikalni smeri z metodo QVBoxLayout(). Na vrhu je definiran QLabel, pod njim pa gumb QPushButton. S klikom nanj se izvede funkcija, ki izriše panel in ga pozicionira v prostoru. Nato lahko panel še rotiramo in naredimo kopije panela. V QLineEdit pod Set name: zapišemo imena rotiranih panelov, v QLineEdit pod Set rotation angle:: zapišemo kot rotacije okoli z-osi tipa float, v QLineEdit pod Set number of rotations: pa število panelov tipa int.

Dialog za izdelavo panela.

Za primer vzemimo, da želimo izdelati panel, nato pa narediti še štiri kopije pri lemer je vsaka kopija zamaknjena za 20 stopinj okoli z-osi. Najprej s klikom na gumb Create Panel, naredimo panel iz prejšnjega primera, ki je že predhodno pozicioniran v prostoru (glede na prejšnji primer je pomaknjen v y smeri za -4200 milimetrov). Sedaj želimo izdelati še štiri panele, ki bodo zarotirani za 20, 40, 60 in 80 stopinj okoli z-osi glede na prvega. Najprej določimo ime panelov ('panelsrotated'), nato določimo začetni kot rotacije, ki znaša 20 stopinj, nato pa se pri vsakem panelu poveča za 20 stopinj. Določimo še število vseh zasukanih panelov oziroma število vseh rotacij, torej 4. Nato pritisnemo na gumb Apply. Rezultat programa je viden na spodnji sliki.

Prikaz rotiranih panelov.

Opis izdelave programa

Na začetku ponovno uvozimo vse potrebne knjižnice, tokrat tudi grafično knjižnico PyQt5.

# import libraries
import salome
import GEOM
from salome.geom import geomBuilder
import os
from functools import partial
# GUI library 
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

Sedaj lahko definiramo obe funkciji, kise bosta izvedli, ko bomo pritisnili na oba gumba tipa QPushButton. Funkcija, ki izdela panel in ga premakne v y osi za -4200 milimetrov, se imenuje createPanel in je v osnovi isti program kot pri izdelavi panela, le da je shranjen v funkcijo.

def createPanel():
    global panelIsMade
    panelIsMade = True
    # If file is not opened, determine path with os library
    os.chdir(os.path.expanduser('d:/vaje_KT/'))
    with open('data.txt','r') as f:
        fileread = f.readlines()
        content = [x.strip() for x in fileread]
        # Define data list
        data = []
        for coord in content:
            data.append([x.strip() for x in coord.split(" ")])
    f.close()
    
    coord_x = []
    coord_y = []
    # convert coordinates to mm and to float type
    for i in range(len(data)):
        data[i][0] = float(data[i][0])*(1000)
        data[i][1] = float(data[i][1])*(1000)
        data[i][2] = float(data[i][1])*(1000)
        coord_x.append(data[i][0])
        coord_y.append(data[i][1])
    
    
    # mirror x coordinatex over yz - plane
    coord_mirror_x = coord_x[::-1]
    for n in range(len(coord_mirror_x)):
        coord_mirror_x[n] = coord_mirror_x[n]*(-1)
    coord_mirror_y = coord_y[::-1]
    
    # Iterate over coord_x and create geompy vertices and store those
    # vertices into python list.
    points_x = []
    for i in range(len(coord_x)):
        point_x = geompy.MakeVertex(coord_x[i],coord_y[i],0)
        points_x.append(point_x)

    points_y = []
    for i in range(len(coord_x)):
        point_y = geompy.MakeVertex(coord_mirror_x[i],coord_mirror_y[i],0)
        points_y.append(point_y)
    
    # Create B-Spline curve on the set of points with
    # geompy.MakeInterpol() and add curve to Salome study.
    b_spline = geompy.MakeInterpol(points_x)
    b_splineID = geompy.addToStudy(b_spline,"b_spline_ft")
    
    b_spline_mirror = geompy.MakeInterpol(points_y)
    b_splineID_mirror = geompy.addToStudy(b_spline_mirror,"b_spline_ft_mirrored")
    
    # Create line between both curves.
    ml_point1 = geompy.MakeVertex(-coord_x[0],coord_y[0],0)
    ml_point2 = geompy.MakeVertex(coord_x[0],coord_y[0],0)
    middle_line = geompy.MakeLineTwoPnt(ml_point1,ml_point2)
    middle_lineID = geompy.addToStudy(middle_line,"middle_line")
    
    # Create wire out of all three components
    wire = geompy.MakeWire([b_spline_mirror,middle_line,b_spline])
    wireID = geompy.addToStudy(wire,"wire")
    
    # Load data for extrusion
    dataExtrusion = []
    with open('dataPolyline.txt','r') as f:
        fileread = f.readlines()
        content = [x.strip() for x in fileread]
        # Define data list
        for coord in content:
            dataExtrusion.append([x.strip() for x in coord.split(" ")])
    f.close()
    
    # Read data for extrusion
    coord_xe = []
    coord_ye = []
    coord_ze = []
    for n in range(len(dataExtrusion)):
        coord_xe.append(float(dataExtrusion[n][0]))
        coord_ye.append(float(dataExtrusion[n][1]))
        coord_ze.append(float(dataExtrusion[n][2]))
    
    # Convert data to geompy point and store it in a list.
    points_e = []
    for coord_e in range(len(coord_xe)):
        point_e = geompy.MakeVertex(coord_xe[coord_e],coord_ye[coord_e],coord_ze[coord_e])
        points_e.append(point_e)
    
    # Create polyline for extrusion and add it to study.
    polylineVert = geompy.MakePolyline(points_e)
    polylineVertID = geompy.addToStudy(polylineVert,"polyline_ft_vert")
    panel_FW = geompy.MakePipe(wire, polylineVert)
    panel_FW = geompy.MakeTranslation(panel_FW, 0,-4200,0)
    geompy.addToStudy(panel_FW,'Panel')
    salome.sg.updateObjBrowser(True)

Nato zapišemo še funkcijo createNewPanel, ki se izvede ob pritisku na gumb Apply, in izdela zasukane panele. Omenjena funkcija kot vhodne argumente prejme tri spremenljivke tipa QLineEdit. V našem primeru je lin1 objekt razreda QLineEdit, ki sprejme tekst, ki predstavlja ime zasukanih panelov, lin2 predstavlja kot rotacije panelov, lin3 pa število zasukanih panelov. Do teskta dostopamo z metodo QLineEdit.text(), npr. lin1.text() vrne spremenljivko, ki vsebuje vnešen tekst v omenjeni QLineEdit(). Omenjena funkcija bo zdelala zasukane panele, če bo uporabnik predhodno izdelal panel, ki ga definira gumb Create panel.

def createNewPanel(lin1, lin2, lin3):
    # If panel is not made, there is nothing to rotate
    # If lin2.text() is not float, angle cannot be determined
    # If lin3.text() is not int, number of rotated panels cannot be determined
    if panelIsMade and float(lin2.text()) and int(lin3.text()):
        p1 = geompy.MakeVertex(0, 0, 0)
        p2 = geompy.MakeVertex(0, 0, 1)
        v = geompy.MakeVector(p1, p2)
        # This for loop iterates over number of roteted panels and
        # adds angle to every new panel. Result is panel_FW_rotated
        # Name of panel is given by user + angle of rotation
        for nr in range(1,int(lin3.text())+1):
            panel_FW_rotated = geompy.MakeRotation(panel_FW, v, math.pi/180*nr*float(str(lin2.text())))
            panel_name = str(lin1.text())+"_rotated_"+str(float(str(lin2.text()))*nr)+"_deg"
            geompy.addToStudy(panel_FW_rotated,panel_name)
        salome.sg.updateObjBrowser(True)

Sedaj lahko izdelamo uporabniški vmesnik. Vsak uporabniški vmesnik je definiran kot objekt. Pri knjižnici PyQt5 je to objekt, definiran kot QtWidgets?.QWidget(). Objekt ima svoje metode, kot so npr. setFixedSize(), ki definira točno velikost dialoga, ter setWindowTitle(), ki definira naslov dialoga.

widgetHDF = QtWidgets.QWidget()
widgetHDF.setFixedSize(500, 250)
widgetHDF.setWindowTitle('Rotate panel')

Nato definiramo uporabljene grafične elemente. Spremenljivka panelIsMade je uporabljena v funkciji createNewPanel. Če je njena vrednost False, se funkcija ne izvede, saj to pomeni, da predhodni panel, ki ga kopiramo, ni bil izdelan.

lblPanel = QLabel('Create panel:')
btnPanel = QPushButton('Create Panel')
lbl1 = QLabel('Set name for rotation panels:')
lin1 = QLineEdit('panel4')
lbl2 = QLabel('Set rotation angle:')
lin2 = QLineEdit('0')
lbl3 = QLabel('Set number of rotations:')
lin3 = QLineEdit('1')
btn = QPushButton('Apply')
panelIsMade = False

Metoda setToolTip prikaže namig, če kurzor premaknemo na gumb. Ko kliknemo na gumb, se mora izvesti neka funkcija. V PyQt5 knjižnici ima gumb metodo clicked.connect(), ki kot vhodni argument sprejme ime funkcije, ki se mora izvesti. Gumb btnPanel razreda QPushButton pokliče funkcijo createPanel(), ki ne sprejme nobenega vhodnega argumenta, saj je njena naloga samo izrisati predhodno določen in pozicioniran panel. Drugače je pri gumbu btn. Ta kliče funkcijo createNewPanel(), ki sprejme tri vhodne argumente, ki so ime panelov, kot in število panelov. Metoda clicked.connect() pa sprejme samo en argument. To rešimo s funkcijo partial. Prvi argument te funkcije je createNewPanel, ostali argumenti pa so vhodni argumenti za našo funkcijo. Funkcija partial() tako vhodne argumente poda v createNewPanel. in rezultat prenese v clicked.connect().

btnPanel.setToolTip('Create panel')
btn.setToolTip('Create rotated panels')
btnPanel.clicked.connect(btnPanel.clicked.connect(createPanel))
btn.clicked.connect(partial(createNewPanel,lin1,lin2,lin3))

Sedaj lahko definiramo razporeditev grafičnih elementov v našem dialogu. Možne izbire so QGridLayout(), kar pomeni mrežna razporeditev elementov, QHBoxLayout(), ki elemente razporedi horizontalno in QVBoxLayout(), ki elemente razporedi vertikalno. V našem primeru uporabimo QVBoxLayout(), ki grafične elemente glede na zaporedje dodajanja v dialog razvršča vertikalno od zgoraj navzdol (prvi element, ki je dodan v dialog, v našem primeru lblPanel tipa QLabel, je na vrhu, nato sledijo drugi).

layout = QtWidgets.QVBoxLayout()
layout.addWidget(lblPanel)
layout.addWidget(btnPanel)
layout.addWidget(lbl1)
layout.addWidget(lin1)
layout.addWidget(lbl2)
layout.addWidget(lin2)
layout.addWidget(lbl3)
layout.addWidget(lin3)
layout.addWidget(btn)

Na koncu v objekt, ki definira dialog, namestimo porazdelitev grafičnih elementov. Z metodo move() lahko določimo, kje na ekranu bo pozicioniran dialog, z metodo show() pa dokončno prikažemo dialog na zaslonu.

widgetHDF.setLayout(layout)
widgetHDF.move(500, 500)
widgetHDF.show()

Celoten postopek izdelave programa je v priponki (salomeDialogPanelExample.py). Ta program morda ni najbolj smiseln, saj je najprej potrebno izdelati že vnaprej pozicioniran panel, če želimo izdelati še zasukane kopije omenjenega panela. V razmislek tako lahko vzamemo delovanje omenjenega programa in programov na splošno ter kaj želimo s programom uporabniku olajšati.

Attachments (27)