Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to refer to file contents? #11

Open
ceremcem opened this issue Sep 29, 2018 · 5 comments
Open

How to refer to file contents? #11

ceremcem opened this issue Sep 29, 2018 · 5 comments

Comments

@ceremcem
Copy link

"File" type only includes the file's name, not the contents. How can we refer to file contents, for example a text file?

@mwganson
Copy link
Owner

mwganson commented Oct 3, 2018

Sorry, I didn't see your issue until today.

Yes, the File property is really just a string pointing to the filename and path with an editor that allows you to set the property value by selecting the file via the open file dialog.

One of my goals for these dd objects is that they will be fully compatible with FreeCAD installations that do not have DynamicData workbench installed. I want it to be possible, for example, to create a model using a dd object, upload the model to the forum, and other users will be able to download and use the model even if they don't have the workbench installed. Because of this I cannot add code to make the dd object respond to property change events or to have functionality for the dd object to read file contents. Basically, these dd objects are just "dumb" property containers.

What did you have in mind exactly? I could probably come up with a workbench command that would enable you to read the contents of the file in the File property and place those contents into either a FloatList or a StringList. The List object could then be accessed with the Expression Engine as an array, e.g. dd.ddFloatStrings[0]. The data would then be held in the dd object and would survive saving to disk and reloading from disk.

@ceremcem
Copy link
Author

ceremcem commented Oct 3, 2018

Thanks for the answer. I'm trying to provide script embedding functionality to FreeCAD as I need it. This requires to add the script contents into the fcstd file. Although it might be done manually (copy and paste) this will lead some human errors in the end, so I'll need an automatic flow.

Besides, I need something like lookup tables when I wanted to construct more parametric designs (https://forum.freecadweb.org/viewtopic.php?f=3&t=30720&p=254625#p254496) , which will require a tiny database engine in the end, so this also will require the scripting support.

I can understand that this might be out of scope of this workbench, so I may fork and modify it for my needs, but I wanted to ask first.

Rationale

I think the "single file models" can't be the way to go, because a typical CAD design will require tens of other CAD files (like a typical program would need tens of external libraries) so if a user wants to share a model, it will probably require lots of fcstd files, which would lead the users put them into a zip file at least, usually a git repo. (the git repo would require human readable file format, not fcstd: https://forum.freecadweb.org/viewtopic.php?f=8&t=31026). Anyway, a non-trivial CAD design won't fit into a single CAD document. That's why we should be prepared and should provide a way to read/write external files (like txt, json, etc.), so we could easily generate 3D models from regular files.

For example, I needed a functional bolt model that will be used to cut the other solids. I draw a couple of cylinders and I was good to go. When I wanted a longer bolt, I copied and pasted the file, renamed it accordingly and updated its length parameter. Now I have 2 bolt files for 2 variants of the bolt. Then I wanted to add flat head bolt. I added a cone to one bolt. Now 2 files differ (one has cone and one doesn't). This might be simplified by a simple lookup table.

@louisgag
Copy link

louisgag commented Mar 5, 2020

Hi,

I find your Workbench quite useful, especially for the parametric feature.

Sorry if I am reviving this old issue, but I am facing a similar problem:

I use external software to do some animations and analyses and it needs to know, for example, where some part/body/feature is in FreeCAD. Inversely, I also want to modify this Placement (or other) data externally and then automatically update my FreeCAD model consequently.

I know I could do this by calling each object as such FreeCAD.getDocument("testDocument").getObject("dd").ddTestPlacement and then finding a way to convert the name and numbers to some text file and doing somewhat the opposite when re-importing such as tVec = App.Placement(App.Vector(0,0,0),App.Rotation(App.Vector(0,0,1),0))
FreeCAD.getDocument("testDocument").getObject("dd").ddTestPlacement = tVec
but that means writing some code for each specific dd custom property. I was wondering if there is an easier way that escaped my quick look at the code and forums?
EDIT: what I describe here will actually not work because tangling with the dd object that is parametrically linked to a feature will eventually be cancelled by the parametric link itself...

@mwganson
Copy link
Owner

mwganson commented Mar 6, 2020

I'm not sure I understand exactly what you are trying to do. Perhaps you can link the FreeCAD object parametrically to the dd property. Then when you change the dd property the FreeCAD object will update itself.

One way you could perhaps (fairly easily) get contents of a text file into DynamicData is to copy and paste multiline text (numbers only) into a FloatList property. You could then access those values from other dd properties by indexing into that FloatList. For example, a Float type property could be set to =dd.ddMyFloatList[2] to get at the number in the 3rd line of the text file, which was copied and pasted into the ddMyFloatList property editor. You could probably update the FloatList property via script that reads the text file and updates that property.

If you were doing a placement property this way you could have the lines of the file be:
angle
x_axis
y_axis
z_axis
x
y
z

Then you could access, for example, the angle property as =dd.ddMyFloatList[0] and the z coordinate as =dd.ddMyFloatList[6]

As I mentioned before, one of my goals for this workbench is for people to be able to use the models created using it even when they don't have the workbench installed. This means I can't have the dd objects dependent upon special code that would add extra functionality, such as being able to automatically update the properties by reading them in from another file.

@louisgag
Copy link

louisgag commented Mar 9, 2020

Hi, sorry that I was not clear. I had not understood that parametric links are not bidirectional.

I agree and understand why models created using the workbench should be compatible with FreeCAD versions that don't have it installed. But, that doesn't exclude the possibility to dump and read from a file. Reading could simply be manually done or automatic and user-activated through a function which checks whether the DD workbench is installed. I also understand that this may be out of scope for this workbench.

Thanks for the method you suggested using a FloatList. Elaborating a bit on that and trying to render the process as transparent as possible I wrote a pair of (very rough draft) macros to dump and load data from a file. I'm sharing them here should someone have the same need, but keep in mind that they are only written for my own purpose and will need adjustments and further elaboration should anyone want to seriously use them. Also @ceremcem suggested using JSON and I suppose this macro draft could be easily adapted to do so, as long as the chosen objects remain Python "standard" (ie: no Placement and other internal classes).

What they do is parse the objects within a selected Dynamic Data object, find those that match a pattern inserted in their name, find within those the Placements (this can be easily extended), and dumps the Placement's matrix into a file. The load macro does somewhat the opposite.

ddName='dd001' # set the name of your Dynamic Data container
ddPattern='Torus' ## chose a text pattern that will identify each dd object you wish to export (here "Torus")
ddDumpFile='/home/louis/Desktop/exportFreeCADdd.txt'

ddDump={}
ddd=FreeCAD.ActiveDocument.getObject(ddName)
for i in ddd.PropertiesList:
  if ddPattern in i:
    if 'Placement' in str(type(getattr(ddd,i))): # only doing Placement objects at the moment, can easily be extended
      ddDump[i] = getattr(ddd,i).Matrix.A
with open(ddDumpFile, 'w') as F:
    F.write(repr(ddDump))

ddName='dd001' # set the name of your Dynamic Data container
ddDumpFile='/home/louis/Desktop/exportFreeCADdd.txt'

import ast
with open(ddDumpFile,'r') as F:
  ddLoadStr = ast.literal_eval(F.read())
for i in ddLoadStr:
  theTup = ddLoadStr[i]
  theName = i
  try:
    setattr(FreeCAD.ActiveDocument.getObject(ddName), theName, FreeCAD.Matrix(*theTup))
  except:
    print('Failed to set value for ' + theName)
    pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants