Skip to main content

Posts

Showing posts from October, 2008

Shadows

Not the most important use of rendering code..

:)

Symbols and Elements

I have made attempts over the years to draw triangles and circles like, for example, this:
(in fact, this was drawn by David Westhead's code). There is a small design decision to be made between representing drawing elements as basic geometry or as symbols. A symbol may be the same as a geometric element (like a circle), but it might be a combination of them. Consider the 'N' and 'C' in boxes, above. Or this image:
where the mass number and charge are separate text elements on the left, and part of the whole symbol on the right. Neither is a 'better' way of doing things; they each have their advantages - and disadvantages.
It can be a lot clearer to use symbols, as each model object (atom, bond, helix, gene, cell) has a corresponding representation, and then a diagram composes the symbols into a manageable whole. On the other hand, you can re-use elements in different combinations for diagrams. A general vector drawing package would have Line, Text, Rectangle,…

The Trouble with Tribble Visitors

So, I'm now partly sold on the power of a Visitor approach to rendering. Consider this snippet:
if (clicked) diagram.accept(new DropShadowVisitor(g, 5, -5);
else         diagram.accept(new DrawVisitor(g));
What this is doing is drawing a diagram normally unless the mouse is clicked, when it draws with a drop shadow. I see that the beauty of this is the ability to manipulate functionality as a block (just as in languages where you can pass around functions...).
However, I should point out that the approach has its tricky rapids as well as such smooth sailing. The image below is a spot-the-difference (click for bigger):

On the left is the version drawn by a naive first try at the drop visitor. Its methods look like this, the visitText(Text text) method:
g.setColor(Color.LIGHT_GRAY);
g.drawString(text.text, text.x, text.y);
g.setColor(Color.BLACK);
g.drawString(text.text, text.x + dx, text.y + dy);
The problem with this code is subtle - the elements are visited…

Arvid's Renderer Design

This is a sketch of my understanding of Arvid's renderer design:

I say 'my understanding' with good reason - a diagram can be biased, even a formal(ish) one like this, so I don't claim that this is definitive!
It is interesting, anyway, as it seems to be a combination of a Composite and a Visitor pattern. The RenderingModel implements IRenderingElement (and Iterable of IRenderingElements), which is Composite.
The Modules are Elements in the Visitor pattern, and the Elements are Visitors.
edit: What nonsense I talk! The IRenderingElements are Elements and the  IRenderingModules are Visitors. That's better.

Font Management and GlyphVectors

Fonts and text are always a pain when drawing vector graphics!
After hitting myself over the head over a stupid bug in my zoom tests (like this:)JButton inButton = new JButton("IN");
inButton.setActionCommand("IN");
JButton outButton = new JButton("OUT");
inButton.setActionCommand("OUT");I got center scaling implemented in my branch. Which lets me test a different approach to managing fonts. I had tried to be clever and do something like:GlyphVector glyphs = font.createGlyphVector("N");
ArrayList shapes = new ArrayList();
for (int i = 0; i < glyphs.getNumberOfGlyphs(); i++) {
shapes.add(affineTransform.getTransformedShape(glyphs.get(i)));
}
but letter shapes fill horribly with lots of missing pixels. Anyway, I eventually settled on just storing the Glyphs themselves. Less pure, but it works, and it allows the size of TextSymbols to be computed and used by the class in between drawing.
So, for fonts there had to be a way in my architecture to…

A correction, and a simpler example

There was of course a deliberate mistake in the previous post:
as the highlighting shows, the matrix for cubane numbered PVR style is neatly divided. A simpler example is cyclobutane:
which also shows the important point that, even if the sum of the row-numbers is the same as for other possible numberings, the PVR numbering is still the only ordered one.

On Canonical Numberings

So, after reading* this (2005) paper : "On Canonical Numbering of Carbon Atoms in Fullerenes : C60 Buckminsterfullerene" (link) I made some pictures to illustrate the difference between it and the numbering scheme used for SMILES (as described here). Er, which is used in the CDK.
Anyway, the point is that the scheme used by Plavšić, Vukičević, and Randić (or PVR as I will refer to them, I hope they don't mind!) numbers the atoms in a way that produces an adjacency matrix with a particular property. If you consider the rows of the matrix to be binary numbers, then the set of numbers is the smallest possible. So, for example:

The structure on the left is cubane, with its adjacency matrix on the right. The column on the far right shows the rows of the matrix in base 10. They are clearly in order. Now what happens for the SMILES? Well:
Here, the rows are neither in order (I'm not sure from their paper whether the ordering is an expected outcome for all structures, nor have …

KDTree in SymbolTree

So, the new Symbol tree base class now has a working implementation of a KDTree. (Or as close as the test can tell). What this means is that, should you ever need to edit (not just display) a very large 2D structure, you would do something like:
SymbolTree tree = createTree(); // get a tree somehow
tree.setHitDistance(minDistance); // the minimum distance from mouse to symbol
tree.useKDTree(true); // essential
tree.highlightClosestSymbol(point); // will now do a fast search for the closestOf course, this is really only useful for a) large trees and b) when doing many "closest symbol" operations. For example, highlighting when moving the mouse.

The best situation would be to dynamically call the "useKDTree" method when the size was above some threshold (100 atoms?). The interface is the same, either way.

Steps to move Bioclipse to the new CDK plugins

Thanks to egon the monolithic cdk plugin is now about 40 small plugins. Here's how to migrate...

In no particular order:

Step 1: Delete plugin org.openscience.cdk from the workspace
Step 2: Download the third-party library plugins from bioclipse2/trunk/cdk-externals/
Step 3: Download the (many) new cdk plugins from bioclipse2/trunk/cdk-externals/trunk/
Step 4: Update those plugins that complain about missing org.openscience.cdk dependency
(Step 5: Possibly change the Require-bundle for org.apache.log4j : as in this bug report)

It should now all compile...

The cdk renderer forest

CASE Diagram

Just a sketch:Of course, if the structure source is a database, then it would make more sense to generate the spectra beforehand. So it would then be a spectrum source, I suppose.

Ultimate Generic Diagram

Sorry, I couldn't resist, but when reading this paper (see also : this) I came across this paragraph :
The compilation of metabolic data sets comprises three aspects. Each analytical data aquisition produces numerical values as estimates of metabolite concentration [...] Second, all such studies involve biological material [...] and a particular study context and this produces a wide variety of supplementary data (metadata). Finally, many studies process the data further using a variety of algorithms and then subject the data to statistical or bioinformatic analysis..
and made this (fairly foolish) diagram) for myself. I then realised that the diagram covers almost anything, and could be safely incorporated into almost any talk :)

Of course, the symbols (ab)used are very vague - what should be a package is here some kind of 'context'. Who knows, I suppose there is correct UML for this, but anyway.

Oh, and I'm not mocking the original authors - I just realised that what I d…

What's on my whiteboard?

Current situation with Seneca and Medea.

This is a better picture of what the dependencies were like in bioclipse:

The dashed lines indicate some kind of vague boundary between plugin 'layers'. There's no such concept of a plugin layer, as far as I know, but still. Of course, there is the net.bioclipse.core plugin, which could be considered to be an inner core.
It may be an artificial distinction to make between the 'data' and 'analysis' layers, but basically the data plugins do the open-edit-save cycle mentioned here while the analysis plugins do more. Specifically, the seneca and medea plugins can produce spectra data from molecule data.