[Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
paullee
Veteran
Posts: 5098
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Tue Jan 07, 2020 1:25 am

Code: Select all

class _WindowLink:

  def execute(self, obj):
...
Just another thought reading again some fundamental python wiki for beginner, sorry if below is silly :)

About "Python extended version of App::Link" / specialized LinkPython for _Window in this discussion -

Could this custom LinkPython multiple inherit / subclass the _Window object - so the method() (automatic update of placement in my experiment) can be used in the LinkPython ?


Then I do not need to maintain the same methods but now in 2 objects (the _Window object and custom LinkPython for _Window) twice.


Thanks.
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by realthunder »

paullee wrote: Tue Jan 14, 2020 7:22 pm Could this custom LinkPython multiple inherit / subclass the _Window object - so the method() (automatic update of placement in my experiment) can be used in the LinkPython ?
Calling other Proxy's execute is not a good idea. But if you can make a method in _Windows for just the placement calculation, then you can do something like this. Make sure calculatePlacement() does not change anything internal to _Windows class, just the Placement property.

Code: Select all

class _WindowLink
	def execute(self, obj):
		if isinstance(getattr(obj.LinkedObject, 'Proxy', _Window):
			obj.LinkedObject.Proxy.calculatePlacement(obj)
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
paullee
Veteran
Posts: 5098
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Tue Jan 14, 2020 10:31 pm Calling other Proxy's execute is not a good idea. But if you can make a method in _Windows for just the placement calculation, then you can do something like this. Make sure calculatePlacement() does not change anything internal to _Windows class, just the Placement property.
Thanks mentoring :) Not directly calling execute() indeed. I have a more general idea about how Link should better working calling methods() in LinkObject below... make sense ? ...


Pseudo-code

Code: Select all

Add a special method say LinkMethods() in every Objects for Link / LinkPython to identify this could be run 'Locally' and be called by a Link 'Remotely' in 'Child Link Instances '... 

class _Window:

	def execute(self, obj):
            ...
            self.LinkMethods(obj)
            ...

	def LinkMethods(self, obj):
            ''' Designated methods which could be called 'Locally' and also be called by a Link object to run as Child Instances '''

            self.LinkAddProperties(obj)
            self.LinkCalculateShape(obj)
            self.LinkCalculatePlacement(obj)
           
        @staticmethod
	def LinkAddProperties(obj):
            ''' Designated method to Add Properties that allows to vary in Link Object - i.e. to be different from the Linked Object in each Child Instances'''
            
            obj.addProperty("App::PropertyLink","Attachment","AttachedObject","Object to Attach on")
            obj.addProperty("App::PropertyInteger","Attachment","Offset-X","")
            obj.addProperty("App::PropertyInteger","Shape","Height","")            
            ...

        @staticmethod
	def LinkCalculatePlacement(obj):
            ... say this use Link's properties added by LinkAddProperties, Offset-X, to define this Child Instances specific Attachment

Code: Select all

Then a Link  / General purpose LinkPython can have methods, already identified and managed by the Linked Object itself, rather than writing specific LinkPython(say _Window) which needs itself to identify again which methods needs to run for each LinkObjectType.

class _GeneralLinkPython
	def execute(self, obj):
		if hasattr(obj.LinkedObject, 'LinkMethods'):
			obj.LinkedObject.Proxy.LinkMethods(obj)
Make sense ?

And should stock Link already can do this instead of making a general LinkPython ?

And have some related idea about Variant Link @Zolko in separate thread

Thanks again!

EDIT -
UseCases - Placing Frank Gehry's jumping window on his 'dancing house', placing (repetitive) doors on layout...
1024px-Praag,_Tsjechië_Aug_21,_2019_05-42-54_PM.jpeg
1024px-Praag,_Tsjechië_Aug_21,_2019_05-42-54_PM.jpeg (274.57 KiB) Viewed 2671 times
Source: wikipedia
Screenshot from 2020-01-05 02-15-37.png
Screenshot from 2020-01-05 02-15-37.png (239.29 KiB) Viewed 2674 times
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by realthunder »

That is actually not a bad idea. I'll add that feature, so that Link's execute() function will search and run python method in linked object with name 'appLinkExecute', passing the linked object and the Link itself as input arguments. For array elements, it will pass two additional parameters as parent link object, and element index. The method will look something like this,

Code: Select all

class _Window:
	def appLinkExecute(self, obj, linkObj, linkParent, index):
		pass
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
paullee
Veteran
Posts: 5098
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

Glad the concept is feasible to be implemented, and hope it is useful for other peoples :D

Can't wait to test !
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by realthunder »

PR submitted here.

Slight difference than the one described above. appLinkExecute() will not be called on array element object, only on the parent array link, with additional third (index) and fourth (element object) argument. In case the array is collapsed, fourth element will be None. If linkElement is not None, you can change its placement directly. If it is None, you can change the placement with linkObj.PlacementList[index]. Anyway, handling array is kind of tricky. I suggest you try normal link first.

Code: Select all

class _Window:
	def appLinkExecute(self, obj, linkObj, index, linkElement):
		pass

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
paullee
Veteran
Posts: 5098
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Wed Feb 12, 2020 9:33 am PR submitted here.

Slight difference than the one described above. appLinkExecute() will not be called on array element object, only on the parent array link, with additional third (index) and fourth (element object) argument. In case the array is collapsed, fourth element will be None. If linkElement is not None, you can change its placement directly. If it is None, you can change the placement with linkObj.PlacementList[index]. Anyway, handling array is kind of tricky. I suggest you try normal link first.

Code: Select all

class _Window:
	def appLinkExecute(self, obj, linkObj, index, linkElement):
		pass

Thanks, hope it is useful for many other peoples, and get merged soon :)
paullee
Veteran
Posts: 5098
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

realthunder wrote: Wed Feb 12, 2020 9:33 am Slight difference than the one described above. appLinkExecute() will not be called on array element object, only on the parent array link, with additional third (index) and fourth (element object) argument. In case the array is collapsed, fourth element will be None. If linkElement is not None, you can change its placement directly. If it is None, you can change the placement with linkObj.PlacementList[index]. Anyway, handling array is kind of tricky. I suggest you try normal link first.
Noting the PR had been merged, thanks!, finally I am testing (normal Link first as suggested) to implement a method to calculate its Placement in the Linked Feature Python :D

To enable that, I need a few parameters to be input by Users, so in original Feature Python, there are a few App::PropertyString added. For the Link objects, these are repeated in the appLinkExecute(). Whilst it works (screencapture), these lines would be run everytime appLinkExecute() is run ...

[EDIT - LinkObj rather than Obj ]

Code: Select all

class ArchSketch():

  def __init__(self, obj):
      if not hasattr(obj,"Test"):
          obj.addProperty("App::PropertyString","Test","TestLink","Testing - appLinkExecute")
  ...
  def appLinkExecute(self, obj, linkObj, index, linkElement):
      if not hasattr(linkObj,"Test"):
          linkObj.addProperty("App::PropertyString","Test","TestLink","Testing - appLinkExecute")
      print ("linkObj.Test is - " , linkObj.Test)
      print (self)
      print (obj.Name)
      print (linkObj.Name)
      print (index)
      print (linkElement)

Wondering if similar to appLinkExecute(), an appLinkInit() be added so whenever a Link is created, it looks if there is appLinkInit() and to run it for once ?

[EDIT - LinkObj rather than Obj ]

Code: Select all

class ArchSketch():

  def __init__(self, obj):
      if not hasattr(obj,"Test"):
          obj.addProperty("App::PropertyString","Test","TestLink","Testing - appLinkExecute")
  ...
  def appLinkInit(self, obj, linkObj, index, linkElement):
      if not hasattr(linkObj,"Test"):
          linkObj.addProperty("App::PropertyString","Test","TestLink","Testing - appLinkExecute")

  def appLinkExecute(self, obj, linkObj, index, linkElement):
      print ("linkObj.Test is - " , linkObj.Test)
      print (self)
      print (obj.Name)
      print (linkObj.Name)
      print (index)
      print (linkElement)

Thanks.

[EDIT - LinkObj rather than Obj ]
Screenshot from 2020-09-06 08-12-00.png
Screenshot from 2020-09-06 08-12-00.png (205.87 KiB) Viewed 2254 times
Screenshot from 2020-09-06 08-11-39.png
Screenshot from 2020-09-06 08-11-39.png (212.51 KiB) Viewed 2254 times
paullee
Veteran
Posts: 5098
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

Ok, further development and illustration of the idea of appLinkInit()

p.s.
' Link ' is added as equivalent attribute of the Linked FeaturePthon counterpart for distinction.

Assume there is no way to distinguish in a Link, if same attribute name is used, whether an attribute is owned by the Linked Object or the Link right ? Or any way to do so ? Much easier in programming in the methods.

Code: Select all

  def __init__(self, obj):
      self.setProperties(obj)
      self.setPropertiesLinkCommon(obj)

  def appLinkInit(self, fp, linkFp, index, linkElement):
      self.setPropertiesLinkCommon(fp, linkFp)

  def setPropertiesLinkCommon(self, fp, linkFp=None):  # fp and linkFp depends on caller
      link = ""
      if linkFp:
          fp = linkFp
          link = "Link"
      if not hasattr(fp, link+"XYZ"):
          fp.addProperty("App::PropertyLink",link+"XYZ",link+"Section")
      if not hasattr(fp,link+"MNO"):
          fp.addProperty("App::PropertyEnumeration",link+"MNO",link+"Section")
          setattr(fp, link+"MNO", [ "123", "456" ])

  def appLinkExecute(self, fp, linkFp, index, linkElement):

      # This below better called by Link once as __init__, rather than calling by appLinkExecute()
      self.appLinkInit(fp, linkFp, index, linkElement)

paullee
Veteran
Posts: 5098
Joined: Wed May 04, 2016 3:58 pm

Re: [Link] of (Sketch)ObjectPython / Part FeaturePython lose its 'Proxy Methods' ?

Post by paullee »

Further examine how setEditorMode() works and there is another issue, 3 issues so far related:-

  1. Suggestion / Feature Request - To add appLinkInit(self, obj, linkObj, index, linkElement)
  2. Adding Attribute counterpart to Link - Can same Attribute names be used?
    (trying to use "Link"+Attribute, but complicate programming in relevant method)
  3. Trying to hide in Links those Attributes of the Linked Objects, but display counterpart Attributes in LinkedObject (see item 2 above). Found hiding Links.Attributes in Links also hide the same in LinkedObj

Code: Select all

  def initEditorModeLink(self, fp, linkFp=None):

      propList = [ "XYZ", "MNO", "PQR" ]
      for i in propList:
          linkFp.setEditorMode(i, 2)  # 2=hidden
The above is supposedly invoked by a Link, but the LinkedObject as well as the Links have the all same attributes hidden.

Any way to setEditorMode independently for LinkedObjects and Links ?

It is very confusing to have 2 seemingly same sets of attributes, one being the LinkedObject's Attributes, which are not relevant in the Links anymore, but the LinkAttributes are, shown in the Link.
Post Reply