assembly without solver

Discussion about the development of the Assembly workbench.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
fosselius
Posts: 381
Joined: Sat Apr 23, 2016 10:03 am
Contact:

Re: assembly without solver

Post by fosselius »

Zolko wrote: Sun Jan 27, 2019 9:08 pm
Haha, was actually working on this, have so far only created a listView containing labels for all Bodies in all open files, got stuck in a movie halfway through..

Code: Select all

from PySide import QtGui, QtCore
# Our main window will be a QListView
list = QtGui.QListView()
list.setWindowTitle('Import Link')
list.setMinimumSize(200, 400)
 
# Create an empty model for the list's data
model = QtGui.QStandardItemModel(list)
textInput = QtGui.QLineEdit(list)

# Find all PartDesign::Body inside all open documents
for documents in App.listDocuments().values():
	for body in documents.findObjects("PartDesign::Body"):
		print body.Label 

		item = QtGui.QStandardItem(body.Label)
	 
	    # Add a checkbox to it
		item.setCheckable(False)
	 
	    # Add the item to the model
		model.appendRow(item)
 
def on_item_changed(item):
    # If the changed item is not checked, don't bother checking others
    if not item.checkState():
        return
 
    # Loop through the items until you get None, which
    # means you've passed the end of the list
    i = 0
    while model.item(i):
        if not model.item(i).checkState():
            return
        i += 1
 
    app.quit()
 
def on_text_changed(text):
	#todo filter on text
	print text

model.itemChanged.connect(on_item_changed)
textInput.textChanged.connect(on_text_changed)
 
# Apply the model to the list view
list.setModel(model)
 
# Show the window and run the app
list.show()
User avatar
Zolko
Veteran
Posts: 2213
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Post by Zolko »

fosselius wrote: Sun Jan 27, 2019 9:54 pm
Zolko wrote: Sun Jan 27, 2019 9:08 pm
Haha, was actually working on this, have only created a listView containing labels for all Bodies in all open files
if you can manage to do it all in 1 dialog, and not like me have 2, it would be much better.
try the Assembly4 workbench for FreCAD — tutorials here and here
User avatar
fosselius
Posts: 381
Joined: Sat Apr 23, 2016 10:03 am
Contact:

Re: assembly without solver

Post by fosselius »

Zolko wrote: Sun Jan 27, 2019 9:58 pm if you can manage to do it all in 1 dialog, and not like me have 2, it would be much better.
That was my goal, but that wont be done today. maybe tomorrow, depends on how the day turns out.
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: assembly without solver

Post by realthunder »

Zolko wrote: Sun Jan 27, 2019 9:08 pm Now ... about that expression thingy ... would it be possible to store / retrieve the placement expression from an object in the assembly document ? Specifically, an App::Placement, as used here ( App.ActiveDocument.addObject( 'App::Placement' ) ) has a property called "Expression Engine", but that is frozen. Would it be possible to use that property to store the text of the expression ? The field is frozen and empty, but it would be the ideal place to store the string used in the expression engine. (populating the text of that expression is then another subject, but using it would be very natural). Do you know if there is a way to use the field "Expression Engine" in an App::Placement ? Or if it's possible to add another field / property / whatever that could store text, which could be evaluated by the expression engine ? This App::Placement would then become, de facto, the constraint for the corresponding App::Part.
Very object has this "ExpressionEngine" property. This is how you can bind an expression to calculate the placement of an object based on others. If you want to actually use an expression to calculate the placement of an App::Placement object, then

Code: Select all

pla = App.ActiveDocument.addObject( 'App::Placement' )
pla.setExpression('Placement', expression)
On the other hand, if you want to store expression text in App::Placement for use by other object, then it is better to add some string type property of your own. I have just added python binding object for App::Placement so that you can do just that. Please sync LinkStage3.

Code: Select all

pla = App.ActiveDocument.addObject('App::PlacementPython')

# This '=1' below is necessary to make a python binding object visible. 
# In fact this is how FC lets user create their own types, by attaching a user defined Python object to 'Proxy'.
# pla has 'Proxy' too. But for simplicity sake, we are not creating a full fledged python binding here. So just
# assign any thing to ViewObject.Proxy to activate it.
pla.ViewObject.Proxy = 1

pla.addProperty('App::PropertyString','Text')
pla.Text = expression
You can write an expression that accepts parameter, and later calls it when actually binding to some object using eval. If you can't get it work, please provide a file with your exact intention (like which property of which object binds to what expression, etc.), and I'll give it a try.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
User avatar
Zolko
Veteran
Posts: 2213
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Post by Zolko »

realthunder wrote: Sun Jan 27, 2019 11:59 pm Please sync LinkStage3.
ah yes, that ... you mean this git-thing, don't you ? Until now, I've downloaded a ZIP of your branch and compiled it. To actually set-up a GIT branch (clone / repository / account / thing) on my computer, I'll have to look how to do that. I'm better with a screwdriver than with a keyboard.
try the Assembly4 workbench for FreCAD — tutorials here and here
User avatar
fosselius
Posts: 381
Joined: Sat Apr 23, 2016 10:03 am
Contact:

Re: assembly without solver

Post by fosselius »

Code: Select all

from PySide import QtGui, QtCore

class ExampleModalGuiClass(QtGui.QDialog):
	""""""
	def __init__(self):
		super(ExampleModalGuiClass, self).__init__()
		self.initUI()

	def reloadList(self):
		# Find all PartDesign::Body inside all open documents
		self.model.clear()
		self.bodyList = []
		for documents in App.listDocuments().values():
			objectList = documents.findObjects("PartDesign::Body")
			objectList += documents.findObjects("App::Part")
			#print documents.Label
			for body in objectList:
				#print documents.Label + " " + body.Label 
				self.bodyList.append(body)
				item = QtGui.QStandardItem(documents.Label + "->" + body.Label)
				item.setIcon(body.ViewObject.Icon)
			    # Add a checkbox to it
				item.setCheckable(False)
			 
			    # Add the item to the model
				self.model.appendRow(item)

	def initUI(self):

		# Our main window will be a QListView
		self.list = QtGui.QListView(self)
		self.list.move(10,40)
		self.setWindowTitle('Create Link')
		self.setMinimumSize(400, 400)
 
		# Create an empty model for the list's data
		self.model = QtGui.QStandardItemModel(self)
		self.list.setMinimumSize(380, 300)
		self.textInput = QtGui.QLineEdit(self)
		self.textInput.setMinimumSize(380, 0)
		self.textInput.move(10,10)
		self.reloadList()

		self.linkNameInput = QtGui.QLineEdit(self)
		self.linkNameInput.setMinimumSize(200, 0)
		self.linkNameInput.move(10, 350)

		#create link button
		# toggle visibility button
		self.createLinkButton = QtGui.QPushButton('Create Link', self)
		self.createLinkButton.setAutoDefault(False)
		self.createLinkButton.move(210, 350)

		self.model.itemChanged.connect(self.on_item_changed)
		self.textInput.textChanged.connect(self.on_text_changed)
		self.createLinkButton.clicked.connect(self.onCreateLink)

		# Apply the model to the list view
		self.list.setModel(self.model)
		# Show the window and run the app
		self.list.show()

	def onCreateLink(self):
		print "create link"
		#for item in self.model.data():
		#	print item
		selected = self.list.selectedIndexes()
		for sel in selected:
			itemSelected = self.model.item(sel.row()).text()
			document,body = itemSelected.split('->')
			print "import " + body + " from " + document
				# create the App::Link to the previously selected model
			#App.activeDocument().getObject('Model').newObject( 'App::Link', linkName ).LinkedObject = model
			
				# create an App::Placement for that object
			#App.ActiveDocument.getObject('Constraints').newObject( 'App::Placement', 'PLMT_'+linkName )

	def on_item_changed(self,item):
	    # If the changed item is not checked, don't bother checking others
		if not item.checkState():
			return
	 
	    # Loop through the items until you get None, which
	    # means you've passed the end of the list
		i = 0
		while self.model.item(i):
			if not self.model.item(i).checkState():
				return
			i += 1
		 
	def on_text_changed(self,text):
		#todo filter on text
		self.reloadList()
		filteredText = self.model.findItems(text,QtCore.Qt.MatchFlag.MatchContains)
		if len(filteredText):
			self.model.clear()
			for label in filteredText:
				self.model.appendRow(label)


form = ExampleModalGuiClass()
form.exec_()
A slight update, still needs lots of love.
select2.gif
select2.gif (193.68 KiB) Viewed 3471 times
Last edited by fosselius on Mon Jan 28, 2019 12:24 pm, edited 1 time in total.
User avatar
Zolko
Veteran
Posts: 2213
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Post by Zolko »

fosselius wrote: Mon Jan 28, 2019 10:49 am A slight update, still needs lots of love.
nice, looks promising. I like the dynamic filter. Meanwhile ...

asm_Lego2.png
asm_Lego2.png (363.24 KiB) Viewed 3473 times

setting all those LCS-s is time consuming, but once it's done it becomes quite usable. The edit of the expression is the painful part now. And then, I thought about that script that generates bricks ... Couldn't it include an option to place LCS-s automagically on the fixation spots ? Did you manage to make it work ? I didn't.
Attachments
asm_Lego.zip
(209.61 KiB) Downloaded 71 times
try the Assembly4 workbench for FreCAD — tutorials here and here
User avatar
fosselius
Posts: 381
Joined: Sat Apr 23, 2016 10:03 am
Contact:

Re: assembly without solver

Post by fosselius »

Zolko wrote: Mon Jan 28, 2019 12:18 pm The edit of the expression is the painful part now. And then, I thought about that script that generates bricks ... Couldn't it include an option to place LCS-s automagically on the fixation spots ? Did you manage to make it work ? I didn't.
I have not looked at it yet. will let you know if/when i do.

Just updated the previous post. added an element of style ;)
also, if you want a bit more variation, i have my other lego bricks here:
https://gitlab.com/maidenOne/freecad_le ... ster/Parts

And latest import script is here:
https://gitlab.com/maidenOne/freecad_le ... nk.FCMacro

Note, its not yet functional, but its close.
User avatar
Zolko
Veteran
Posts: 2213
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Post by Zolko »

realthunder wrote: Sun Jan 27, 2019 11:59 pm if you want to store expression text in App::Placement for use by other object, then it is better to add some string type property of your own. I have just added python binding object for App::Placement so that you can do just that. Please sync LinkStage3.

Code: Select all

pla = App.ActiveDocument.addObject('App::PlacementPython')
pla.addProperty('App::PropertyString','Text')
pla.Text = expression
You can write an expression that accepts parameter, and later calls it when actually binding to some object using eval.
yes, that would work ... but would it make it into mainline ?

Code: Select all

// Python feature ---------------------------------------------------------
namespace App {
PROPERTY_SOURCE_TEMPLATE(App::PlacementPython, App::Placement)
template<> const char* App::PlacementPython::getViewProviderName(void) const {
   return "Gui::ViewProviderPlacementPython";
}
template class AppExport FeaturePythonT<App::Placement>;
}

This is a useful functionality, but quite an ad-hoc hack, don't you think ? If it was my money, I wouldn't bet on this horse. May-be as a general purpose feature that allows to add custom text fields to the properties of any object, through Python ... in the file ~/src/App/PropertyContainerPyImp.cpp there is :

Code: Select all

int PropertyContainerPy::setCustomAttributes(const char* attr, PyObject *obj)
{...

or in PropertyPythonObject.cpp

Code: Select all

void PropertyPythonObject::setPyObject(PyObject * obj)
{
    Base::PyGILStateLocker lock;
    aboutToSetValue();
    this->object = obj;
    hasSetValue();
}
try the Assembly4 workbench for FreCAD — tutorials here and here
User avatar
Zolko
Veteran
Posts: 2213
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Post by Zolko »

an App::Placement is also an App::GeoFeature

Code: Select all

PROPERTY_SOURCE(App::Placement, App::GeoFeature)

and App::GeoFeature has GeoFeaturePyImp.cpp

Code: Select all

int GeoFeaturePy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
    return 0; 
}

couldn't this be used ? I don't think that modifying the general App::Placement will be accepted. Either there is already a way to add custom fields/objects, and then it can be used, or a custom placement should be coded, derived from App::Placement but enhanced by useful fields/objects, and this enhanced Placement (Link::Placement ?) should be used for assembly. Actually, if this is meant to become the placeholder for constraints, having a purpose-built App::Placement derivative could make sense.

Of course, I have no idea how to actually code that.
try the Assembly4 workbench for FreCAD — tutorials here and here
Post Reply