File: glBoundingBox.tex

package info (click to toggle)
ball 1.5.0%2Bgit20180813.37fc53c-11
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 239,924 kB
  • sloc: cpp: 326,149; ansic: 4,208; python: 2,303; yacc: 1,778; lex: 1,099; xml: 958; sh: 322; javascript: 164; makefile: 88
file content (285 lines) | stat: -rw-r--r-- 9,928 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
\section{Building a bounding box processor}
\label{section:bounding_box_processor}

The processor we create should compute a bounding box for the molecular structure
it is started from. Then a GLSimpleBox will be created with the calculated
boundaries and appended to the root of the processed structure if that root is
of kind System. Otherwise no bounding box will be created. The color of this
bounding box can be set in the preferences tab widget discussed in the VIEW section 
\ref{section:view_construction_of_a_dialog} tutorial.
To create a bounding box of a molecular structure we must calculate the lower left 
and the upper right corner of the box enclosing all Atom objects in the molecular
structure the processor is started from. To achieve this goal we iterate over all atoms
and create a Box3 containing only the processed atom then we join the new box
with the previously constructed box.
The implementation follows (includes are omitted):

\begin{lstlisting}{}
class GLBoundingBoxModel: public BaseModelProcessor
{
	public:
		GLBoundingBoxModel();
		virtual ~GLBoundingBoxModel();

		void setColor(const ColorRGBA &color);

		virtual bool start();
		virtual bool finish();
		virtual Processor::Result operator() (Composite& composite);

	private:
		ColorRGBA color_;
		bool new_start_;
		Composite* start_composite_;
		Box3 bbox_;

};
\end{lstlisting}

The processor is derived from BaseModelProcessor because
it should iterate over all atoms in the molecular structure it is started from.
There are three important methods that must be overridden for the processor
to function correctly.\\
First we implement the method {\em start}. This method performs any initialization
needed by the processor. If the processor is started we keep the Composite object
it is started from because later in the finish method we use this composite to get
any information about the molecular structure the bounding box was created for.

\begin{lstlisting}{}
bool GLBoundingBoxModel::start()
{
	new_start_ = true;
	start_composite_ = 0;

	return BaseModelProcessor::start();
}
\end{lstlisting}

Next we override the method {\em finish} that can do some cleaning. In this case
however we have no need of such a thing. But if the method finish is called
all atoms of the molecular structure are processed thus the bounding box is computed.

\begin{lstlisting}{}
bool GLBoundingBoxModel::finish()
{
	Composite *root = &(start_composite_->getRoot());

	if (bbox_.a == bbox_.b || !RTTI::isKindOf<System>(*root))
	{
		return false;
	}
\end{lstlisting}

If the calculated box is degenerated or if the root of our start composite is
not of kind System we do not create a bounding box.

\begin{lstlisting}{}
	MolecularInformation molecular_information;
	start_composite_->host(molecular_information);                        
\end{lstlisting}

Next we use the MolecularInformation visitor to get some information about the
molecular structure of the start composite.

\begin{lstlisting}{}
	GLSimpleBox *pbox = new GLSimpleBox();
	pbox->setVertex1(bbox_.a);
	pbox->setVertex2(bbox_.b);
	pbox->PropertyManager::set(*this);
	pbox->setColor(color_);
	pbox->setName(String("BoundingBox of ")
								+ molecular_information.getTypeName()
								+ String(" (")
								+ molecular_information.getName()
								+ String(")"));
\end{lstlisting}

Now we create a GLSimpleBox with the boundaries of the calculated box, set the
color and properties of our dialog into the GLSimpleBox and set name with the help
of the {\em molecular\_information}.
																										 
\begin{lstlisting}{}
	root->appendChild(*pbox);

	return true;
}
\end{lstlisting}

The last command will append the created bounding box to the root composite.\\ \\

The last method we must implement is the method {\em operator()}. This method
will be called from the processor mechanism for every Composite object
in the molecular structure thus iterating over it.
The implementation is straight forward.

\begin{lstlisting}{}
Processor::Result GLBoundingBoxModel::operator() 
	(Composite &composite)
{
	if (start_composite_ == 0)
	{
		start_composite_ = &composite;
	}

	if (!RTTI::isKindOf<Atom>(composite))
	{
		return Processor::CONTINUE;
	}
\end{lstlisting}

In this part of the code we store the start Composite so that later in the finish
method we can append the created bounding box to it.
We only want to process Atom objects, so we test with the runtime type
identification if the processed {\em composite} is not of kind Atom. If this
is the case we tell the processor to continue.

\begin{lstlisting}{}
	Atom *atom = RTTI::castTo<Atom>(composite);

	Box3 bbox(atom->getPosition(), 
						atom->getPosition());

	if (new_start_)
	{
		bbox_ = bbox;
		new_start_ = false;
	}
	else
	{
		bbox_.join(bbox);
	}

	return Processor::CONTINUE;
}
\end{lstlisting}

We create a box with the atom object and use it as start box if we do not have already
one. Next we join the created box with previously calculated one. This mechanism
extends the computed box so that if all atoms are processed we have a correctly calculated
bounding box.\\

This concludes the implementation of the bounding box processor. In the next
section we use this processor in a dialog the applies it to molecular structures.



\section{Constructing a dialog for the example application}
\label{section:construction_of_a_dialog}

In the section \ref{section:bounding_box_processor} we have constructed a processor that creates bounding boxes
for molecular structures. In this section we create a dialog that allows us to
create bounding boxes in different colors for molecular structures. We use the dialog
created in the VIEW tutorial (section \ref{section:view_construction_of_a_dialog}) and extend and 
reimplement certain methods to achieve the intended functionality.
There are only two methods we must change, the method {\em onNotify} and the method
{\em applyButtonClicked}.

\begin{lstlisting}{}
void TestDialog::onNotify(Message *message)
{
	...

	if (RTTI::isKindOf<MolecularSelectionMessage>(*message))
		selection_ = (RTTI::castTo<MolecularSelectionMessage>
									(*message))->getSelection();
	...
}
\end{lstlisting}

In the old dialog the method {\em onNotify} catches only {\em SelectionMessage} objects.
Now we want it to catch {\em MolecularSelectionMessage} objects that contain the 
molecular structure selected in the {\em MolecularControl}.\\ \\
The next method that must be changed is the {\em applyButtonClicked}.

\begin{lstlisting}{}
void TestDialog::applyButtonClicked()
{
	if (selection_.empty())
		return;
\end{lstlisting}

If no selection is available we do nothing.

\begin{lstlisting}{}
	List<Composite*> update_list;

	GLBoundingBoxModel bboxModel;
	bboxModel.setColor(color_);

	List<Composite*>::ConstIterator list_it=selection_.begin();
	for (; list_it != selection_.end(); ++list_it)
	{
		if (RTTI::isKindOf<Atom>(**list_it))
			continue;
		
		(*list_it)->apply(bboxModel);
		
		update_list.push_back(*list_it);
	}
\end{lstlisting}

We iterate over the structures in the selection list and start for each
structure (except atoms) the previously created bounding box processor. Before we
do this we transfer the color of the preferences tab widget of {\em *this} dialog
into the processor so that created bounding box has the needed color.
All processed composite objects are stored in an update list so that those objects
can be updated later. \\
{\em Note: } That updating process can not be done in this loop because
the message sent for the update can change the selection list thus invalidating
the loop which can lead to segmentation faults. 
	
\begin{lstlisting}{}
	list_it = update_list.begin();
	for (; list_it != update_list.end(); ++list_it)
	{
		ChangedCompositeMessage change_message;
		change_message.setComposite((*list_it));
		notify_(change_message);
	}
\end{lstlisting}

For each processed object we sent the message {\em ChangedCompositeMessage} so
that the graphical representation of that {\em Composite} object will be regenerated
when the {\em Scene} object is updated next.			

\begin{lstlisting}{}
	SceneMessage scene_message;
	scene_message.updateOnly();
	notify_(scene_message);
}
\end{lstlisting}

To initialize this update we also sent the message {\em SceneMessage} with 
update flag set to redraw all changed objects.\\ \\

That is all we must do to use our previously defined processor. In the next section
we will see how to include this dialog into an existing application.



\section{Adding the dialog to the example application}
\label{section:adding_the_dialog}

Now that we have a dialog for creating bounding boxes for molecular structures
the only thing to be done is to include this dialog into an existing application.
We use the example application created in the {\em BALLView.} document.
To add the dialog to the application we just create it with {\em MainControl}
as parent. Add this line to the example application.

\begin{lstlisting}{}
	new TestDialog(&main);
\end{lstlisting}

Now we have successfully added this dialog into our application. If we start the
application now a new menu entry ({\em DISPLAY-TestDialog}) is available. If pressed our dialog opens and
any selection done in the {\em MolecularControl} will be caught by our dialog. If we press
the {\em apply} button for each molecular structure (except atoms) a bounding box
will be created in the color displayed in the preferences tab widget. In the {\em MolecularControl}
we can see each bounding box as an entry below the {\em System} with the name of
the molecular structure the bounding box was created for.
If we want to delete such a bounding box just press the right mouse button on it and
choose {\em remove bounding box}, it will be deleted.\\ \\

That concludes the tutorial for BALLView. Now you are able to build your own
processors and dialogs and thus extend or rewrite any functionality the actual
example application lacks.