assembly without solver

Discussion about the development of the Assembly workbench.
User avatar
fosselius
Posts: 319
Joined: Sat Apr 23, 2016 10:03 am

Re: assembly without solver

Postby fosselius » Sun Jan 27, 2019 9:54 pm

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()
Zolko
Posts: 219
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Postby Zolko » Sun Jan 27, 2019 9:58 pm

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.
User avatar
fosselius
Posts: 319
Joined: Sat Apr 23, 2016 10:03 am

Re: assembly without solver

Postby fosselius » Sun Jan 27, 2019 10:01 pm

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
Posts: 939
Joined: Tue Jan 03, 2017 10:55 am

Re: assembly without solver

Postby realthunder » Sun Jan 27, 2019 11:59 pm

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 (latest version 0.9.1) along with my custom build of FreeCAD at here.
And if you like to show your support, you can find the donate button at here.
Zolko
Posts: 219
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Postby Zolko » Mon Jan 28, 2019 8:30 am

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.
User avatar
fosselius
Posts: 319
Joined: Sat Apr 23, 2016 10:03 am

Re: assembly without solver

Postby fosselius » Mon Jan 28, 2019 10:49 am

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 268 times
Last edited by fosselius on Mon Jan 28, 2019 12:24 pm, edited 1 time in total.
Zolko
Posts: 219
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Postby Zolko » Mon Jan 28, 2019 12:18 pm

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 270 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 5 times
User avatar
fosselius
Posts: 319
Joined: Sat Apr 23, 2016 10:03 am

Re: assembly without solver

Postby fosselius » Mon Jan 28, 2019 12:27 pm

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.
Zolko
Posts: 219
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Postby Zolko » Mon Jan 28, 2019 2:17 pm

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();
}
Zolko
Posts: 219
Joined: Mon Dec 17, 2018 10:02 am

Re: assembly without solver

Postby Zolko » Mon Jan 28, 2019 2:49 pm

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.