Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
DanielLeeWenger
Posts: 53
Joined: Sun Feb 02, 2020 4:02 am
Location: Santa Cruz, California
Contact:

Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by DanielLeeWenger »

While working on a project that involved coloring objects created via a script I was surprised that information on this subject was not easy to find. I did a good bit of searching to find specifically how to access a Gui object from the script that created the object.

There are a number of postings on the forum on how to do this but none seemed to work for me. I suspect that they might have worked in older versions of FC as the dates on the postings were old.

This posting displays what I did learn, namely, how to create a face and then give it a color, all from a script. I had help from one posting on the forum but I apologize for not being able to find it again to give credit to the author.

I hope that this posting will be of help to others and perhaps considered as a code snippet for FC. I was not able to learn this technique from the FC Code snippets.

Code: Select all

# Code snippet to demonstrate how to access, from a script, a Gui object created by the script
import FreeCAD as App
import FreeCADGui
import Part

v=App.Vector
v1=v(1.0,0.0,0.0)
v2=v(-1.0,0.0,0.0)
v3=v(0.0,0.0,1.0)

theList=[v1,v2,v3]

myColor=0.0,0.0,1.0,0.0 # blue

def makeFace(theList,theColor):
	thePart=Part.makeFilledFace(Part.makePolygon(theList, True).Edges)
	if thePart.isNull(): print("cannot make face!")
	thePartObj=App.ActiveDocument.addObject('Part::Feature','Face')
	thePartObj.Shape=thePart
	gad = Gui.activeDocument()
	theGuiObj = gad.getObject(thePartObj.Name)
	theGuiObj.ShapeColor=theColor

makeFace(theList,myColor)

App.ActiveDocument.recompute()

OS: macOS Mojave (10.14)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.19.24291 (Git)
Build type: Release
Branch: (HEAD detached at 0.19.2)
Hash: 7b5e18a0759de778b74d3a5c17eba9cb815035ac
Python version: 3.8.8
Qt version: 5.12.9
Coin version: 4.0.0
OCC version: 7.4.0
Locale: C/Default (C)
User avatar
onekk
Veteran
Posts: 6205
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by onekk »

Objects have also a property ViewObject see the code:

Code: Select all

import FreeCAD
from FreeCAD import Rotation, Vector
import Part

DOC_NAME =  "test_gen"

DOC = FreeCAD.newDocument(DOC_NAME)

theList=[(10.0,0.0,0.0), (-10.0,0.0,0.0), (0.0,0.0,10.0)]

myColor=0.0,0.0,1.0,0.0 # blue

def makeFace(theList,theColor):
	thePart=Part.makeFilledFace(Part.makePolygon(theList, True).Edges)
	if thePart.isNull(): print("cannot make face!")
	thePartObj=DOC.addObject('Part::Feature','Face')
	thePartObj.Shape=thePart
	thePartObj.ViewObject.ShapeColor=theColor

makeFace(theList,myColor)

DOC.recompute()
Side Notes:
  • your code did not work if there is no a FCStd document open, so I've added a simple line to open a document, plus, this could became easy the reference of FreeCAD.ActiveDocument to be more concise in writing.
  • makePolygon simply accept tuples of three number as a position, so no need to have and create Vectors and assign them to a list, simply create a "list of 3D coordinates" ant job is done.
  • You could shorten things, using the from FreeCAD import in the first line, maybe adding also Placement if you like
Hope it will be useful in your journey into FreeCAD Scritping.

Best Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by openBrain »

Agree with Carlo.
Actually you can easily switch from AppObject (the solid) to GuiObject (the representation) with following relations :

Code: Select all

AppObject = GuiObject.Object # returns a DocumentObject
GuiObject = AppObject.ViewObject # returns a ViewProvider
DanielLeeWenger
Posts: 53
Joined: Sun Feb 02, 2020 4:02 am
Location: Santa Cruz, California
Contact:

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by DanielLeeWenger »

Thank you for the feedback and the improvements.
DanielLeeWenger
Posts: 53
Joined: Sun Feb 02, 2020 4:02 am
Location: Santa Cruz, California
Contact:

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by DanielLeeWenger »

Thank you mario52 for your post. I have benefited much from your macros. They have helped me in learning Python and FC.

I too have been playing with polyhedra. Below is code that I recently completed that will produce the "great rhombicuboctahedron", incorrectly called a "truncated cuboctahedron". I have been working on finding the object from which the "great rhombicuboctahedro" can be found by truncation.

This project has raised a question that I will ask here, perhaps not the preferred posting site but here goes.

Question:
If the code below is placed in the Macro editor and executed the code is successful in producing the "great rhombicuboctahedro" as desired. If the code is placed in the Python console an error (invalid syntax) is generated, an error that I cannot rectify. Is there an explanation for this?

Code: Select all

# code to generate the great rhombicuboctahedron
import FreeCAD as App
import Part
import math
import numpy as np
import FreeCADGui

v=App.Vector

red=1.0,0.0,0.0,0.0
green=0.0,1.0,0.0,0.0
blue=0.0,0.0,1.0,0.0
yellow=(1.0,1.0,0.0)

theLengthOfEdge=10.0

# (±1, ±(1 + √2), ±(1 + 2√2)) vertices for edge length of 2.0
print("12 squares")
print(" 8 hexagons")
print("6 octagons")
print("26 total")
A1=float(1)
print("A1",A1)
B1=float(1+math.sqrt(2))
print("B1",B1)
C1=float(1+2*math.sqrt(2))
print("C1",C1)

#ABC
#ACB
#BAC
#BCA
#CAB
#CBA

#ABC
v11=v(A1,B1,C1)
v21=v(A1,B1,-C1)
v31=v(A1,-B1,C1)
v41=v(-A1,B1,C1)
v51=v(A1,-B1,-C1)
v61=v(-A1,-B1,C1)
v71=v(-A1,B1,-C1)
v81=v(-A1,-B1,-C1)

#ACB
v12=v(A1,C1,B1)
v22=v(A1,C1,-B1)
v32=v(A1,-C1,B1)
v42=v(-A1,C1,B1)
v52=v(A1,-C1,-B1)
v62=v(-A1,-C1,B1)
v72=v(-A1,C1,-B1)
v82=v(-A1,-C1,-B1)

#BAC
v13=v(B1,A1,C1)
v23=v(B1,A1,-C1)
v33=v(B1,-A1,C1)
v43=v(-B1,A1,C1)
v53=v(B1,-A1,-C1)
v63=v(-B1,-A1,C1)
v73=v(-B1,A1,-C1)
v83=v(-B1,-A1,-C1)

#BCA
v14=v(B1,C1,A1)
v24=v(B1,C1,-A1)
v34=v(B1,-C1,A1)
v44=v(-B1,C1,A1)
v54=v(B1,-C1,-A1)
v64=v(-B1,-C1,A1)
v74=v(-B1,C1,-A1)
v84=v(-B1,-C1,-A1)

#CAB
v15=v(C1,A1,B1)
v25=v(C1,A1,-B1)
v35=v(C1,-A1,B1)
v45=v(-C1,A1,B1)
v55=v(C1,-A1,-B1)
v65=v(-C1,-A1,B1)
v75=v(-C1,A1,-B1)
v85=v(-C1,-A1,-B1)

#CBA
v16=v(C1,B1,A1)
v26=v(C1,B1,-A1)
v36=v(C1,-B1,A1)
v46=v(-C1,B1,A1)
v56=v(C1,-B1,-A1)
v66=v(-C1,-B1,A1)
v76=v(-C1,B1,-A1)
v86=v(-C1,-B1,-A1)

theV=[v11,v21,v31,v41,v51,v61,v71,v81,v12,v22,v32,v42,v52,v62,v72,v82,v13,v23,v33,v43,v53,v63,v73,v83,v14,v24,v34,v44,v54,v64,v74,v84,v15,v25,v35,v45,v55,v65,v75,v85,v16,v26,v36,v46,v56,v66,v76,v86]
print("theV",len(theV))
	
def reverse(L):
	return(L[::-1])

def rotateLeft(T,n):
	return( T[n:] + T[:n])

def rotateRight(T,n):
	return( T[-n:] + T[:-n])

def cross(a, b):
	x = a[1]*b[2] - a[2]*b[1]
	y=a[2]*b[0] - a[0]*b[2]
	z=a[0]*b[1] - a[1]*b[0]
	return(x,y,z)

def dot(v1,v2):
	theDot=v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]
	return(theDot)

def mag(v):
	theMag=math.sqrt(v.x*v.x+v.y*v.y+v.z*v.z)
	return theMag

def cleanDuplicates(L):
	M=L
	for i in L:
		k=i
		for j in range(len(i)-1):
			k=rotateRight(k,1)
			try:
				M.remove(k)
			except:
				pass
		k=reverse(i)
		for j in range(len(i)):
			k=rotateRight(k,1)
			try:
				M.remove(k)
			except:
				pass
	return(M)

def displayEdges(E):
	print("displaying edges")
	for i in E:
		v1=i[0]
		v2=i[1]
		Edge=Part.LineSegment(v1,v2).toShape()
		Wire=Part.Wire(Edge)
		Part.show(Wire)
#displayEdges(theEdges)

def uniqueList(L):
	bin=[L[0]]
	for i in L:
		flag=1
		for j in bin:
			if i==j:
				flag=0
		if flag==1:
			bin.append(i)
	return(bin)

def isIn(obj,theList):
	for i in theList:
		if obj==i:
			return(True)
	return(False)

def makeEdges(theV):
	bin=[]  # each edge is a pair of indices to two vertices - edge length is 2
	for i in range(len(theV)):
		for j in range(len(theV)):
			if i!=j:
				theMag=mag(theV[i]-theV[j])
				if theMag<2.1 and theMag>1.9:
					bin.append((i,j))
	return(uniqueList(bin))


def makeLegs(theEdges):
	bin=[] # combine two edges that meet each other
	for i in theEdges:
		for j in theEdges:
			if i!=j and not (i[0]==j[1] and i[1]==j[0]): 
				if i[1]==j[0]:
					bin.append((i,j))
				if i[0]==j[1]:
					bin.append((j,i))
	return(uniqueList(bin))

theLegs90=[]
theLegs60=[]
theLegs45=[]
def placeLegs(angle,Edge):
	if angle==45:
		theLegs45.append(Edge)
	elif angle==60:
		theLegs60.append(Edge)
	elif angle==90:
		theLegs90.append(Edge)
	else:
		print("placeLegs()",angle)

def makeLegLists(theLegs):
	for i in theLegs:
		v1=theV[i[0][0]]-theV[i[0][1]]
		v1=v(v1)
		v2=theV[i[1][0]]-theV[i[1][1]]
		v2=v(v2)
		m1=mag(v1)
		m2=mag(v2)
		C=dot(v1,v2)/(m1*m2)
		if C>1.0:
			C=1.0
		if C< -1.0:
			C= -1.0
		A=math.acos(C)
		A*= 180.0/math.pi
		A=np.round(A,4)
		A=int(A)
		placeLegs(A,i)

def splitLegs(L):
	bin=[]
	for i in L:
		for j in i:
			bin.append(j)
	return(uniqueList(bin))

def attachEdges(L0,L1):
	bin=[]
	for i in L0:
		for j in L1:
			if i[-1]==j[0] and i[-2]!=j[1]:
				term=i+j
				bin.append(term)
#				print(term)
	return(bin)

def removeDups(L):
	bin = []
	for i in L:
		term=[]
		for j in i:
			if j not in term:
				term.append(j)
		bin.append(term)
	return(bin)

def displayFaces(V,theColor):
	for i in V:
		thePoints=[]
		for j in i:
			V=(theLengthOfEdge/2.0)*v(theV[j])
			thePoints.append(V)
		makeFace(thePoints,theColor)

theFaces=[]
theGuiFaces=[]
def makeFace(theList,theColor): # P are Vertex.Point
	thePart=Part.makeFilledFace(Part.makePolygon(theList, True).Edges)
	if thePart.isNull(): print("cannot make face!")
	thePartObj=App.ActiveDocument.addObject('Part::Feature','Face')
	thePartObj.Shape=thePart
	gad = Gui.activeDocument()
	theGuiObj = gad.getObject(thePartObj.Name)
	theGuiObj.ShapeColor=theColor
	theFaces.append(thePartObj.Shape)

def makeShell(theFaces):
	thePart=Part.Shell(theFaces)
	if thePart.isNull():print("No shell!")
	thePartObject=App.ActiveDocument.addObject('Part::Feature','Shell')
	thePartObject.Shape=thePart.removeSplitter()

#	shell=App.ActiveDocument.Shell.Shape
#	if shell.ShapeType != 'Shell': raise RuntimeError('Part object is not a shell')
#	_=Part.Solid(shell)
	_=Part.Solid(thePartObject.Shape)
	if _.isNull(): raise RuntimeError('Failed to create solid')
	App.ActiveDocument.addObject('Part::Feature','Solid').Shape=_.removeSplitter()



##########################################################################
doc=App.newDocument("great rhombicuboctahedron")

theEdges=makeEdges(theV)
print("theEdges",int(len(theEdges)/2))

theLegs=makeLegs(theEdges)

makeLegLists(theLegs)

theV90=theEdges90=splitLegs(theLegs90)
for i in range(3):
	theV90=attachEdges(theV90,theEdges90)
theV90=cleanDuplicates(theV90)
print("theV90",len(theV90))
theList=removeDups(theV90)
displayFaces(theList,blue)

theV60=theEdges60=splitLegs(theLegs60)
for i in range(5):
	theV60=attachEdges(theV60,theEdges60)
theV60=cleanDuplicates(theV60)
print("theV60",len(theV60))
theList=removeDups(theV60)
displayFaces(theList,yellow)

theV45=theEdges45=splitLegs(theLegs45)
for i in range(7):
	theV45=attachEdges(theV45,theEdges45)
theV45=cleanDuplicates(theV45)
print("theV45",len(theV45))
theList=removeDups(theV45)
displayFaces(theList,red)

makeShell(theFaces)

doc.recompute()
Gui.SendMsgToActiveView("ViewFit")
OS: macOS Mojave (10.14)
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.19.24291 (Git)
Build type: Release
Branch: (HEAD detached at 0.19.2)
Hash: 7b5e18a0759de778b74d3a5c17eba9cb815035ac
Python version: 3.8.8
Qt version: 5.12.9
Coin version: 4.0.0
OCC version: 7.4.0
Locale: C/Default (C)
mario52
Veteran
Posts: 4692
Joined: Wed May 16, 2012 2:13 pm

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by mario52 »

Hi

you must create one line after the end loop for... feature :

original code

Code: Select all

for i in range(3):
	theV90=attachEdges(theV90,theEdges90)
theV90=cleanDuplicates(theV90)

replace by

Code: Select all

for i in range(3):
	theV90=attachEdges(theV90,theEdges90)

theV90=cleanDuplicates(theV90)
and you see the beautiful rhombicuboctahedro incorrectly called a "truncated cuboctahedron"

you must create the page in the Macros_recipes (Section Object creation) here for access How to get wiki editing permissions welcome on club

if you want well sure

mario
Maybe you need a special feature, go into Macros_recipes and Code_snippets, Topological_data_scripting.
My macros on Gist.github here complete macros Wiki and forum.
TheMarkster
Veteran
Posts: 5513
Joined: Thu Apr 05, 2018 1:53 am

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by TheMarkster »

mario52 wrote: Sat Nov 13, 2021 10:48 am
you must create one line after the end loop for... feature :
The extra line after a for loop is necessary for running in the python console? Very interesting information.
User avatar
Chris_G
Veteran
Posts: 2598
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by Chris_G »

TheMarkster wrote: Sat Nov 13, 2021 7:01 pm The extra line after a for loop is necessary for running in the python console? Very interesting information.
After any indented block.
I think this is because the python console interprets lines just when they are sent, so it needs a blank line to know that a indented block is finished and can actually be interpreted.
DanielLeeWenger
Posts: 53
Joined: Sun Feb 02, 2020 4:02 am
Location: Santa Cruz, California
Contact:

Re: Code snippet to demonstrate how to access, from a script, a Gui object created by the script

Post by DanielLeeWenger »

Ahhh. Thank you Mario. It is the simple things that need attention.

Thanks for the guidance for creating a macro. I did not realize I could post a macro without do so via GitHub.
Post Reply