libsim  Versione6.3.0
georef_coord_class.F90
1 ! Copyright (C) 2010 ARPA-SIM <urpsim@smr.arpa.emr.it>
2 ! authors:
3 ! Davide Cesari <dcesari@arpa.emr.it>
4 ! Paolo Patruno <ppatruno@arpa.emr.it>
5 
6 ! This program is free software; you can redistribute it and/or
7 ! modify it under the terms of the GNU General Public License as
8 ! published by the Free Software Foundation; either version 2 of
9 ! the License, or (at your option) any later version.
10 
11 ! This program is distributed in the hope that it will be useful,
12 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ! GNU General Public License for more details.
15 
16 ! You should have received a copy of the GNU General Public License
17 ! along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "config.h"
19 
33 MODULE georef_coord_class
34 USE err_handling
37 USE geo_proj_class
38 #ifdef HAVE_SHAPELIB
39 USE shapelib
40 #endif
41 IMPLICIT NONE
42 
47 TYPE georef_coord
48  PRIVATE
49  DOUBLE PRECISION :: x=dmiss, y=dmiss
50 END TYPE georef_coord
51 
53 TYPE(georef_coord),PARAMETER :: georef_coord_miss=georef_coord(dmiss,dmiss)
54 
60  PRIVATE
61  INTEGER,ALLOCATABLE :: parts(:)
62  TYPE(georef_coord),ALLOCATABLE :: coord(:)
63  INTEGER :: topo=imiss
64  TYPE(geo_proj) :: proj
65  TYPE(georef_coord) :: bbox(2)=(/georef_coord_miss, georef_coord_miss/)
66  LOGICAL :: bbox_updated=.false.
67 END TYPE georef_coord_array
68 
69 INTEGER,PARAMETER :: georef_coord_array_point = 1
70 INTEGER,PARAMETER :: georef_coord_array_arc = 3
71 INTEGER,PARAMETER :: georef_coord_array_polygon = 5
72 INTEGER,PARAMETER :: georef_coord_array_multipoint = 8
73 
74 
78 INTERFACE delete
79  MODULE PROCEDURE georef_coord_delete, georef_coord_array_delete
80 END INTERFACE
81 
83 INTERFACE c_e
84  MODULE PROCEDURE georef_coord_c_e, georef_coord_array_c_e
85 END INTERFACE
86 
88 INTERFACE getval
89  MODULE PROCEDURE georef_coord_getval, georef_coord_proj_getval, georef_coord_array_getval
90 END INTERFACE
91 
92 INTERFACE compute_bbox
93  MODULE PROCEDURE georef_coord_array_compute_bbox
94 END INTERFACE
95 
97 INTERFACE OPERATOR (==)
98  MODULE PROCEDURE georef_coord_eq
99 END INTERFACE
100 
102 INTERFACE OPERATOR (/=)
103  MODULE PROCEDURE georef_coord_ne
104 END INTERFACE
105 
108 INTERFACE OPERATOR (>=)
109  MODULE PROCEDURE georef_coord_ge
110 END INTERFACE
111 
114 INTERFACE OPERATOR (<=)
115  MODULE PROCEDURE georef_coord_le
116 END INTERFACE
117 
118 #ifdef HAVE_SHAPELIB
119 
121 INTERFACE import
122  MODULE PROCEDURE arrayof_georef_coord_array_import
123 END INTERFACE
124 
127 INTERFACE export
128  MODULE PROCEDURE arrayof_georef_coord_array_export
129 END INTERFACE
130 #endif
131 
134 INTERFACE read_unit
135  MODULE PROCEDURE georef_coord_read_unit, georef_coord_vect_read_unit
136 END INTERFACE
137 
140 INTERFACE write_unit
141  MODULE PROCEDURE georef_coord_write_unit, georef_coord_vect_write_unit
142 END INTERFACE
143 
145 INTERFACE inside
146  MODULE PROCEDURE georef_coord_inside, georef_coord_inside_rectang
147 END INTERFACE
148 
149 #define ARRAYOF_ORIGTYPE TYPE(georef_coord_array)
150 #define ARRAYOF_TYPE arrayof_georef_coord_array
151 !define ARRAYOF_ORIGEQ 0
152 #define ARRAYOF_ORIGDESTRUCTOR(x) CALL delete(x)
153 #include "arrayof_pre.F90"
154 ! from arrayof
155 PUBLIC insert, append, remove, packarray
156 
157 PRIVATE
158 PUBLIC georef_coord, georef_coord_miss, &
159  georef_coord_array, georef_coord_array_point, georef_coord_array_arc, &
160  georef_coord_array_polygon, georef_coord_array_multipoint, &
161  delete, c_e, getval, compute_bbox, OPERATOR(==), OPERATOR(/=), OPERATOR(>=), OPERATOR(<=), &
162 #ifdef HAVE_SHAPELIB
163  import, export, &
164 #endif
166  georef_coord_new, georef_coord_array_new
167 
168 CONTAINS
169 
170 #include "arrayof_post.F90"
171 
172 ! ===================
173 ! == georef_coord ==
174 ! ===================
178 FUNCTION georef_coord_new(x, y) RESULT(this)
179 DOUBLE PRECISION,INTENT(in),OPTIONAL :: x
180 DOUBLE PRECISION,INTENT(in),OPTIONAL :: y
181 TYPE(georef_coord) :: this
182 
183 CALL optio(x, this%x)
184 CALL optio(y, this%y)
185 
186 END FUNCTION georef_coord_new
187 
188 
189 SUBROUTINE georef_coord_delete(this)
190 TYPE(georef_coord),INTENT(inout) :: this
191 
192 this%x = dmiss
193 this%y = dmiss
194 
195 END SUBROUTINE georef_coord_delete
196 
197 
198 ELEMENTAL FUNCTION georef_coord_c_e(this) RESULT (res)
199 TYPE(georef_coord),INTENT(in) :: this
200 LOGICAL :: res
201 
202 res = .NOT. this == georef_coord_miss
203 
204 END FUNCTION georef_coord_c_e
205 
206 
213 ELEMENTAL SUBROUTINE georef_coord_getval(this, x, y)
214 TYPE(georef_coord),INTENT(in) :: this
215 DOUBLE PRECISION,INTENT(out),OPTIONAL :: x
216 DOUBLE PRECISION,INTENT(out),OPTIONAL :: y
217 
218 IF (PRESENT(x)) x = this%x
219 IF (PRESENT(y)) y = this%y
220 
221 END SUBROUTINE georef_coord_getval
222 
223 
232 ELEMENTAL SUBROUTINE georef_coord_proj_getval(this, proj, x, y, lon, lat)
233 TYPE(georef_coord),INTENT(in) :: this
234 TYPE(geo_proj),INTENT(in) :: proj
235 DOUBLE PRECISION,INTENT(out),OPTIONAL :: x
236 DOUBLE PRECISION,INTENT(out),OPTIONAL :: y
237 DOUBLE PRECISION,INTENT(out),OPTIONAL :: lon
238 DOUBLE PRECISION,INTENT(out),OPTIONAL :: lat
239 
240 DOUBLE PRECISION :: llon, llat
241 
242 IF (PRESENT(x)) x = this%x
243 IF (PRESENT(y)) y = this%y
244 IF (PRESENT(lon) .OR. present(lat)) THEN
245  CALL unproj(proj, this%x, this%y, llon, llat)
246  IF (PRESENT(lon)) lon = llon
247  IF (PRESENT(lat)) lat = llat
248 ENDIF
249 
250 END SUBROUTINE georef_coord_proj_getval
251 
252 
253 ! document and improve
254 ELEMENTAL FUNCTION getlat(this)
255 TYPE(georef_coord),INTENT(in) :: this ! oggetto di cui restituire latitudine
256 DOUBLE PRECISION :: getlat ! latitudine geografica
257 
258 getlat = this%y ! change!!!
259 
260 END FUNCTION getlat
261 
262 ! document and improve
263 ELEMENTAL FUNCTION getlon(this)
264 TYPE(georef_coord),INTENT(in) :: this ! oggetto di cui restituire latitudine
265 DOUBLE PRECISION :: getlon ! longitudine geografica
267 getlon = this%x ! change!!!
268 
269 END FUNCTION getlon
270 
271 
272 ELEMENTAL FUNCTION georef_coord_eq(this, that) RESULT(res)
273 TYPE(georef_coord),INTENT(IN) :: this, that
274 LOGICAL :: res
275 
276 res = (this%x == that%x .AND. this%y == that%y)
277 
278 END FUNCTION georef_coord_eq
279 
280 
281 ELEMENTAL FUNCTION georef_coord_ge(this, that) RESULT(res)
282 TYPE(georef_coord),INTENT(IN) :: this, that
283 LOGICAL :: res
285 res = (this%x >= that%x .AND. this%y >= that%y)
286 
287 END FUNCTION georef_coord_ge
288 
289 
290 ELEMENTAL FUNCTION georef_coord_le(this, that) RESULT(res)
291 TYPE(georef_coord),INTENT(IN) :: this, that
292 LOGICAL :: res
293 
294 res = (this%x <= that%x .AND. this%y <= that%y)
295 
296 END FUNCTION georef_coord_le
297 
298 
299 ELEMENTAL FUNCTION georef_coord_ne(this, that) RESULT(res)
300 TYPE(georef_coord),INTENT(IN) :: this, that
301 LOGICAL :: res
302 
303 res = .NOT.(this == that)
304 
305 END FUNCTION georef_coord_ne
306 
307 
313 SUBROUTINE georef_coord_read_unit(this, unit)
314 TYPE(georef_coord),INTENT(out) :: this
315 INTEGER, INTENT(in) :: unit
316 
317 CALL georef_coord_vect_read_unit((/this/), unit)
318 
319 END SUBROUTINE georef_coord_read_unit
320 
327 SUBROUTINE georef_coord_vect_read_unit(this, unit)
328 TYPE(georef_coord) :: this(:)
329 INTEGER, INTENT(in) :: unit
330 
331 CHARACTER(len=40) :: form
332 INTEGER :: i
333 
334 INQUIRE(unit, form=form)
335 IF (form == 'FORMATTED') THEN
336  read(unit,*) (this(i)%x,this(i)%y, i=1,SIZE(this))
337 !TODO bug gfortran compiler !
338 !missing values are unredeable when formatted
339 ELSE
340  READ(unit) (this(i)%x,this(i)%y, i=1,SIZE(this))
341 ENDIF
342 
343 END SUBROUTINE georef_coord_vect_read_unit
344 
345 
350 SUBROUTINE georef_coord_write_unit(this, unit)
351 TYPE(georef_coord),INTENT(in) :: this
352 INTEGER, INTENT(in) :: unit
354 CALL georef_coord_vect_write_unit((/this/), unit)
355 
356 END SUBROUTINE georef_coord_write_unit
357 
363 SUBROUTINE georef_coord_vect_write_unit(this, unit)
364 TYPE(georef_coord),INTENT(in) :: this(:)
365 INTEGER, INTENT(in) :: unit
366 
367 CHARACTER(len=40) :: form
368 INTEGER :: i
369 
370 INQUIRE(unit, form=form)
371 IF (form == 'FORMATTED') THEN
372  WRITE(unit,*) (this(i)%x,this(i)%y, i=1,SIZE(this))
373 !TODO bug gfortran compiler !
374 !missing values are unredeable when formatted
375 ELSE
376  WRITE(unit) (this(i)%x,this(i)%y, i=1,SIZE(this))
377 ENDIF
378 
379 END SUBROUTINE georef_coord_vect_write_unit
380 
381 
384 !FUNCTION georef_coord_dist(this, that) RESULT(dist)
385 !USE doubleprecision_phys_const
386 !TYPE(georef_coord), INTENT (IN) :: this !< primo punto
387 !TYPE(georef_coord), INTENT (IN) :: that !< secondo punto
388 !DOUBLE PRECISION :: dist !< distanza in metri
389 !
390 !DOUBLE PRECISION :: x,y
391 !! Distanza approssimata, valida per piccoli angoli
392 !
393 !x = (this%x-that%x)*COS(((this%y+this%y)/2.)*degrad)
394 !y = (this%y-that%y)
395 !dist = SQRT(x**2 + y**2)*degrad*rearth
396 !
397 !END FUNCTION georef_coord_dist
399 
405 FUNCTION georef_coord_inside_rectang(this, coordmin, coordmax) RESULT(res)
406 TYPE(georef_coord),INTENT(IN) :: this
407 TYPE(georef_coord),INTENT(IN) :: coordmin
408 TYPE(georef_coord),INTENT(IN) :: coordmax
409 LOGICAL :: res
410 
411 res = (this >= coordmin .AND. this <= coordmax)
412 
413 END FUNCTION georef_coord_inside_rectang
414 
416 ! ========================
417 ! == georef_coord_array ==
418 ! ========================
424 FUNCTION georef_coord_array_new(x, y, topo, proj) RESULT(this)
425 DOUBLE PRECISION,INTENT(in),OPTIONAL :: x(:)
426 DOUBLE PRECISION,INTENT(in),OPTIONAL :: y(:)
427 INTEGER,INTENT(in),OPTIONAL :: topo
428 TYPE(geo_proj),INTENT(in),OPTIONAL :: proj
429 TYPE(georef_coord_array) :: this
430 
431 INTEGER :: lsize
432 
433 IF (PRESENT(x) .AND. PRESENT(y)) THEN
434  lsize = min(SIZE(x), SIZE(y))
435  ALLOCATE(this%coord(lsize))
436  this%coord(1:lsize)%x = x(1:lsize)
437  this%coord(1:lsize)%y = y(1:lsize)
438 ENDIF
439 this%topo = optio_l(topo)
440 IF (PRESENT(proj)) this%proj = proj
441 
442 END FUNCTION georef_coord_array_new
443 
444 
445 SUBROUTINE georef_coord_array_delete(this)
446 TYPE(georef_coord_array),INTENT(inout) :: this
447 
448 TYPE(georef_coord_array) :: lobj
449 
450 this = lobj
451 
452 END SUBROUTINE georef_coord_array_delete
453 
454 
455 ELEMENTAL FUNCTION georef_coord_array_c_e(this) RESULT (res)
456 TYPE(georef_coord_array),INTENT(in) :: this
457 LOGICAL :: res
458 
459 res = ALLOCATED(this%coord)
460 
461 END FUNCTION georef_coord_array_c_e
462 
463 
468 SUBROUTINE georef_coord_array_getval(this, x, y, topo, proj)
469 TYPE(georef_coord_array),INTENT(in) :: this
470 DOUBLE PRECISION,OPTIONAL,ALLOCATABLE,INTENT(out) :: x(:)
471 DOUBLE PRECISION,OPTIONAL,ALLOCATABLE,INTENT(out) :: y(:)
472 ! allocatable per vedere di nascosto l'effetto che fa
473 INTEGER,OPTIONAL,INTENT(out) :: topo
474 TYPE(geo_proj),OPTIONAL,INTENT(out) :: proj
475 
476 
477 IF (PRESENT(x)) THEN
478  IF (ALLOCATED(this%coord)) THEN
479  x = this%coord%x
480  ENDIF
481 ENDIF
482 IF (PRESENT(y)) THEN
483  IF (ALLOCATED(this%coord)) THEN
484  y = this%coord%y
485  ENDIF
486 ENDIF
487 IF (PRESENT(topo)) topo = this%topo
488 IF (PRESENT(proj)) proj = this%proj ! warning proj has no missing value yet
489 
490 END SUBROUTINE georef_coord_array_getval
491 
492 
498 SUBROUTINE georef_coord_array_compute_bbox(this)
499 TYPE(georef_coord_array),INTENT(inout) :: this
500 
501 IF (ALLOCATED(this%coord)) THEN
502  this%bbox(1)%x = minval(this%coord(:)%x)
503  this%bbox(1)%y = minval(this%coord(:)%y)
504  this%bbox(2)%x = maxval(this%coord(:)%x)
505  this%bbox(2)%y = maxval(this%coord(:)%y)
506  this%bbox_updated = .true.
507 ENDIF
508 
509 END SUBROUTINE georef_coord_array_compute_bbox
510 
511 #ifdef HAVE_SHAPELIB
512 ! internal method for importing a single shape
513 SUBROUTINE georef_coord_array_import(this, shphandle, nshp)
514 TYPE(georef_coord_array),INTENT(OUT) :: this
515 TYPE(shpfileobject),INTENT(INOUT) :: shphandle
516 INTEGER,INTENT(IN) :: nshp
517 
518 TYPE(shpobject) :: shpobj
519 
520 ! read shape object
521 shpobj = shpreadobject(shphandle, nshp)
522 IF (.NOT.shpisnull(shpobj)) THEN
523 ! import it in georef_coord object
524  this = georef_coord_array_new(x=dble(shpobj%padfx), y=dble(shpobj%padfy), &
525  topo=shpobj%nshptype)
526  IF (shpobj%nparts > 1 .AND. ASSOCIATED(shpobj%panpartstart)) THEN
527  this%parts = shpobj%panpartstart(:) ! automatic f95 allocation
528  ELSE IF (ALLOCATED(this%parts)) THEN
529  DEALLOCATE(this%parts)
530  ENDIF
531  CALL shpdestroyobject(shpobj)
532  CALL compute_bbox(this)
533 ENDIF
534 
535 
536 END SUBROUTINE georef_coord_array_import
537 
538 
539 ! internal method for exporting a single shape
540 SUBROUTINE georef_coord_array_export(this, shphandle, nshp)
541 TYPE(georef_coord_array),INTENT(in) :: this
542 TYPE(shpfileobject),INTENT(inout) :: shphandle
543 INTEGER,INTENT(IN) :: nshp ! index of shape to write starting from 0, -1 to append
544 
545 INTEGER :: i
546 TYPE(shpobject) :: shpobj
547 
548 IF (ALLOCATED(this%coord)) THEN
549  IF (ALLOCATED(this%parts)) THEN
550  shpobj = shpcreateobject(this%topo, -1, SIZE(this%parts), this%parts, &
551  this%parts, SIZE(this%coord), this%coord(:)%x, this%coord(:)%y)
552  ELSE
553  shpobj = shpcreatesimpleobject(this%topo, SIZE(this%coord), &
554  this%coord(:)%x, this%coord(:)%y)
555  ENDIF
556 ELSE
557  RETURN
558 ENDIF
559 
560 IF (.NOT.shpisnull(shpobj)) THEN
561  i = shpwriteobject(shphandle, nshp, shpobj)
562  CALL shpdestroyobject(shpobj)
563 ENDIF
564 
565 END SUBROUTINE georef_coord_array_export
566 
567 
578 SUBROUTINE arrayof_georef_coord_array_import(this, shpfile)
579 TYPE(arrayof_georef_coord_array),INTENT(out) :: this
580 CHARACTER(len=*),INTENT(in) :: shpfile
581 
582 REAL(kind=fp_d) :: minb(4), maxb(4)
583 INTEGER :: i, ns, shptype, dbfnf, dbfnr
584 TYPE(shpfileobject) :: shphandle
585 
586 shphandle = shpopen(trim(shpfile), 'rb')
587 IF (shpfileisnull(shphandle)) THEN
588  ! log here
589  CALL raise_error()
590  RETURN
591 ENDIF
592 
593 ! get info about file
594 CALL shpgetinfo(shphandle, ns, shptype, minb, maxb, dbfnf, dbfnr)
595 IF (ns > 0) THEN ! allocate and read the object
596  CALL insert(this, nelem=ns)
597  DO i = 1, ns
598  CALL georef_coord_array_import(this%array(i), shphandle=shphandle, nshp=i-1)
599  ENDDO
600 ENDIF
601 
602 CALL shpclose(shphandle)
603 ! pack object to save memory
604 CALL packarray(this)
605 
606 END SUBROUTINE arrayof_georef_coord_array_import
607 
608 
614 SUBROUTINE arrayof_georef_coord_array_export(this, shpfile)
615 TYPE(arrayof_georef_coord_array),INTENT(in) :: this
616 CHARACTER(len=*),INTENT(in) :: shpfile
617 
618 INTEGER :: i
619 TYPE(shpfileobject) :: shphandle
620 
621 IF (this%arraysize > 0) THEN
622  shphandle = shpcreate(trim(shpfile), this%array(1)%topo)
623 ELSE
624  shphandle = shpcreate(trim(shpfile), georef_coord_array_polygon)
625 ENDIF
626 IF (shpfileisnull(shphandle)) THEN
627  ! log here
628  CALL raise_error()
629  RETURN
630 ENDIF
631 
632 DO i = 1, this%arraysize
633  CALL georef_coord_array_export(this%array(i), shphandle=shphandle, nshp=i-1)
634 ENDDO
635 
636 CALL shpclose(shphandle)
637 
638 END SUBROUTINE arrayof_georef_coord_array_export
639 #endif
640 
652 FUNCTION georef_coord_inside(this, poly) RESULT(inside)
653 TYPE(georef_coord), INTENT(IN) :: this
654 TYPE(georef_coord_array), INTENT(IN) :: poly
655 LOGICAL :: inside
656 
657 INTEGER :: i
658 
659 inside = .false.
660 IF (.NOT.c_e(this)) RETURN
661 IF (.NOT.ALLOCATED(poly%coord)) RETURN
662 ! if outside bounding box stop here
663 IF (poly%bbox_updated) THEN
664  IF (.NOT.georef_coord_inside_rectang(this, poly%bbox(1), poly%bbox(2))) RETURN
665 ENDIF
666 
667 IF (ALLOCATED(poly%parts)) THEN
668  DO i = 1, SIZE(poly%parts)-1
669  inside = inside .NEQV. pointinpoly(this%x, this%y, &
670  poly%coord(poly%parts(i)+1:poly%parts(i+1))%x, &
671  poly%coord(poly%parts(i)+1:poly%parts(i+1))%y)
672  ENDDO
673  IF (SIZE(poly%parts) > 0) THEN ! safety check
674  inside = inside .NEQV. pointinpoly(this%x, this%y, &
675  poly%coord(poly%parts(i)+1:)%x, &
676  poly%coord(poly%parts(i)+1:)%y)
677  ENDIF
678 
679 ELSE
680  IF (SIZE(poly%coord) < 1) RETURN ! safety check
681  inside = pointinpoly(this%x, this%y, &
682  poly%coord(:)%x, poly%coord(:)%y)
683 ENDIF
684 
685 CONTAINS
686 
687 FUNCTION pointinpoly(x, y, px, py)
688 DOUBLE PRECISION, INTENT(in) :: x, y, px(:), py(:)
689 LOGICAL :: pointinpoly
690 
691 INTEGER :: i, j, starti
692 
693 pointinpoly = .false.
694 
695 IF (px(1) == px(SIZE(px)) .AND. py(1) == py(SIZE(px))) THEN ! closed polygon
696  starti = 2
697  j = 1
698 ELSE ! unclosed polygon
699  starti = 1
700  j = SIZE(px)
701 ENDIF
702 DO i = starti, SIZE(px)
703  IF ((py(i) <= y .AND. y < py(j)) .OR. &
704  (py(j) <= y .AND. y < py(i))) THEN
705  IF (x < (px(j) - px(i)) * (y - py(i)) / (py(j) - py(i)) + px(i)) THEN
706  pointinpoly = .NOT. pointinpoly
707  ENDIF
708  ENDIF
709  j = i
710 ENDDO
711 
712 END FUNCTION pointinpoly
713 
714 END FUNCTION georef_coord_inside
715 
716 
717 
718 END MODULE georef_coord_class
Method for removing elements of the array at a desired position.
Compute forward coordinate transformation from geographical system to projected system.
Method for packing the array object reducing at a minimum the memory occupation, without destroying i...
Read a single georef_coord object or an array of georef_coord objects from a Fortran FORMATTED or UNF...
Check missing value.
Module for quickly interpreting the OPTIONAL parameters passed to a subprogram.
Write a single georef_coord object or an array of georef_coord objects to a Fortran FORMATTED or UNFO...
Quick method to append an element to the array.
Derived type defining a dynamically extensible array of TYPE(georef_coord_array) elements.
This module defines objects describing georeferenced sparse points possibly with topology and project...
Determine whether a point lies inside a polygon or a rectangle.
Generic subroutine for checking OPTIONAL parameters.
Import an array of georef_coord_array objects from a file in ESRI/Shapefile format.
Method for inserting elements of the array at a desired position.
Derived type defining a one-dimensional array of georeferenced points with an associated topology (is...
Compute backward coordinate transformation from projected system to geographical system.
Gestione degli errori.
Methods for returning the value of object members.
Definitions of constants and functions for working with missing values.
Detructors for the two classes.
Derive type defining a single georeferenced point, either in geodetic or in projected coordinates...
Export an array of georef_coord_array objects to a file in ESRI/Shapefile format. ...

Generated with Doxygen.