[Discussion] Drafting 2d annotations for architecture

Like I said before, I think it is better to handle lines and stuff inside a single a single Draft object, so you can use more efficient object model. FreeCAD objects may slow down the system because of all those onChanged() signaling. That being said, a database is probably an overkill for this.

BTW, I have actually made a few optimization on tree view, document loading and stuff for handling large amount of objects. I’ve tested with projects containing dozens of files, over 2k objects, loading in about 5 seconds. Most of the time is actually spent on loading the workbench for the first time. If those workbenches are preloaded, then loading time is less than 3 seconds. The loading time also depends on the content of the object, for example if those objects has complex geometries, etc.

So the idea of having a mean to add a sqlite file in the FCstd format is not too strange, and if ir used by a GIS program, that usually manage thousand of objects, will be a good solution, not said that the relevant libraries are already included in python, so non need to search anything strange.

What do you think?

Regards

Carlo D.

@carlopav : Didn’t meant to disrespect 2D :wink: I also think the act of “drafting/drawing/annotating” is needed everywhere, and also look at your model in plan or section very fundamental when doing architecture. I just don’t like the “here we work in plan and sections! Ah, you want a 3D view? Really?” paradigm of Revit. A great thing of FreeCAD is that it’s totally manageable to do almost anything directly in the 3D view that would be almost impossible in Revit (you wouldn’t be able to see what you are doing). We should take great care of that.

@onekk: In principle anything can be embedded in a FreeCAD file. That’s why the file format is designed that way. But I also think a database is overkill to solve an internal problem, unless you specifically need a database, like GIS. I would find it totally sound to have a GIS workbench save a database file inside a FreeCAD file. But then that GIS WB is sole responsible for dependencies, libraries, and all it needs.

Let’s start designing such a generic, multi-annotation (Draft) annotation! I think it is a very good path to go.

I think it should:

  1. not be shape-based, as there is no need for shapes here (no booleans, etc)
  2. contain “subobjects” like texts, dimensions, and generic geometry (that can yes be obtained from shapes)
  3. have a very nice and well-designed task UI and toolbar. Maybe actually it should be an own workbench? Like sketcher? That is activated on edit?
  4. coded in C++? I would find that pretty interesting for the speed, and if we start a separate WB, we can start from scratch really nicely. I did something very similar when we started coding Path, started with designed the “invisible” subobjects (Path command, path tool, etc…) then the FreeCAD docobject that holds them all, then the view provider, then the UI… I think it proved pretty solid

Yes, but someone has told that there will be problems fi there are many objects, why don’t use the database interface, a carefully created database could hold thousands of annotations and permit complex queries, and maybe some other nice things, like updating reference, and maybe searching annotations with conditionals.

a simple query could be done even in python, but for a complex query in say 10.000 annotations, maybe even the C++ code is complex to develop: let me explain.

import sqlite3 as sq3
import json

conn = sq3.connect('/home/carlo-arch/annotations.db')
c = conn.cursor()


def create_db():
    """Create table"""
    c.execute("CREATE TABLE annotations (Id INTEGER PRIMARY KEY, name, content, position, style)")
    conn.commit()

def populate():
    cnt = 0
    
    for idx in range (0,1000):
        cnt += 1
        name = "ann_" + str(idx)
        content = "contenuto dell'annotazione {0}".format(name)
        pos = json.dumps((idx, idx, idx))
        style = "style_{0}".format(str(cnt)) 
        c.execute("insert into annotations (name, content, position, style) values (?,?,?,?)", (name, content, pos, style) ) 
        if cnt > 3:
            cnt = 0    
    conn.commit()

def retrieve():
    for row in conn.execute("SELECT * FROM annotations WHERE style LIKE 'style_1'"):
        print(row[0], row[1], row[2], json.loads(row[3]), row[4])

#c.execute("DROP TABLE annotations")
#create_db()
#populate()

retrieve()

for testing you have to run create.db and modify the path of the database, in conn = sq3.connect(‘/home/carlo-arch/annotations.db’)

once you have created the table, feel free to modify the populate() and then launch it, or decomment both create and populate, for the first run.

Now you have the database, of 1000 or 10000 or even 100000 annotation, the table is simple, a name, holding:

  • Id as index that could be generated in a automated way due to the “PRIMARY KEY” value in the creation table
  • name that could be a meaningful name and could be used as a descriptor
  • content the content of the annotation, watever you want
  • pos a field that hold a tuple that is serialized using json, so it could hold whatever you want, maybe directly a Vector, we could try
  • style a reference to the style_name, the proper style definition could be put maybe in another table where style_name could be the primary key

now after having created those hundreds of annotations, yoiu could retrieve them using simply a query like:

.execute(“SELECT * FROM annotations WHERE style LIKE ‘style_1’”):

if you want search in a big project some other things, maybe the author in a collaborative environment, add a author field and you could sort using conditionals using the style and the author.

writing simply a string “SELECT * FROM annotation WHERE style LIKE 'style_1” AND author LIKE ‘yorik’", and then simply iterate in the row objects of the returned query.

No need to write if then else or so.


storing the important information of an annotation could even create them on the fly in the final document, if needed.

Not telling that a BLOB field in sqlkite coudl hold a 1MB binary data that maybe could contain directly the object if it serialized in some way.

Regards

Carlo D.

Indeed i see it works for you, but not for me.

@onekk I have no experience to understand if there is some hidden potential that Yorik and realthunder do not spot in the approach you are suggesting abut using a database for annotations… Let’s think about that some more time…

I know :slight_smile: I just wanted to state it is fundamental to me.
And I also agree that everything has to happen inside the 3d view, since that’s the true meaning of a plan, to be a schematic representation of a plane cutting the 3d space! What is more satisfying than seeing this happen?

  1. coded in C++? I would find that pretty interesting for the speed, and if we start a separate WB, we can start from scratch really nicely. I did something very similar when we started coding Path, started with designed the “invisible” subobjects (Path command, path tool, etc…) then the FreeCAD docobject that holds them all, then the view provider, then the UI… I think it proved pretty solid

This perspective seems really promising. What about completely discarding the z coordinate for those subobjects?

After having thought on the db approach, I’ve envised some critical points, that could be put in the discussion.

Developer are facing generally the problem of speed when doing searches, for which a relational db like sqlite is tailored for this scope, so qhy not leverage his power in doing such things.

Said so the main concern of a developer could be “the binary format could lead to data corruption”, the answer is yes.

But if we are dealing with thousand of objects maybe a search would be using much horsepower, using the object directly.

Why not leveraging the power of sqlite to construct some “pivot table” between relevant data and the real objects?

think a document with thousand of objects, and maybe you will search for a particular object that have one property that interest you.

maybe simply you want to find all objects, with a particular name or whose position is between a min point and a max point.

if you build a table containing the object data and the object relevant reference, like this:

CREATE TABLE objects (Id INTEGER PRIMARY KEY, name, fcid, label, bbmin, bbmax, … )

fcid is the internal FreeCAD id number, or maybe the unique name property, i.e the identifier for this objects that permit to retrieve it correctly by the subsequent code.

then you make a slection like:

SELECT * FROM objects WHERE name LIKE “whatyouwant” AND bbmin > yourminpos AND bbmax < yourmaxpos"

you will find all the relevant object and maybe load in memory only these objects.

This pivot table could be stored in the file, or maybe build at the loading of file.

Same thing should be done with annotations, maybe an XML file, or a csc file could hold the data (for an easy “crash recovery”) and a pivot table stored in the file, or rebuild on loading.

eventually a mean to rebuild such tables could be supplied.

When dealing with thousand of objects, this will be a correct approach, a similar approach is used in BRL-CAD (I know it is jurassic but it have been built for dealing with complex objects) it use a database for holding all the 3d objects and use this when for example it id doing ballistic analysis (it was build by the US army in fact his name mean Ballistic Research Laboratory - CAD).

Anyone who has programmed a complex search could catch the amount of work needed to put in place a query, with sqlite is only matter of doing a query and iterate through the resulting list of database rows, not telling that the selct could only return the relevant internal id to retrieve the objects, using:

SELECT fcid from objects …

Regards

Carlo D.

@onekk I haven’t read this thread in details but JFYI have you seen: https://github.com/furti/FreeCAD-Reporting “SQL Like Reporting for FreeCAD Documents” ?

No I haven’t read it, but the approach is different, here we are discussing about to imlement a sqlite database to manage the possibly thousand annotations in a big project, the example project from which at least I’m thinking is a multi plane building, with one or maybe multiple 2d “floorplans” with a bunch of lines and annotations (think maybe as HVAC or wiring harnesses) with many annotations on them.

So maybe with 10 or 12 plans, and 3 2d drafting you have thousand of annotations.

We are speaking of leveraging the relational database module based on sqlite3 “on board” of python 3 to manage the searching or maybe to hold the entire annotations structure.

Maybe during the saving of the work in FCstd file some of this structure could be translated in some other format, XML, or even csv.

During the opening phase of the FCstd file, the data are put in the sqlite3 structure to permit fast queries and updating the structure using the sql syntax.

Some ideas are arising, so we have to decide one way to spedd up such project, someone has proposed to sepdd it up using C++ interfaces, but for not reinventing the wheel, I’ve proposed to leverage the “ready made” python sqlite3 interface already “on board” as a standard library in python.

Hope to have been almost clear.

Carlo D.

About databases: You might have a point there, working with some kind of database structure could mean speed improvements over the current way FreeCAD works, but if we would want to apply such thing to whole FreeCAD it would mean a complete rewrite of very large and deep parts of FreeCAD itself. I don’t see that even remotely likely to happen. And doing it just for one small part (annotations) seems to me a huge work when using existing tools is pretty straightforward, specially that there is no guarantee it would effectively bring any useful improvement.

If you want to pursue this path and build something to test, it would definitely be interesting. But I guess it would be your job to prove your point there :wink:

Sadly without some support, I can’t develop entirely all alone, the main concern is how to be able to add the db file into the FCstd format.

This have to be done by some developers, as touching the File format is a delicate things, or at least have some assistance on working on this matter.

It suffice to have two exposed interface, save_to_file and load_from_file (as file in intended to be the FCsd document) this will lead to many expansion in future, as it is easy to incorporate other file formats, when using or developing a workbench, not too many other things are needed.

Once there is the ability to store a "custom "file in the compressed format and tto be able to retrieve it, no more work will be requested.

I’m thinking of coupling at least in the development phase the db file in the user directory, so it is persistent here, and experimenting with this one.

Best Regards

Carlo D.

This could be good to develop a proof of concept for the community to evaluate.

By the way, let’s not lose the focus on the topic subject!

I noticed that FreeCAD have already an App::Annotation and an App::AnnotationLabel object. Would those be of some help?

I think the best place to start with, for the structure would be in Path: https://github.com/FreeCAD/FreeCAD/tree/master/src/Mod/Path/App
There you basically have the “Command” object which is a basic GCODE command. then the “Path” object that is nothing more than a list of commands. Then the “PropertyPath” which creates a Path property, then the “FeaturePath” which is the actual FreeCAD object, that has a “Path” property, which can hold a Path object, which is itself a list of Commands.

All this is derived from base FreeCAD classes, so it inherits a lot of interesting abilities, such as how it must be saved to the file, structure for easy python bindings, etc.

Then the GUI to make all this is something else, but it roughly follows the same structure as above.

I think we could start with something similar:

  • A base Annotation class
  • A Dimension class, a Text class and a Symbol class (and possibly others in the future), all derived from the above
  • An “Annotations” property, that would hold a list of Annotation-derived objects
  • An Annotation Feature that has an Annotations property
  • A GUI object for the AnnotationFeature, that would have an edit mode just like a sketch. You manipulate the individual Annotations through it, the same way as the sketcher works.

This is a very “visual” object, it doesn’t make much sense without a GUI. So I don’t think there is much sense to separate the individual properties of dimensions, texts and symbols into App and Gui counterparts… Specially that they won’t be directly manipulatable outside the Annotation Feature’s edit mode.

Bascially each Annotation object should:

  • have a name
  • have a series of attributes such as start point, end point, color, text fonts… All that is needed for each of them
  • be able to render a coin version of itself
  • provide a list of control points
  • be able to save and restore to file
  • have all its attributes manipulatable through python

The AnnotationFeature should:

  • have a placement
  • be able to save and restore to file by calling save/restore of each of its annotations

The ViewProvider should:

  • contain a transformation node with the placement data
  • be able to render a coin version of itself by gathering the coin nodes of each of its annotations
  • have an edit mode

The edit mode should:

  • Show a list of annotations where one can click through, delete, rename or add new
  • When one clicks an annotation, all its properties should be available to edit
  • When one clicks an annotation, its control points should appear in the 3D view and be draggable by the user

How does that sound?

Simply great! How can we start? Can you setup a branch containing an empty c++/python Annotations Wb?

Really struggling to do some annotation :slight_smile: But find can’t follow the advanced technical discussion here :blush:
Screenshot from 2020-05-30 08-02-04.png

Edit: reporting this interesting topic by @chakkree
https://forum.freecadweb.org/viewtopic.php?f=23&t=48040

Currently, it is difficult to put it fittings like bathtub, toilets, basin, sink etc.

Used to have numbers of blocks available in AutoCAD, but there is only a few found in the Part Library.

It is currently both difficult to draw these objects in Draft as 2D or make them as 3D objects :slight_smile:
(maybe better drawing as 2D in Sketch)

As simple as a bathtub e.g., say just want to put a 2d shape in the model for 2d drawing ( before a simple 3d one is available ) -

Can this bathtub be contained in an FC object instead of 3 ?

So it can more easily be moved around, cloned / app:link, numbers counted etc.

Any idea ? Thanks.
Screenshot from 2020-07-01 08-29-51.png
Bath-1_ 1.FCStd (6.11 KB)

How about using a Std_Part and then linking to it with Std_LinkMake?

You could even put all bathroom furniture in an external file.
And have several versions of that file (2D, simple 3D, complex 3D).

Thanks @Roy_043 for the Std_LinkMake :slight_smile:

Have tried DraftLinkArray etc. but not knowing Std_LinkMake yet. However, this needs a numbers of object.


I can make in Python console the shapes in the 3 objects into a dump Part object with compound of the shapes mentioned.

But there are few problems though:-

  1. Haven’t found GUI command to do that - not very handy to do that in Python console
  2. It is a dump Part object, can’t easily edited

Screenshot from 2020-07-01 19-26-47.png
Bath-1_ 1.FCStd (15.9 KB)