Index
The project grew up arond the GObject library: the ADG canvas is developed in plain C using the object-oriented approach supplied by GObject. This does not mean an ADG based application must be developed in C: the basic idea, when the API will be stable enough, is to have a set of language bindings for higher level languages (above all the garbage-collected ones). Then the application could be developed using these languages much in the same way as GTK+ applications are conceived. The first language supported will probably be LUA.
The rendering is based on the cairo engine, so the ADG project fully shares strong and weak points of the underlying cairo library.
For the optional database connectivity my suggestion is to look in the libgda project, partly because it is an actively maintained project and partly because it uses the same technology (object-oriented C code using GObject and language bindings), so it can be easily integrated in a single application.
Basically, an application based on ADG must fulfill the following tasks:
The model is the abstract representation of the drawing subject (or part of it). The most common one is probably the AdgPath class, a model built around the cairo_path_t struct.
The units used in the model definition are not relevant, as they will became signicative only while used by an entity. It is common practice to use obvious units: for instance, in Italy you will use meters for building plants and millimeters for mechanical parts. When adding to the canvas an entity binded to this model, you should set a proper local map to scale the result as needed and get the proper ending scale.
You can have as many models you need, depending on the application complexity. For instance, if the part you want to manage changes a lot only on some specific detail, you can consider to move this everchanging piece on its own model leaving the rest in another one, and join the models just before populating the canvas.
Also, a single model can be referred by as many different entities as you need: for example, the same model can be used by more AdgStroke entities, thus allowing rendering with different maps.
This operation transposes the model to the view. Just instantiate an AdgCanvas and add entities inside it in the same way you construct a user interface in GTK+. Together with some representation of the model you will probably would like to add other decoration entities such as title block, dimensions, hatches and whatever needed to get the final drawing.
Drawing by hand or with a CAD gives you full control: you can choose where positioning quotes to avoid overlapping. An automatic drawing system doesn't have the cognition of proper position and a collision detection system is beyond the scope of this project. The ADG way to solve this issue is to provide everything needed to escape from (hopefully) any situation, allowing to customize almost everything. It is up to the application to put the quotes in a better place or to choose a proper scale.
One key concept of this approach is the use of two matrices that can be set transformed by every AdgEntity and derived objects: the global matrix and the local matrix.
To grasp this concept, here are two shots of the adg-demo test program (found in the demo directory). The image on the right shows the same canvas with a local matrix scaled up while the global matrix is still the same.
As you can see, the model shape is scaled and the endpoints of the quotes followed this change but some other stuff kept the original scale, such as line thicknesses, text and arrow sizes, the distance from the extension lines to the shape and the spacing between the baselines.
You can think to the global matrix as a magnify glass: modifying it affects everything on the canvas. It works about the same way the traditional zoom works (allowing also translations, rotations and everything you can do using a matrix). As such, the global matrix is always applied, and it is applied as last transformation. The local matrix instead is quite unusual: it affects only something, mainly related to the model. It can also be "normalized" before being applied.
These two matrices can't be set directly. Instead the AdgEntity class provides APIs to manipulate the so called maps (short for affine maps). Every matrix is the result of combining by multiplication all the maps on the entity hierarchy.
In a typical example of an entity inside a container, the local matrix of the entity will be computed as follow (the same will apply for the global matrix):
AdgMatrix matrix, map;
adg_entity_get_local_map(canvas, &matrix);
adg_entity_get_local_map(container, &map);
cairo_matrix_multiply(&matrix, &map, &matrix);
adg_entity_get_local_map(entity, &map);
cairo_matrix_multiply(&matrix, &map, &matrix);
This allows some funny thing, such as scaling only a group of entities inside the same container or placing the same model more times in a canvas applying different matrices. Consequentially, changing the AdgCanvas maps will affect every entity.
By default global and local maps are initialized to the identity matrix, that is a matrix that doesn't change the source.
The rendering customization is provided throught the interaction of the following ADG components:
The style is the brick over which all the customization is done. Being a huge task that could grow beyond any guess, the ADG approach is to implement the styles in an opened way, without knowing or guessing anything about them.
This means adding a new style is a matter of subclassing AdgStyle: the only requirement is to implement the apply() virtual method. You could put all the stuff you consider style stuff inside this new class: it is handled as an opaque object by the ADG library itsself. A new style will be likely used by a new entity, so you'd probably access the style instance only from the render() method of this new entity.
In the default implementation all the styles will be resolved by adg_dress_get_style(), but this implementation gives a good level of freedom, allowing the cascade overriding of a dress style with a single adg_entity_set_style() call. When required, new AdgDress values can be easily added with adg_dress_new(). Every dress always requires a default style, just to be sure to resolve any request as stated above.
To be useful, the canvas needs to be rendered somewhere. For convenience, the ADG library provides AdgWidget if the library has been built with GTK+ support enabled. This is a GtkWidget that can be embedded inside a GTK+ user interface but it is meant only as a demo widget.
In general you should use plain cairo to create the surface. The following example shows a quite basic way to render a canvas to a pdf file:
void
render_to_pdf(AdgCanvas *canvas)
{
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_pdf_surface_create("test.pdf", 841, 595);
cr = cairo_create(surface);
cairo_surface_destroy(surface);
adg_entity_render(ADG_ENTITY(canvas), cr);
cairo_show_page(cr);
cairo_destroy(cr);
}
You can check the demo/adg-demo.c source file for further examples.
Technical detailswas last modified by Nicola on Mon 19 Oct 2009 11:19:49 PM CEST