Alternaria
fit cylinders and ellipsoids to fungus
hypha.cpp
Go to the documentation of this file.
00001 /*
00002  * This work is licensed under a Creative Commons 
00003  * Attribution-Noncommercial-Share Alike 3.0 United States License.
00004  * 
00005  *    http://creativecommons.org/licenses/by-nc-sa/3.0/us/
00006  * 
00007  * You are free:
00008  * 
00009  *    to Share - to copy, distribute, display, and perform the work
00010  *    to Remix - to make derivative works
00011  * 
00012  * Under the following conditions:
00013  * 
00014  *    Attribution. You must attribute the work in the manner specified by the
00015  *    author or licensor (but not in any way that suggests that they endorse you
00016  *    or your use of the work).
00017  * 
00018  *    Noncommercial. You may not use this work for commercial purposes.
00019  * 
00020  *    Share Alike. If you alter, transform, or build upon this work, you may
00021  *    distribute the resulting work only under the same or similar license to
00022  *    this one.
00023  * 
00024  * For any reuse or distribution, you must make clear to others the license
00025  * terms of this work. The best way to do this is by including this header.
00026  * 
00027  * Any of the above conditions can be waived if you get permission from the
00028  * copyright holder.
00029  * 
00030  * Apart from the remix rights granted under this license, nothing in this
00031  * license impairs or restricts the author's moral rights.
00032  */
00033 
00034 
00047 #include <config.h>
00048 
00049 #include <cassert>
00050 #include <cmath>
00051 #include <cstring>
00052 #include <iostream>
00053 #include <sstream>
00054 #include <list>
00055 #include <vector>
00056 
00057 #include <inttypes.h>
00058 
00059 #if defined ALTERNARIA_HAVE_OPENGL_FRAMEWORK
00060 #include <OpenGL/gl.h>
00061 #include <OpenGL/glu.h>
00062 #elif defined ALTERNARIA_HAVE_OPENGL
00063 #include <GL/gl.h>
00064 #include <GL/glu.h>
00065 #endif
00066 
00067 #include <jwsc/base/limits.h>
00068 #include <jwsc/math/constants.h>
00069 #include <jwsc/prob/pdf.h>
00070 #include <jwsc/vector/vector.h>
00071 #include <jwsc/vector/vector_math.h>
00072 #include <jwsc/matrix/matrix.h>
00073 #include <jwsc/matrix/matrix_math.h>
00074 #include <jwsc/matblock/matblock.h>
00075 
00076 #include <jwsc++/base/exception.h>
00077 
00078 #include "density.h"
00079 #include "printable.h"
00080 #include "structure.h"
00081 #include "spore.h"
00082 #include "hypha.h"
00083 
00084 
00085 #define  CENTROID_X_MIN         0
00086 #define  CENTROID_X_MAX         0
00087 
00088 #define  CENTROID_Y_MIN         0
00089 #define  CENTROID_Y_MAX         0
00090 
00091 #define  CENTROID_Z_MIN         0
00092 #define  CENTROID_Z_MAX         0
00093 
00094 #define  APICAL_LENGTH_MU       15.0f
00095 #define  APICAL_LENGTH_SIGMA    1.0f
00096 #define  APICAL_LENGTH_MIN      10.f
00097 #define  APICAL_LENGTH_MAX      100.0f
00098 
00099 #define  LATERAL_LENGTH_MU      15.0f
00100 #define  LATERAL_LENGTH_SIGMA   1.0f
00101 #define  LATERAL_LENGTH_MIN     10.f
00102 #define  LATERAL_LENGTH_MAX     100.0f
00103 
00104 #define  APICAL_WIDTH_MU        6.0f
00105 #define  APICAL_WIDTH_SIGMA     0.3f
00106 #define  APICAL_WIDTH_MIN       1.0f
00107 #define  APICAL_WIDTH_MAX       20.0f
00108 
00109 #define  APICAL_DWIDTH_SIGMA    0.05f
00110 #define  APICAL_DWIDTH_MIN      -2.0f
00111 #define  APICAL_DWIDTH_MAX      2.0f
00112 
00113 #define  LATERAL_WIDTH_MU       6.0f
00114 #define  LATERAL_WIDTH_SIGMA    0.3f
00115 #define  LATERAL_WIDTH_MIN      1.0f
00116 #define  LATERAL_WIDTH_MAX      20.0f
00117 
00118 #define  APICAL_THETA_MU        0
00119 #define  APICAL_THETA_SIGMA     0.2f
00120 #define  APICAL_THETA_MIN       0
00121 #define  APICAL_THETA_MAX       JWSC_PI
00122 
00123 #define  LATERAL_THETA_MU       JWSC_PI_4
00124 #define  LATERAL_THETA_SIGMA    0.2f
00125 #define  LATERAL_THETA_MIN      0
00126 #define  LATERAL_THETA_MAX      JWSC_PI
00127 
00128 #define  PSI_MIN                -JWSC_PI
00129 #define  PSI_MAX                JWSC_PI
00130 
00131 #define  OPACITY_MU             0.9f
00132 #define  OPACITY_SIGMA          0.2f
00133 #define  OPACITY_MIN            0.1f
00134 #define  OPACITY_MAX            1.0f
00135 
00136 #define  LAT_DIST_MU            0.5f
00137 #define  LAT_DIST_SIGMA         0.1f
00138 #define  LAT_DIST_MIN           0
00139 #define  LAT_DIST_MAX           1.0f
00140 
00141 
00142 using std::istream;
00143 using std::ostringstream;
00144 using std::strncmp;
00145 using std::strlen;
00146 using std::list;
00147 using std::vector;
00148 using namespace jwsc;
00149 using jwscxx::base::Arg_error;
00150 using jwscxx::base::IO_error;
00151 
00152 
00153 /* -----------------------  Apical_hypha_density  --------------------------- */
00154 
00161 Apical_hypha_density::Apical_hypha_density() throw (Arg_error)
00162 {
00163     float mu, sigma;
00164     float min, max;
00165 
00166     min = CENTROID_X_MIN;
00167     max = CENTROID_X_MAX;
00168     set_centroid_x(min, max);
00169 
00170     min = CENTROID_Y_MIN;
00171     max = CENTROID_Y_MAX;
00172     set_centroid_y(min, max);
00173 
00174     min = CENTROID_Z_MIN;
00175     max = CENTROID_Z_MAX;
00176     set_centroid_z(min, max);
00177 
00178     mu    = APICAL_LENGTH_MU;
00179     sigma = APICAL_LENGTH_SIGMA;
00180     min   = APICAL_LENGTH_MIN;
00181     max   = APICAL_LENGTH_MAX;
00182     set_length(mu, sigma, min, max);
00183 
00184     mu    = APICAL_WIDTH_MU;
00185     sigma = APICAL_WIDTH_SIGMA;
00186     min   = APICAL_WIDTH_MIN;
00187     max   = APICAL_WIDTH_MAX;
00188     set_width(mu, sigma, min, max);
00189 
00190     sigma = APICAL_DWIDTH_SIGMA;
00191     min   = APICAL_DWIDTH_MIN;
00192     max   = APICAL_DWIDTH_MAX;
00193     set_dwidth(sigma, min, max);
00194 
00195     mu    = APICAL_THETA_MU;
00196     sigma = APICAL_THETA_SIGMA;
00197     min   = APICAL_THETA_MIN;
00198     max   = APICAL_THETA_MAX;
00199     set_theta(mu, sigma, min, max);
00200 
00201     min = PSI_MIN;
00202     max = PSI_MAX;
00203     set_psi(min, max);
00204 
00205     mu    = OPACITY_MU;
00206     sigma = OPACITY_SIGMA;
00207     min   = OPACITY_MIN;
00208     max   = OPACITY_MAX;
00209     set_opacity(mu, sigma, min, max);
00210 }
00211 
00212 
00214 Apical_hypha_density* Apical_hypha_density::clone() const
00215 {
00216     float mu, sigma;
00217     float min, max;
00218 
00219     Apical_hypha_density* h  = new Apical_hypha_density();
00220 
00221     min = centroid_x.get_min();
00222     max = centroid_x.get_max();
00223     h->set_centroid_x(min, max);
00224 
00225     min = centroid_y.get_min();
00226     max = centroid_y.get_max();
00227     h->set_centroid_y(min, max);
00228 
00229     min = centroid_z.get_min();
00230     max = centroid_z.get_max();
00231     h->set_centroid_z(min, max);
00232 
00233     mu    = length.get_mu();
00234     sigma = length.get_sigma();
00235     min   = length.get_min();
00236     max   = length.get_max();
00237     h->set_length(mu, sigma, min, max);
00238 
00239     mu    = width.get_mu();
00240     sigma = width.get_sigma();
00241     min   = width.get_min();
00242     max   = width.get_max();
00243     h->set_width(mu, sigma, min, max);
00244 
00245     sigma = dwidth.get_sigma();
00246     min   = dwidth.get_min();
00247     max   = dwidth.get_max();
00248     h->set_dwidth(sigma, min, max);
00249 
00250     mu    = theta.get_mu();
00251     sigma = theta.get_sigma();
00252     min   = theta.get_min();
00253     max   = theta.get_max();
00254     h->set_theta(mu, sigma, min, max);
00255 
00256     min = psi.get_min();
00257     max = psi.get_max();
00258     h->set_psi(min, max);
00259 
00260     mu    = opacity.get_mu();
00261     sigma = opacity.get_sigma();
00262     min   = opacity.get_min();
00263     max   = opacity.get_max();
00264     h->set_opacity(mu, sigma, min, max);
00265 
00266     return h;
00267 }
00268 
00269 
00280 void Apical_hypha_density::set_dwidth
00281 (
00282     float sigma, 
00283     float min, 
00284     float max
00285 ) 
00286 throw (Arg_error)
00287 {
00288     dwidth.set(0, sigma, min, max);
00289 }
00290 
00291 
00299 Apical_hypha* Apical_hypha_density::sample
00300 (
00301     float base_theta, 
00302     float base_psi,
00303     size_t level
00304 ) 
00305 const
00306 {
00307     return new Apical_hypha(sample_centroid_x(), sample_centroid_y(), 
00308             sample_centroid_z(), sample_length(), sample_width(), 
00309             base_theta, base_psi, sample_theta(), sample_psi(), 
00310             sample_opacity(), level, this);
00311 }
00312 
00313 
00327 Apical_hypha* Apical_hypha_density::sample
00328 (
00329     float centroid_x, 
00330     float centroid_y, 
00331     float centroid_z,
00332     float base_theta,
00333     float base_psi,
00334     size_t level
00335 ) 
00336 const throw (Arg_error)
00337 {
00338     return new Apical_hypha(centroid_x, centroid_y, centroid_z, sample_length(),
00339             sample_width(), base_theta, base_psi, sample_theta(), sample_psi(), 
00340             sample_opacity(), level, this);
00341 }
00342 
00343 
00354 Apical_hypha* Apical_hypha_density::sample
00355 (
00356     Structure* parent,
00357     float      base_theta,
00358     float      base_psi
00359 ) 
00360 const throw (Arg_error)
00361 {
00362     if (dynamic_cast<Apical_hypha*>(parent) || 
00363         dynamic_cast<Lateral_hypha*>(parent))
00364     {
00365         return new Apical_hypha(parent, sample_length(), 
00366                 parent->get_width() + sample_dwidth(), base_theta, base_psi,
00367                 sample_theta(), sample_psi(), sample_opacity(), this);
00368     }
00369 
00370     return new Apical_hypha(parent, sample_length(), sample_width(), base_theta,
00371             base_psi, sample_theta(), sample_psi(), sample_opacity(), this);
00372 }
00373 
00374 
00376 float Apical_hypha_density::sample_dwidth() const
00377 {
00378     return (float)sample_gaussian_pdf_d(dwidth.get_mu(), dwidth.get_sigma(), 
00379             dwidth.get_min(), dwidth.get_max());
00380 }
00381 
00382 /* -------------------------------------------------------------------------- */
00383 
00384 
00385 
00386 
00387 
00388 
00389 /* ----------------------  Lateral_hypha_density  --------------------------- */
00390 
00397 Lateral_hypha_density::Lateral_hypha_density() throw (Arg_error)
00398 {
00399     float mu, sigma;
00400     float min, max;
00401 
00402     min = CENTROID_X_MIN;
00403     max = CENTROID_X_MAX;
00404     set_centroid_x(min, max);
00405 
00406     min = CENTROID_Y_MIN;
00407     max = CENTROID_Y_MAX;
00408     set_centroid_y(min, max);
00409 
00410     min = CENTROID_Z_MIN;
00411     max = CENTROID_Z_MAX;
00412     set_centroid_z(min, max);
00413 
00414     mu    = LATERAL_LENGTH_MU;
00415     sigma = LATERAL_LENGTH_SIGMA;
00416     min   = LATERAL_LENGTH_MIN;
00417     max   = LATERAL_LENGTH_MAX;
00418     set_length(mu, sigma, min, max);
00419 
00420     mu    = LATERAL_WIDTH_MU;
00421     sigma = LATERAL_WIDTH_SIGMA;
00422     min   = LATERAL_WIDTH_MIN;
00423     max   = LATERAL_WIDTH_MAX;
00424     set_width(mu, sigma, min, max);
00425 
00426     mu    = LATERAL_THETA_MU;
00427     sigma = LATERAL_THETA_SIGMA;
00428     min   = LATERAL_THETA_MIN;
00429     max   = LATERAL_THETA_MAX;
00430     set_theta(mu, sigma, min, max);
00431 
00432     min = PSI_MIN;
00433     max = PSI_MAX;
00434     set_psi(min, max);
00435 
00436     mu    = OPACITY_MU;
00437     sigma = OPACITY_SIGMA;
00438     min   = OPACITY_MIN;
00439     max   = OPACITY_MAX;
00440     set_opacity(mu, sigma, min, max);
00441 
00442     mu    = LAT_DIST_MU;
00443     sigma = LAT_DIST_SIGMA;
00444     min   = LAT_DIST_MIN;
00445     max   = LAT_DIST_MAX;
00446     set_lat_dist(mu, sigma, min, max);
00447 }
00448 
00449 
00451 Lateral_hypha_density* Lateral_hypha_density::clone() const
00452 {
00453     float mu, sigma;
00454     float min, max;
00455 
00456     Lateral_hypha_density* h  = new Lateral_hypha_density();
00457 
00458     min = centroid_x.get_min();
00459     max = centroid_x.get_max();
00460     h->set_centroid_x(min, max);
00461 
00462     min = centroid_y.get_min();
00463     max = centroid_y.get_max();
00464     h->set_centroid_y(min, max);
00465 
00466     min = centroid_z.get_min();
00467     max = centroid_z.get_max();
00468     h->set_centroid_z(min, max);
00469 
00470     mu    = length.get_mu();
00471     sigma = length.get_sigma();
00472     min   = length.get_min();
00473     max   = length.get_max();
00474     h->set_length(mu, sigma, min, max);
00475 
00476     mu    = width.get_mu();
00477     sigma = width.get_sigma();
00478     min   = width.get_min();
00479     max   = width.get_max();
00480     h->set_width(mu, sigma, min, max);
00481 
00482     mu    = theta.get_mu();
00483     sigma = theta.get_sigma();
00484     min   = theta.get_min();
00485     max   = theta.get_max();
00486     h->set_theta(mu, sigma, min, max);
00487 
00488     min = psi.get_min();
00489     max = psi.get_max();
00490     h->set_psi(min, max);
00491 
00492     mu    = opacity.get_mu();
00493     sigma = opacity.get_sigma();
00494     min   = opacity.get_min();
00495     max   = opacity.get_max();
00496     h->set_opacity(mu, sigma, min, max);
00497 
00498     mu    = lat_dist.get_mu();
00499     sigma = lat_dist.get_sigma();
00500     min   = lat_dist.get_min();
00501     max   = lat_dist.get_max();
00502     h->set_lat_dist(mu, sigma, min, max);
00503 
00504     return h;
00505 }
00506 
00507 
00515 Lateral_hypha* Lateral_hypha_density::sample
00516 (
00517     float base_theta, 
00518     float base_psi,
00519     size_t level
00520 ) 
00521 const
00522 {
00523     return new Lateral_hypha(sample_centroid_x(), sample_centroid_y(), 
00524             sample_centroid_z(), sample_lat_dist(), sample_length(), 
00525             sample_width(), base_theta, base_psi, sample_theta(), sample_psi(), 
00526             sample_opacity(), level, this);
00527 }
00528 
00529 
00543 Lateral_hypha* Lateral_hypha_density::sample
00544 (
00545     float centroid_x, 
00546     float centroid_y, 
00547     float centroid_z,
00548     float base_theta,
00549     float base_psi,
00550     size_t level
00551 ) 
00552 const throw (Arg_error)
00553 {
00554     return new Lateral_hypha(centroid_x, centroid_y, centroid_z, 
00555             sample_lat_dist(), sample_length(), sample_width(), base_theta,
00556             base_psi, sample_theta(), sample_psi(), sample_opacity(), level,
00557             this);
00558 }
00559 
00560 
00571 Lateral_hypha* Lateral_hypha_density::sample
00572 (
00573     Structure* parent,
00574     float      base_theta,
00575     float      base_psi
00576 ) 
00577 const throw (Arg_error)
00578 {
00579     return new Lateral_hypha(parent, sample_lat_dist(), sample_length(), 
00580             sample_width(), base_theta, base_psi, sample_theta(), sample_psi(), 
00581             sample_opacity(), this);
00582 }
00583 
00584 /* -------------------------------------------------------------------------- */
00585 
00586 
00587 
00588 
00589 
00590 
00591 
00592 /* ----------------------------  Apical_hypha  ------------------------------ */
00593 
00611 Apical_hypha::Apical_hypha
00612 (
00613     float centroid_x, 
00614     float centroid_y,
00615     float centroid_z,
00616     float length,
00617     float width,
00618     float base_theta,
00619     float base_psi,
00620     float theta,
00621     float psi,
00622     float opacity,
00623     size_t level,
00624     const class Apical_hypha_density* density
00625 ) 
00626 throw (Arg_error)
00627     : Apical_structure(centroid_x, centroid_y, centroid_z, length, width, 
00628             base_theta, base_psi, theta, psi, opacity, level, density)
00629 {
00630     this->density = density;
00631 
00632     update_ancestry_log_prob();
00633 }
00634 
00635 
00651 Apical_hypha::Apical_hypha
00652 (
00653     Structure* parent,
00654     float      length,
00655     float      width,
00656     float      base_theta,
00657     float      base_psi,
00658     float      theta,
00659     float      psi,
00660     float      opacity,
00661     const class Apical_hypha_density* density
00662 )
00663 throw (Arg_error, Apical_error)
00664     : Apical_structure(parent, length, width, base_theta, base_psi, theta, psi, 
00665             opacity, density)
00666 {
00667     this->density = density;
00668 
00669     update_ancestry_log_prob();
00670 }
00671 
00672 
00674 Apical_hypha::Apical_hypha(const Apical_hypha& h) : Apical_structure(h)
00675 {
00676     density = h.density;
00677 }
00678 
00679 
00681 Apical_hypha::Apical_hypha
00682 (
00683     const class Spore&          s, 
00684     float                       width,
00685     const Apical_hypha_density* density
00686 )
00687 throw (Arg_error) : Apical_structure(s)
00688 {
00689     Structure::density        = density;
00690     Apical_structure::density = density;
00691     this->density             = density;
00692 
00693     this->width = width;
00694 
00695     try
00696     {
00697         check_width();
00698         check_length();
00699         check_theta();
00700         check_psi();
00701         check_opacity();
00702     }
00703     catch (Arg_error e)
00704     {
00705         apical = 0;
00706         laterals.clear();
00707 
00708         throw e;
00709     }
00710 
00711     update_log_prob();
00712 }
00713 
00714 
00716 Apical_hypha* Apical_hypha::clone() const
00717 {
00718     return new Apical_hypha(*this);
00719 }
00720 
00721 
00727 Apical_hypha& Apical_hypha::operator= (const Apical_hypha& h)
00728 {
00729     Apical_structure::operator=(h);
00730 
00731     density = h.density;
00732 
00733     return *this;
00734 }
00735 
00736 
00747 Apical_hypha* Apical_hypha::split_into_apical
00748 (
00749     const Apical_hypha* rvals_1,
00750     const Apical_hypha* rvals_2
00751 ) 
00752 throw (Arg_error)
00753 {
00754     return (Apical_hypha*)Apical_structure::split_into_apical(rvals_1, rvals_2);
00755 }
00756 
00757 
00772 Apical_hypha* Apical_hypha::merge_with_apical
00773 (
00774     const Apical_hypha* rvals
00775 ) 
00776 throw (Arg_error)
00777 {
00778     if (!apical)
00779     {
00780         throw Arg_error("No apical to merge with");
00781     }
00782 
00783     if (!dynamic_cast<Apical_hypha*>(apical))
00784     {
00785         throw Arg_error("Apical to merge with not a hypha");
00786     }
00787 
00788     return (Apical_hypha*)Apical_structure::merge_with_apical(rvals);
00789 }
00790 
00791 
00807 Apical_hypha* Apical_hypha::merge_with_apical
00808 (
00809     class Spore**        spore_out,
00810     const class Spore*   rvals
00811 ) 
00812 throw (Arg_error)
00813 {
00814     assert(*spore_out == 0);
00815 
00816     if (!apical)
00817     {
00818         throw Arg_error("No apical to merge with");
00819     }
00820 
00821     if (!dynamic_cast<Apical_hypha*>(apical))
00822     {
00823         throw Arg_error("Apical to merge with not a hypha");
00824     }
00825 
00826     Apical_hypha hypha(*rvals, width, density);
00827 
00828     Apical_hypha* merged = (Apical_hypha*)Apical_structure::merge_with_apical(
00829             &hypha);
00830 
00831     *spore_out = new Spore(*this, rvals->get_width(), rvals->get_density());
00832 
00833     try
00834     {
00835         this->replace(*spore_out);
00836     }
00837     catch (Arg_error e)
00838     {
00839         delete *spore_out;
00840         delete merged;
00841         throw e;
00842     }
00843 
00844     return merged;
00845 }
00846 
00847 
00858 Lateral_hypha* Apical_hypha::split_into_lateral
00859 (
00860     const Apical_hypha*        rvals_1,
00861     const class Lateral_hypha* rvals_2
00862 ) 
00863 throw (Arg_error)
00864 {
00865     return (Lateral_hypha*)Apical_structure::split_into_lateral(rvals_1, 
00866             rvals_2);
00867 }
00868 
00869 
00886 Lateral_hypha* Apical_hypha::merge_with_lateral
00887 (
00888     class Lateral_hypha* lateral,
00889     const Apical_hypha*  rvals
00890 ) 
00891 throw (Arg_error)
00892 {
00893     return (Lateral_hypha*)Apical_structure::merge_with_lateral(lateral,rvals);
00894 }
00895 
00896 
00902 void Apical_hypha::replace(class Spore* spore) throw (Arg_error)
00903 {
00904     Apical_structure::replace(spore);
00905 }
00906 
00907 
00949 bool Apical_hypha::draw_in_matblock_f
00950 (
00951     jwsc::Matblock_f* M_blk,
00952     float       x, 
00953     float       y,
00954     float       z,
00955     float       x_scale,
00956     float       y_scale,
00957     float       z_scale,
00958     bool        fill
00959 )
00960 const
00961 {
00962     uint32_t num_mats, num_rows, num_cols;
00963     uint32_t mat, row, col;
00964 
00965     float height, radius;
00966     float min_scale;
00967     float phi;
00968     float phi_step;
00969     float h;
00970     float h_step;
00971     float r;
00972     float r_step;
00973     float x_0, y_0, z_0;
00974 
00975     Vector_f* point = 0;
00976 
00977     num_mats = M_blk->num_mats;
00978     num_rows = M_blk->num_rows;
00979     num_cols = M_blk->num_cols;
00980 
00981     height = length;
00982     radius = 0.5*width;
00983 
00984     create_vector_f(&point, 3);
00985 
00986     if (x_scale < y_scale && x_scale < z_scale)
00987         min_scale = x_scale;
00988     else if (y_scale < z_scale)
00989         min_scale = y_scale;
00990     else
00991         min_scale = z_scale;
00992 
00993     h_step = 0.5*min_scale;
00994     r_step = (fill) ? 0.5*min_scale : radius;
00995     phi_step = 0.5*min_scale / radius;
00996 
00997     bool intersect = false;
00998 
00999     // Iterate over the points on the hypha parametrically and paint each
01000     // point in the matrix block.
01001     for (r = radius; r > 0; r -= r_step)
01002     {
01003         for (phi = 0; phi < 2*JWSC_PI; phi += phi_step)
01004         {
01005             x_0 = r*std::cos(phi);
01006             y_0 = r*std::sin(phi);
01007 
01008             for (h = 0; h <= height; h += h_step)
01009             {
01010                 z_0 = h;
01011 
01012                 point->elts[0] = x_0;
01013                 point->elts[1] = y_0;
01014                 point->elts[2] = z_0;
01015                 multiply_matrix_and_vector_f(&point, R, point);
01016                 add_vectors_f(&point, point, begin_pt);
01017 
01018                 col = static_cast<uint32_t>(std::floor(
01019                             (point->elts[0] - x) / x_scale + 0.5));
01020                 row = static_cast<uint32_t>(std::floor(
01021                             (point->elts[1] - y) / y_scale + 0.5));
01022                 mat = static_cast<uint32_t>(std::floor(
01023                             (point->elts[2] - z) / z_scale + 0.5));
01024 
01025                 if (mat >= 0 && mat < num_mats &&
01026                     row >= 0 && row < num_rows && 
01027                     col >= 0 && col < num_cols)
01028                 {
01029                     uint32_t current_id = (uint32_t)floor(
01030                             M_blk->elts[ mat ][ row ][ col ]);
01031 
01032                     if (current_id > 0 && current_id != id && 
01033                             !has_child_id(current_id))
01034                     {
01035                         intersect = true;
01036                     }
01037 
01038                     M_blk->elts[ mat ][ row ][ col ] = (float)id + opacity;
01039                 }
01040             }
01041         }
01042     }
01043 
01044     free_vector_f(point);
01045 
01046     return intersect;
01047 }
01048 
01049 
01054 #if defined ALTERNARIA_HAVE_OPENGL_FRAMEWORK || defined ALTERNARIA_HAVE_OPENGL
01055 void Apical_hypha::draw_in_opengl(GLUquadric* quad, float scale) const
01056 {
01057     static GLfloat amb_dif[4] = {0.5f, 0.7f, 0.6f, 1.0f};
01058     static GLfloat shininess[1] = {100.0f};
01059     static GLfloat r[16] = {0};
01060     static GLfloat s[16] = {0};
01061 
01062     glMatrixMode(GL_MODELVIEW);
01063 
01064     glPushMatrix();
01065 
01066     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, amb_dif);
01067     glMaterialfv(GL_FRONT, GL_SPECULAR, amb_dif);
01068     glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
01069 
01070     glTranslatef(scale*begin_pt->elts[0], scale*begin_pt->elts[1], 
01071             scale*begin_pt->elts[2]);
01072 
01073     const float* elts = *(R->elts);
01074     r[0] = elts[0];  r[4] = elts[1];  r[8]  = elts[2];
01075     r[1] = elts[3];  r[5] = elts[4];  r[9]  = elts[5];
01076     r[2] = elts[6];  r[6] = elts[7];  r[10] = elts[8];
01077     r[15] = 1.0f;
01078     glMultMatrixf(r);
01079 
01080     s[0]  = scale*0.5f*width;
01081     s[5]  = scale*0.5f*width;
01082     s[10] = scale*length;
01083     s[15] = 1.0f;
01084     glMultMatrixf(s);
01085 
01086     GLint slices = static_cast<GLint>(2.0f*width*scale);
01087     if (slices < 6)
01088         slices = 6;
01089     GLint stacks = static_cast<GLint>(length*scale);
01090     if (stacks < 1)
01091         stacks = 1;
01092     gluCylinder(quad, 1, 1, 1, slices, stacks);
01093 
01094     glPopMatrix();
01095 }
01096 #endif
01097 
01098 
01115 float Apical_hypha::get_intersection
01116 (
01117     jwsc::Vector_f**      isect_out, 
01118     uint32_t              n,
01119     const jwsc::Vector_f* p1_in, 
01120     const jwsc::Vector_f* p2_in
01121 )
01122 throw (Arg_error)
01123 {
01124     if (n != 1 && n != 2)
01125     {
01126         throw Arg_error("Intersection number is not 1 or 2");
01127     }
01128 
01129     if (p1_in->num_elts != 3 || p2_in->num_elts != 3)
01130     {
01131         throw Arg_error("Line end-points are not in R^3");
01132     }
01133 
01134     // Transform a copy of the vectors to bring them into hypha coords.
01135     Vector_f* p1 = 0;
01136     Vector_f* p2 = 0;
01137     Matrix_f* M  = 0;
01138     subtract_vectors_f(&p1, p1_in, centroid);
01139     subtract_vectors_f(&p2, p2_in, centroid);
01140     transpose_matrix_f(&M, R);
01141     multiply_matrix_and_vector_f(&p1, M, p1);
01142     multiply_matrix_and_vector_f(&p2, M, p2);
01143     free_matrix_f(M);
01144 
01145     float x1 = p1->elts[0];
01146     float y1 = p1->elts[1];
01147     float z1 = p1->elts[2];
01148 
01149     free_vector_f(p1);
01150 
01151     float x2 = p2->elts[0];
01152     float y2 = p2->elts[1];
01153     float z2 = p2->elts[2];
01154 
01155     free_vector_f(p2);
01156 
01157     float i = x2 - x1;
01158     float j = y2 - y1;
01159     float k = z2 - z1;
01160 
01161     float r = 0.5f*width;
01162 
01163     float a = i*i + j*j;
01164     float b = 2*x1*i + 2*y1*j;
01165     float c = x1*x1 + y1*y1 - r*r;
01166 
01167     float discriminant = b*b - 4*a*c;
01168     float t;
01169 
01170     if (discriminant < 0.0f)
01171     {
01172         // no real roots
01173         return -1;
01174     }
01175     else if (discriminant > 1.0e-6f)
01176     {
01177         // two real roots
01178         float t1 = (-b + sqrt(discriminant)) / (2*a);
01179         float t2 = (-b - sqrt(discriminant)) / (2*a);
01180 
01181         if ((n == 1 && t1 < t2) || (n == 2 && t1 > t2))
01182         {
01183             t = t1;
01184         }
01185         else
01186         {
01187             t = t2;
01188         }
01189     }
01190     else
01191     {
01192         // one real root
01193         t = (-b + sqrt(discriminant)) / (2*a);
01194     }
01195 
01196     // Handle precision problems.
01197     if (t < 0)
01198         t = 0;
01199     else if (t > 1.0f)
01200         t = 1.0f;
01201 
01202     float x = x1 + i*t;
01203     float y = y1 + j*t;
01204     float z = z1 + k*t;
01205 
01206     if (fabs(z) > 0.5f*length)
01207     {
01208         return -1;
01209     }
01210 
01211     create_vector_f(isect_out, 3);
01212     Vector_f* isect = *isect_out;
01213 
01214     isect->elts[0] = x;
01215     isect->elts[1] = y;
01216     isect->elts[2] = z;
01217 
01218     // Transform the intersection point to put it back in world coords.
01219     multiply_matrix_and_vector_f(&isect, R, isect);
01220     add_vectors_f(&isect, isect, centroid);
01221 
01222     return t;
01223 }
01224 
01225 
01227 void Apical_hypha::update_log_prob()
01228 {
01229     Apical_structure::update_log_prob();
01230 
01231     if (parent && (dynamic_cast<Apical_hypha*>(parent) || 
01232                    dynamic_cast<Lateral_hypha*>(parent)))
01233     {
01234         float    mu, sigma;
01235         float    min, max;
01236         double   delta;
01237         double   p_1, p_2;
01238 
01239         /* Take out the width log prob. */
01240         mu        = density->get_width().get_mu();
01241         sigma     = density->get_width().get_sigma();
01242         min       = density->get_width().get_min();
01243         max       = density->get_width().get_max();
01244         delta     = (max - min) / 1000;
01245         p_1       = integrate_gaussian_pdf_d(mu, sigma, width, width+delta); 
01246         p_2       = integrate_gaussian_pdf_d(mu, sigma, min, max);
01247         log_prob -= log((p_1 < JWSC_MIN_LOG_ARG) ? JWSC_MIN_LOG_ARG : p_1);
01248         log_prob += log((p_2 < JWSC_MIN_LOG_ARG) ? JWSC_MIN_LOG_ARG : p_2);
01249 
01250         float w = width - parent->get_width();
01251 
01252         /* Put in the differential width log prob. */
01253         mu        = density->get_dwidth().get_mu();
01254         sigma     = density->get_dwidth().get_sigma();
01255         min       = density->get_dwidth().get_min();
01256         max       = density->get_dwidth().get_max();
01257         delta     = (max - min) / 1000;
01258         p_1       = integrate_gaussian_pdf_d(mu, sigma, w, w+delta); 
01259         p_2       = integrate_gaussian_pdf_d(mu, sigma, min, max);
01260         log_prob += log((p_1 < JWSC_MIN_LOG_ARG) ? JWSC_MIN_LOG_ARG : p_1);
01261         log_prob -= log((p_2 < JWSC_MIN_LOG_ARG) ? JWSC_MIN_LOG_ARG : p_2);
01262 
01263 #if defined ALTERNARIA_HAVE_ISINF && defined ALTERNARIA_HAVE_ISNAN
01264         assert(!std::isinf(log_prob) && !std::isnan(log_prob));
01265 #endif
01266     }
01267 }
01268 
01269 /* -------------------------------------------------------------------------- */
01270 
01271 
01272 
01273 
01274 
01275 
01276 
01277 /* -----------------------  Printed_apical_hypha  --------------------------- */
01278 
01284 Printed_apical_hypha::Printed_apical_hypha(const Apical_hypha_density* density)
01285 {
01286     id = 0;
01287     centroid_x = 0;
01288     centroid_y = 0;
01289     centroid_z = 0;
01290     length = 0;
01291     width = 0;
01292     base_theta = 0;
01293     base_psi = 0;
01294     theta = 0;
01295     psi = 0;
01296     opacity = 0;
01297     level = 0;
01298     parent = 0;
01299     apical = 0;
01300     this->density = density;
01301 }
01302 
01303 
01312 Printed_apical_hypha::Printed_apical_hypha
01313 (
01314     std::istream& in,
01315     const Apical_hypha_density* density
01316 )
01317 throw (IO_error, Arg_error)
01318 {
01319     this->density = density;
01320     read(in);
01321 }
01322 
01323 
01354 void Printed_apical_hypha::read(std::istream& in) throw (IO_error, Arg_error)
01355 {
01356     const char* member_value;
01357 
01358     if (!(member_value = Apical_hypha::get_member_value("Structure", in)))
01359     {
01360         throw Arg_error("Missing structure type");
01361     }
01362 
01363     if (strncmp(member_value, Apical_hypha::type_str(), 
01364                 strlen(Apical_hypha::type_str())) != 0)
01365     {
01366         ostringstream ost;
01367         ost << "Tried to read a '" << member_value << "' as a '"
01368             << Apical_hypha::type_str() << "'";
01369         throw Arg_error(ost.str());
01370     }
01371 
01372     read_id(in);
01373     read_level(in);
01374     read_centroid(in);
01375     read_length(in);
01376     read_width(in);
01377     read_base_theta(in);
01378     read_base_psi(in);
01379     read_theta(in);
01380     read_psi(in);
01381     read_opacity(in);
01382     read_parent(in);
01383     read_apical(in);
01384     read_laterals(in);
01385     read_log_prob(in);
01386 }
01387 
01388 
01400 Apical_hypha* Printed_apical_hypha::convert(Structure* parent) const 
01401     throw (Arg_error)
01402 {
01403     if (parent)
01404     {
01405         return new Apical_hypha(parent, length, width, base_theta, base_psi,
01406                 theta, psi, opacity, density);
01407     }
01408 
01409     return new Apical_hypha(centroid_x, centroid_y, centroid_z, length, width,
01410             base_theta, base_psi, theta, psi, opacity, level, density);
01411 }
01412 
01413 /* -------------------------------------------------------------------------- */
01414 
01415 
01416 
01417 
01418 
01419 
01420 
01421 /* ---------------------------  Lateral_hypha  ------------------------------ */
01422 
01441 Lateral_hypha::Lateral_hypha
01442 (
01443     float centroid_x, 
01444     float centroid_y,
01445     float centroid_z,
01446     float lat_dist,
01447     float length,
01448     float width,
01449     float base_theta,
01450     float base_psi,
01451     float theta,
01452     float psi,
01453     float opacity,
01454     size_t level,
01455     const class Lateral_hypha_density* density
01456 ) 
01457 throw (Arg_error)
01458     : Lateral_structure(centroid_x, centroid_y, centroid_z, lat_dist, length, 
01459             width, base_theta, base_psi, theta, psi, opacity, level, density)
01460 {
01461     this->density = density;
01462 
01463     update_ancestry_log_prob();
01464 }
01465 
01466 
01483 Lateral_hypha::Lateral_hypha
01484 (
01485     Structure* parent,
01486     float      lat_dist,
01487     float      length,
01488     float      width,
01489     float      base_theta,
01490     float      base_psi,
01491     float      theta,
01492     float      psi,
01493     float      opacity,
01494     const class Lateral_hypha_density* density
01495 )
01496 throw (Arg_error, Apical_error)
01497     : Lateral_structure(parent, lat_dist, length, width, base_theta, base_psi,
01498             theta, psi, opacity, density)
01499 {
01500     this->density = density;
01501 
01502     update_ancestry_log_prob();
01503 }
01504 
01505 
01507 Lateral_hypha::Lateral_hypha(const Lateral_hypha& h) : Lateral_structure(h)
01508 {
01509     density = h.density;
01510 }
01511 
01512 
01514 Lateral_hypha* Lateral_hypha::clone() const
01515 {
01516     return new Lateral_hypha(*this);
01517 }
01518 
01519 
01525 Lateral_hypha& Lateral_hypha::operator= (const Lateral_hypha& h)
01526 {
01527     Lateral_structure::operator=(h);
01528 
01529     density = h.density;
01530 
01531     return *this;
01532 }
01533 
01534 
01576 bool Lateral_hypha::draw_in_matblock_f
01577 (
01578     jwsc::Matblock_f* M_blk,
01579     float       x, 
01580     float       y,
01581     float       z,
01582     float       x_scale,
01583     float       y_scale,
01584     float       z_scale,
01585     bool        fill
01586 )
01587 const
01588 {
01589     uint32_t num_mats, num_rows, num_cols;
01590     uint32_t mat, row, col;
01591 
01592     float height, radius;
01593     float min_scale;
01594     float phi;
01595     float phi_step;
01596     float h;
01597     float h_step;
01598     float r;
01599     float r_step;
01600     float x_0, y_0, z_0;
01601 
01602     Vector_f* point = 0;
01603 
01604     num_mats = M_blk->num_mats;
01605     num_rows = M_blk->num_rows;
01606     num_cols = M_blk->num_cols;
01607 
01608     height = length;
01609     radius = 0.5*width;
01610 
01611     create_vector_f(&point, 3);
01612 
01613     if (x_scale < y_scale && x_scale < z_scale)
01614         min_scale = x_scale;
01615     else if (y_scale < z_scale)
01616         min_scale = y_scale;
01617     else
01618         min_scale = z_scale;
01619 
01620     h_step = 0.5*min_scale;
01621     r_step = (fill) ? 0.5*min_scale : radius;
01622     phi_step = 0.5*min_scale / radius;
01623 
01624     bool intersect = false;
01625 
01626     // Iterate over the points on the hypha parametrically and paint each
01627     // point in the matrix block.
01628     for (r = radius; r > 0; r -= r_step)
01629     {
01630         for (phi = 0; phi < 2*JWSC_PI; phi += phi_step)
01631         {
01632             x_0 = r*std::cos(phi);
01633             y_0 = r*std::sin(phi);
01634 
01635             for (h = 0; h <= height; h += h_step)
01636             {
01637                 z_0 = h;
01638 
01639                 point->elts[0] = x_0;
01640                 point->elts[1] = y_0;
01641                 point->elts[2] = z_0;
01642                 multiply_matrix_and_vector_f(&point, R, point);
01643                 add_vectors_f(&point, point, begin_pt);
01644 
01645                 col = static_cast<uint32_t>(std::floor(
01646                             (point->elts[0] - x) / x_scale + 0.5));
01647                 row = static_cast<uint32_t>(std::floor(
01648                             (point->elts[1] - y) / y_scale + 0.5));
01649                 mat = static_cast<uint32_t>(std::floor(
01650                             (point->elts[2] - z) / z_scale + 0.5));
01651 
01652 
01653                 if (mat >= 0 && mat < num_mats &&
01654                     row >= 0 && row < num_rows && 
01655                     col >= 0 && col < num_cols)
01656                 {
01657                     uint32_t current_id = (uint32_t)floor(
01658                             M_blk->elts[ mat ][ row ][ col ]);
01659 
01660                     if (current_id > 0 && current_id != id && 
01661                             !has_child_id(current_id))
01662                     {
01663                         intersect = true;
01664                     }
01665 
01666                     M_blk->elts[ mat ][ row ][ col ] = id + opacity;
01667                 }
01668             }
01669         }
01670     }
01671 
01672     free_vector_f(point);
01673 
01674     return intersect;
01675 }
01676 
01677 
01682 #if defined ALTERNARIA_HAVE_OPENGL_FRAMEWORK || defined ALTERNARIA_HAVE_OPENGL
01683 void Lateral_hypha::draw_in_opengl(GLUquadric* quad, float scale) const
01684 {
01685     static GLfloat amb_dif[4] = {0.7f, 0.8f, 0.9f, 1.0f};
01686     static GLfloat shininess[1] = {100.0f};
01687     static GLfloat r[16] = {0};
01688     static GLfloat s[16] = {0};
01689 
01690     glMatrixMode(GL_MODELVIEW);
01691 
01692     glPushMatrix();
01693 
01694     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, amb_dif);
01695     glMaterialfv(GL_FRONT, GL_SPECULAR, amb_dif);
01696     glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
01697 
01698     glTranslatef(scale*begin_pt->elts[0], scale*begin_pt->elts[1], 
01699             scale*begin_pt->elts[2]);
01700 
01701     const float* elts = *(R->elts);
01702     r[0] = elts[0];  r[4] = elts[1];  r[8]  = elts[2];
01703     r[1] = elts[3];  r[5] = elts[4];  r[9]  = elts[5];
01704     r[2] = elts[6];  r[6] = elts[7];  r[10] = elts[8];
01705     r[15] = 1.0f;
01706     glMultMatrixf(r);
01707 
01708     s[0]  = scale*0.5f*width;
01709     s[5]  = scale*0.5f*width;
01710     s[10] = scale*length;
01711     s[15] = 1.0f;
01712     glMultMatrixf(s);
01713 
01714     GLint slices = static_cast<GLint>(2.0f*width*scale);
01715     if (slices < 6)
01716         slices = 6;
01717     GLint stacks = static_cast<GLint>(length*scale);
01718     if (stacks < 1)
01719         stacks = 1;
01720     gluCylinder(quad, 1, 1, 1, slices, stacks);
01721 
01722     glPopMatrix();
01723 }
01724 #endif
01725 
01726 
01744 float Lateral_hypha::get_intersection
01745 (
01746     jwsc::Vector_f**      isect_out, 
01747     uint32_t              n,
01748     const jwsc::Vector_f* p1_in, 
01749     const jwsc::Vector_f* p2_in
01750 )
01751 throw (Arg_error)
01752 {
01753     if (n != 1 && n != 2)
01754     {
01755         throw Arg_error("Intersection number is not 1 or 2");
01756     }
01757 
01758     if (p1_in->num_elts != 3 || p2_in->num_elts != 3)
01759     {
01760         throw Arg_error("Line end-points are not in R^3");
01761     }
01762 
01763     // Transform a copy of the vectors to bring them into hypha coords.
01764     Vector_f* p1 = 0;
01765     Vector_f* p2 = 0;
01766     Matrix_f* M  = 0;
01767     subtract_vectors_f(&p1, p1_in, centroid);
01768     subtract_vectors_f(&p2, p2_in, centroid);
01769     transpose_matrix_f(&M, R);
01770     multiply_matrix_and_vector_f(&p1, M, p1);
01771     multiply_matrix_and_vector_f(&p2, M, p2);
01772     free_matrix_f(M);
01773 
01774     float x1 = p1->elts[0];
01775     float y1 = p1->elts[1];
01776     float z1 = p1->elts[2];
01777 
01778     free_vector_f(p1);
01779 
01780     float x2 = p2->elts[0];
01781     float y2 = p2->elts[1];
01782     float z2 = p2->elts[2];
01783 
01784     free_vector_f(p2);
01785 
01786     float i = x2 - x1;
01787     float j = y2 - y1;
01788     float k = z2 - z1;
01789 
01790     float r = 0.5f*width;
01791 
01792     float a = i*i + j*j;
01793     float b = 2*x1*i + 2*y1*j;
01794     float c = x1*x1 + y1*y1 - r*r;
01795 
01796     float discriminant = b*b - 4*a*c;
01797     float t;
01798 
01799     if (discriminant < 0.0f)
01800     {
01801         // no real roots
01802         return -1;
01803     }
01804     else if (discriminant > 1.0e-6f)
01805     {
01806         // two real roots
01807         float t1 = (-b + sqrt(discriminant)) / (2*a);
01808         float t2 = (-b - sqrt(discriminant)) / (2*a);
01809 
01810         if ((n == 1 && t1 < t2) || (n == 2 && t1 > t2))
01811         {
01812             t = t1;
01813         }
01814         else
01815         {
01816             t = t2;
01817         }
01818     }
01819     else
01820     {
01821         // one real root
01822         t = (-b + sqrt(discriminant)) / (2*a);
01823     }
01824 
01825     // Handle precision problems.
01826     if (t < 0)
01827         t = 0;
01828     else if (t > 1.0f)
01829         t = 1.0f;
01830 
01831     float x = x1 + i*t;
01832     float y = y1 + j*t;
01833     float z = z1 + k*t;
01834 
01835     if (fabs(z) > 0.5f*length)
01836     {
01837         return -1;
01838     }
01839 
01840     create_vector_f(isect_out, 3);
01841     Vector_f* isect = *isect_out;
01842 
01843     isect->elts[0] = x;
01844     isect->elts[1] = y;
01845     isect->elts[2] = z;
01846 
01847     // Transform the intersection point to put it back in world coords.
01848     multiply_matrix_and_vector_f(&isect, R, isect);
01849     add_vectors_f(&isect, isect, centroid);
01850 
01851     return t;
01852 }
01853 
01854 /* -------------------------------------------------------------------------- */
01855 
01856 
01857 
01858 
01859 
01860 
01861 
01862 
01863 /* -----------------------  Printed_lateral_hypha  -------------------------- */
01864 
01871 Printed_lateral_hypha::Printed_lateral_hypha
01872 (
01873     const Lateral_hypha_density* level_1_density,
01874     const Lateral_hypha_density* level_n_density
01875 )
01876 {
01877     id = 0;
01878     centroid_x = 0;
01879     centroid_y = 0;
01880     centroid_z = 0;
01881     length = 0;
01882     width = 0;
01883     base_theta = 0;
01884     base_psi = 0;
01885     theta = 0;
01886     psi = 0;
01887     opacity = 0;
01888     level = 0;
01889     parent = 0;
01890     apical = 0;
01891     this->level_1_density = level_1_density;
01892     this->level_n_density = level_n_density;
01893 }
01894 
01895 
01904 Printed_lateral_hypha::Printed_lateral_hypha
01905 (
01906     std::istream& in,
01907     const Lateral_hypha_density* level_1_density,
01908     const Lateral_hypha_density* level_n_density
01909 )
01910 throw (IO_error, Arg_error)
01911 {
01912     this->level_1_density = level_1_density;
01913     this->level_n_density = level_n_density;
01914     read(in);
01915 }
01916 
01917 
01949 void Printed_lateral_hypha::read(std::istream& in) throw (IO_error, Arg_error)
01950 {
01951     const char* member_value;
01952 
01953     if (!(member_value = Lateral_hypha::get_member_value("Structure", in)))
01954     {
01955         throw Arg_error("Missing structure type");
01956     }
01957 
01958     if (strncmp(member_value, Lateral_hypha::type_str(), 
01959                 strlen(Lateral_hypha::type_str())) != 0)
01960     {
01961         ostringstream ost;
01962         ost << "Tried to read a '" << member_value << "' as a '"
01963             << Lateral_hypha::type_str() << "'";
01964         throw Arg_error(ost.str());
01965     }
01966 
01967     read_id(in);
01968     read_level(in);
01969     read_centroid(in);
01970     read_length(in);
01971     read_width(in);
01972     read_base_theta(in);
01973     read_base_psi(in);
01974     read_theta(in);
01975     read_psi(in);
01976     read_opacity(in);
01977     read_parent(in);
01978     read_apical(in);
01979     read_laterals(in);
01980     read_log_prob(in);
01981     read_lat_dist(in);
01982 }
01983 
01984 
01996 Lateral_hypha* Printed_lateral_hypha::convert(Structure* parent) const 
01997     throw (Arg_error)
01998 {
01999     const Lateral_hypha_density* density = (level == 1) ? level_1_density 
02000                                                         : level_n_density;
02001 
02002     if (parent)
02003     {
02004         return new Lateral_hypha(parent, lat_dist, length, width, base_theta,
02005                 base_psi, theta, psi, opacity, density);
02006     }
02007 
02008     return new Lateral_hypha(centroid_x, centroid_y, centroid_z, lat_dist,
02009             length, width, base_theta, base_psi, theta, psi, opacity, level,
02010             density);
02011 }
02012 
02013 /* -------------------------------------------------------------------------- */