"Fossies" - the Fresh Open Source Software Archive

Member "gama-2.05/lib/gnu_gama/xml/dataparser_g3.cpp" (10 May 2019, 34111 Bytes) of package /linux/privat/gama-2.05.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dataparser_g3.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.04_vs_2.05.

    1 /*
    2   GNU Gama -- adjustment of geodetic networks
    3   Copyright (C) 2002, 2005, 2018, 2019  Ales Cepek <cepek@gnu.org>
    4 
    5   This file is part of the GNU Gama C++ library
    6 
    7   This library is free software; you can redistribute it and/or modify
    8   it under the terms of the GNU General Public License as published by
    9   the Free Software Foundation; either version 3 of the License, or
   10   (at your option) any later version.
   11 
   12   This library is distributed in the hope that it will be useful,
   13   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15   GNU General Public License for more details.
   16 
   17   You should have received a copy of the GNU General Public License
   18   along with GNU Gama.  If not, see <http://www.gnu.org/licenses/>.
   19 */
   20 
   21 #include <gnu_gama/xml/dataparser.h>
   22 #include <gnu_gama/gon2deg.h>
   23 #include <gnu_gama/radian.h>
   24 #include <cstring>
   25 
   26 using namespace std;
   27 using namespace GNU_gama;
   28 
   29 namespace GNU_gama {
   30 
   31   struct DataParser_g3 {
   32 
   33     DataParser_g3() : model(nullptr)
   34     {
   35     }
   36     ~DataParser_g3()
   37     {
   38       delete model;
   39     }
   40 
   41     typedef std::list<double> Scale;
   42     Scale              scale;
   43 
   44 
   45     typedef g3::Model::ObservationType::CovarianceMatrix Cov;
   46 
   47     g3::Model*         model;
   48     g3::ObsCluster*    obs_cluster;
   49     std::list<Cov>     cov_list;
   50     double             from_dh;
   51     double             to_dh;
   52     double             left_dh;
   53     double             right_dh;
   54   };
   55 
   56 }
   57 
   58 
   59 void DataParser::close_g3()
   60 {
   61   delete g3;
   62 }
   63 
   64 void DataParser::init_g3()
   65 {
   66   g3 = new DataParser_g3;
   67 
   68   optional(g3->from_dh);
   69   optional(g3->to_dh);
   70 
   71 
   72   // .....  <g3-model>  ..............................................
   73 
   74   init(s_gama_data, t_g3_model,
   75        s_g3_model, 0, 0,
   76        &DataParser::g3_model, nullptr, &DataParser::g3_model);
   77 
   78   // .....  <g3-model>  <constants>  .................................
   79 
   80   init(s_g3_model, t_constants,
   81        s_g3_const, 0, s_g3_model,
   82        nullptr, nullptr, nullptr);
   83 
   84   init(s_g3_const, t_apriori_sd,
   85        s_g3_const_apriori_sd, 0, s_g3_const,
   86        nullptr, &DataParser::add_text, &DataParser::g3_const_apriori_sd);
   87 
   88   init(s_g3_const, t_conf_level,
   89        s_g3_const_conf_level, 0, s_g3_const,
   90        nullptr, &DataParser::add_text, &DataParser::g3_const_conf_level);
   91 
   92   init(s_g3_const, t_tol_abs,
   93        s_g3_const_tol_abs, 0, s_g3_const,
   94        nullptr, &DataParser::add_text, &DataParser::g3_const_tol_abs);
   95 
   96   init(s_g3_const, t_ang_degrees,
   97        s_g3_const_ang, 0, s_g3_const,
   98        nullptr, nullptr, &DataParser::g3_const_ang_degrees);
   99 
  100   init(s_g3_const, t_ang_gons,
  101        s_g3_const_ang, 0, s_g3_const,
  102        nullptr, nullptr, &DataParser::g3_const_ang_gons);
  103 
  104   // .....  <g3-model>  <constants>  <ellipsoid>  ....................
  105 
  106   init(s_g3_const, t_ellipsoid,
  107        s_g3_const_ellipsoid, s_g3_const_ellipsoid2, s_g3_const,
  108        nullptr, nullptr, nullptr);
  109 
  110   init(s_g3_const_ellipsoid, t_id,
  111        s_g3_const_ellipsoid_id, 0, s_g3_const_ellipsoid2,
  112        nullptr, &DataParser::add_text, &DataParser::g3_const_ellipsoid_id);
  113 
  114   init(s_g3_const_ellipsoid, t_a,
  115        0, 0, s_g3_const_ellipsoid_a,
  116        nullptr, &DataParser::add_text, nullptr);
  117 
  118   init(s_g3_const_ellipsoid_a, t_b,
  119        s_g3_const_ellipsoid_b, 0, s_g3_const_ellipsoid2,
  120        nullptr, &DataParser::add_text, &DataParser::g3_const_ellipsoid_b);
  121 
  122   init(s_g3_const_ellipsoid_a, t_inv_f,
  123        s_g3_const_ellipsoid_inv_f, 0, s_g3_const_ellipsoid2,
  124        nullptr, &DataParser::add_text, &DataParser::g3_const_ellipsoid_inv_f);
  125 
  126   // .....  <g3-model> <unused | fixed | free | constr>  .............
  127 
  128   init(s_g3_model, t_unused,
  129        s_g3_param, 0, s_g3_model,
  130        &DataParser::g3_param_unused, nullptr, nullptr);
  131 
  132   init(s_g3_model, t_fixed,
  133        s_g3_param, 0, s_g3_model,
  134        &DataParser::g3_param_fixed, nullptr, nullptr);
  135 
  136   init(s_g3_model, t_free,
  137        s_g3_param, 0, s_g3_model,
  138        &DataParser::g3_param_free, nullptr, nullptr);
  139 
  140   init(s_g3_model, t_constr,
  141        s_g3_param, 0, s_g3_model,
  142        &DataParser::g3_param_constr, nullptr, nullptr);
  143 
  144   init(s_g3_param, t_n,
  145        s_g3_param_n, 0, 0,
  146        nullptr, nullptr, &DataParser::g3_param_n);
  147 
  148   init(s_g3_param, t_e,
  149        s_g3_param_e, 0, 0,
  150        nullptr, nullptr, &DataParser::g3_param_e);
  151 
  152   init(s_g3_param, t_u,
  153        s_g3_param_u, 0, 0,
  154        nullptr, nullptr, &DataParser::g3_param_u);
  155 
  156   // .....  <g3-model> <point>  .....................................
  157 
  158   init(s_g3_model, t_point,
  159        s_g3_point_1, s_g3_point_2, s_g3_model,
  160        nullptr, nullptr, &DataParser::g3_point);
  161 
  162   init(s_g3_point_1, t_id,
  163        s_g3_point_id, 0, s_g3_point_2,
  164        nullptr, &DataParser::add_text, &DataParser::g3_point_id);
  165 
  166   init(s_g3_point_2, t_b,
  167        s_g3_point_b, 0, s_g3_point_after_b,
  168        nullptr, &DataParser::add_text, &DataParser::g3_point_b);
  169 
  170   init(s_g3_point_after_b, t_l,
  171        s_g3_point_l, 0, s_g3_point_after_l,
  172        nullptr, &DataParser::add_text, &DataParser::g3_point_l);
  173 
  174   init(s_g3_point_after_l, t_h,
  175        s_g3_point_h, 0, s_g3_point_2,
  176        nullptr, &DataParser::add_text, &DataParser::g3_point_h);
  177 
  178   init(s_g3_point_2, t_x,
  179        s_g3_point_x, 0, s_g3_point_after_x,
  180        nullptr, &DataParser::add_text, nullptr);
  181 
  182   init(s_g3_point_after_x, t_y,
  183        s_g3_point_y, 0, s_g3_point_after_y,
  184        nullptr, &DataParser::add_text, nullptr);
  185 
  186   init(s_g3_point_after_y, t_z,
  187        s_g3_point_z, 0, s_g3_point_2,
  188        nullptr, &DataParser::add_text, &DataParser::g3_point_z);
  189 
  190   init(s_g3_point_2, t_height,
  191        s_g3_point_height, 0, s_g3_point_2,
  192        nullptr, &DataParser::add_text, &DataParser::g3_point_height);
  193 
  194   init(s_g3_point_2, t_geoid,
  195        s_g3_point_geoid, 0, s_g3_point_2,
  196        nullptr, &DataParser::add_text, &DataParser::g3_point_geoid);
  197 
  198   init(s_g3_point_2, t_unused,
  199        s_g3_point_param, 0, s_g3_point_2,
  200        &DataParser::g3_param_unused, nullptr, nullptr);
  201 
  202   init(s_g3_point_2, t_fixed,
  203        s_g3_point_param, 0, s_g3_point_2,
  204        &DataParser::g3_param_fixed, nullptr, nullptr);
  205 
  206   init(s_g3_point_2, t_free,
  207        s_g3_point_param, 0, s_g3_point_2,
  208        &DataParser::g3_param_free, nullptr, nullptr);
  209 
  210   init(s_g3_point_2, t_constr,
  211        s_g3_point_param, 0, s_g3_point_2,
  212        &DataParser::g3_param_constr, nullptr, nullptr);
  213 
  214   init(s_g3_point_param, t_n,
  215        s_g3_point_param_n, 0, 0,
  216        nullptr, nullptr, &DataParser::g3_point_param_n);
  217 
  218   init(s_g3_point_param, t_e,
  219        s_g3_point_param_e, 0, 0,
  220        nullptr, nullptr, &DataParser::g3_point_param_e);
  221 
  222   init(s_g3_point_param, t_u,
  223        s_g3_point_param_u, 0, 0,
  224        nullptr, nullptr, &DataParser::g3_point_param_u);
  225 
  226   init(s_g3_point_2, t_db,
  227        s_g3_point_db, 0, s_g3_point_after_db,
  228        nullptr, &DataParser::add_text, nullptr);
  229 
  230   init(s_g3_point_after_db, t_dl,
  231        s_g3_point_dl, 0, s_g3_point_2,
  232        nullptr, &DataParser::add_text, &DataParser::g3_point_dl);
  233 
  234   // .....  <g3-model> <obs>  ........................................
  235 
  236   init(s_g3_model, t_obs,
  237        s_g3_obs, 0, 0,
  238        &DataParser::g3_obs, nullptr, &DataParser::g3_obs);
  239 
  240   // .....  <g3-model> <obs> <cov-mat>  ..............................
  241 
  242   init(s_g3_obs, t_covmat,
  243        s_g3_obs_covmat, s_g3_obs_covmat_after_band, 0,
  244        nullptr, nullptr, &DataParser::g3_obs_cov);
  245 
  246   init(s_g3_obs_covmat, t_dim,
  247        s_g3_obs_covmat_dim, 0, s_g3_obs_covmat_after_dim,
  248        nullptr, &DataParser::add_text, nullptr);
  249 
  250   init(s_g3_obs_covmat_after_dim, t_band,
  251        s_g3_obs_covmat_band, 0, s_g3_obs_covmat_after_band,
  252        nullptr, &DataParser::add_text, nullptr);
  253 
  254   init(s_g3_obs_covmat_after_band, t_flt,
  255        s_g3_obs_covmat_flt, 0, s_g3_obs_covmat_after_band,
  256        nullptr, &DataParser::add_text, nullptr);
  257 
  258   // .....  <g3-model> <obs> <distance>  .............................
  259 
  260   init(s_g3_obs, t_dist,
  261        s_g3_obs_dist, s_g3_obs_dist_opt, 0,
  262        nullptr, nullptr, &DataParser::g3_obs_dist);
  263 
  264   init(s_g3_obs_dist, t_from,
  265        s_g3_obs_dist_from, 0, s_g3_obs_dist_after_from,
  266        nullptr, &DataParser::add_text, nullptr);
  267 
  268   init(s_g3_obs_dist_after_from, t_to,
  269        s_g3_obs_dist_to, 0, s_g3_obs_dist_after_to,
  270        nullptr, &DataParser::add_text, nullptr);
  271 
  272   init(s_g3_obs_dist_after_to, t_val,
  273        s_g3_obs_dist_val, 0, s_g3_obs_dist_opt,
  274        nullptr, &DataParser::add_text, nullptr);
  275 
  276   init(s_g3_obs_dist_opt, t_stdev,
  277        s_g3_obs_dist_opt_stdev, 0, 0,
  278        nullptr, &DataParser::optional_stdev, nullptr);
  279 
  280   init(s_g3_obs_dist_opt, t_variance,
  281        s_g3_obs_dist_opt_variance, 0, 0,
  282        nullptr, &DataParser::optional_variance, nullptr);
  283 
  284   init(s_g3_obs_dist_opt, t_from_dh,
  285        s_g3_obs_dist_opt_from_dh, 0, 0,
  286        nullptr, &DataParser::optional_from_dh, nullptr);
  287 
  288   init(s_g3_obs_dist_opt, t_to_dh,
  289        s_g3_obs_dist_opt_to_dh, 0, 0,
  290        nullptr, &DataParser::optional_to_dh, nullptr);
  291 
  292   // .....  <g3-model> <obs> <zenith>  ...............................
  293 
  294   init(s_g3_obs, t_zenith,
  295        s_g3_obs_zenith, s_g3_obs_zenith_opt, 0,
  296        nullptr, nullptr, &DataParser::g3_obs_zenith);
  297 
  298   init(s_g3_obs_zenith, t_from,
  299        s_g3_obs_zenith_from, 0, s_g3_obs_zenith_after_from,
  300        nullptr, &DataParser::add_text, nullptr);
  301 
  302   init(s_g3_obs_zenith_after_from, t_to,
  303        s_g3_obs_zenith_to, 0, s_g3_obs_zenith_after_to,
  304        nullptr, &DataParser::add_text, nullptr);
  305 
  306   init(s_g3_obs_zenith_after_to, t_val,
  307        s_g3_obs_zenith_val, 0, s_g3_obs_zenith_opt,
  308        nullptr, &DataParser::add_text, nullptr);
  309 
  310   init(s_g3_obs_zenith_opt, t_stdev,
  311        s_g3_obs_zenith_opt_stdev, 0, 0,
  312        nullptr, &DataParser::optional_stdev, nullptr);
  313 
  314   init(s_g3_obs_zenith_opt, t_variance,
  315        s_g3_obs_zenith_opt_variance, 0, 0,
  316        nullptr, &DataParser::optional_variance, nullptr);
  317 
  318   init(s_g3_obs_zenith_opt, t_from_dh,
  319        s_g3_obs_zenith_opt_from_dh, 0, 0,
  320        nullptr, &DataParser::optional_from_dh, nullptr);
  321 
  322   init(s_g3_obs_zenith_opt, t_to_dh,
  323        s_g3_obs_zenith_opt_to_dh, 0, 0,
  324        nullptr, &DataParser::optional_to_dh, nullptr);
  325 
  326  // .....  <g3-model> <obs> <azimuth>  ...............................
  327 
  328   init(s_g3_obs, t_azimuth,
  329        s_g3_obs_azimuth, s_g3_obs_azimuth_opt, 0,
  330        nullptr, nullptr, &DataParser::g3_obs_azimuth);
  331 
  332   init(s_g3_obs_azimuth, t_from,
  333        s_g3_obs_azimuth_from, 0, s_g3_obs_azimuth_after_from,
  334        nullptr, &DataParser::add_text, nullptr);
  335 
  336   init(s_g3_obs_azimuth_after_from, t_to,
  337        s_g3_obs_azimuth_to, 0, s_g3_obs_azimuth_after_to,
  338        nullptr, &DataParser::add_text, nullptr);
  339 
  340   init(s_g3_obs_azimuth_after_to, t_val,
  341        s_g3_obs_azimuth_val, 0, s_g3_obs_azimuth_opt,
  342        nullptr, &DataParser::add_text, nullptr);
  343 
  344   init(s_g3_obs_azimuth_opt, t_stdev,
  345        s_g3_obs_azimuth_opt_stdev, 0, 0,
  346        nullptr, &DataParser::optional_stdev, nullptr);
  347 
  348   init(s_g3_obs_azimuth_opt, t_variance,
  349        s_g3_obs_azimuth_opt_variance, 0, 0,
  350        nullptr, &DataParser::optional_variance, nullptr);
  351 
  352   init(s_g3_obs_azimuth_opt, t_from_dh,
  353        s_g3_obs_azimuth_opt_from_dh, 0, 0,
  354        nullptr, &DataParser::optional_from_dh, nullptr);
  355 
  356   init(s_g3_obs_azimuth_opt, t_to_dh,
  357        s_g3_obs_azimuth_opt_to_dh, 0, 0,
  358        nullptr, &DataParser::optional_to_dh, nullptr);
  359 
  360   // .....  <g3-model> <obs> <vector>  ...............................
  361 
  362   init(s_g3_obs, t_vector,
  363        s_g3_obs_vector, s_g3_obs_vector_opt, 0,
  364        nullptr, nullptr, &DataParser::g3_obs_vector);
  365 
  366    init(s_g3_obs_vector, t_from,
  367         s_g3_obs_vector_from, 0, s_g3_obs_vector_after_from,
  368         nullptr, &DataParser::add_text, nullptr);
  369 
  370    init(s_g3_obs_vector_after_from, t_to,
  371         s_g3_obs_vector_to, 0, s_g3_obs_vector_after_to,
  372         nullptr, &DataParser::add_text, nullptr);
  373 
  374    init(s_g3_obs_vector_after_to, t_dx,
  375         s_g3_obs_vector_dx, 0, s_g3_obs_vector_after_dx,
  376         nullptr, &DataParser::add_text, nullptr);
  377 
  378    init(s_g3_obs_vector_after_dx, t_dy,
  379         s_g3_obs_vector_dy, 0, s_g3_obs_vector_after_dy,
  380         nullptr, &DataParser::add_text, nullptr);
  381 
  382    init(s_g3_obs_vector_after_dy, t_dz,
  383         s_g3_obs_vector_dz, 0, s_g3_obs_vector_opt,
  384         nullptr, &DataParser::add_text, nullptr);
  385 
  386    init(s_g3_obs_vector_opt, t_from_dh,
  387         s_g3_obs_vector_opt_from_dh, 0, 0,
  388         nullptr, &DataParser::optional_from_dh, nullptr);
  389 
  390    init(s_g3_obs_vector_opt, t_to_dh,
  391         s_g3_obs_vector_opt_to_dh, 0, 0,
  392         nullptr, &DataParser::optional_to_dh, nullptr);
  393 
  394    // .....  <g3-model> <obs> <xyz>  ..................................
  395 
  396    init(s_g3_obs, t_xyz,
  397         s_g3_obs_xyz, s_g3_obs_xyz_after_z, 0,
  398         nullptr, nullptr, &DataParser::g3_obs_xyz);
  399 
  400    init(s_g3_obs_xyz, t_id,
  401         s_g3_obs_xyz_id, 0, s_g3_obs_xyz_after_id,
  402         nullptr, &DataParser::add_text, nullptr);
  403 
  404    init(s_g3_obs_xyz_after_id, t_x,
  405         s_g3_obs_xyz_x, 0, s_g3_obs_xyz_after_x,
  406         nullptr, &DataParser::add_text, nullptr);
  407 
  408    init(s_g3_obs_xyz_after_x, t_y,
  409         s_g3_obs_xyz_y, 0, s_g3_obs_xyz_after_y,
  410         nullptr, &DataParser::add_text, nullptr);
  411 
  412    init(s_g3_obs_xyz_after_y, t_z,
  413         s_g3_obs_xyz_z, 0, s_g3_obs_xyz_after_z,
  414         nullptr, &DataParser::add_text, nullptr);
  415 
  416    // .....  <g3-model> <obs> <hdiff>  ................................
  417 
  418    init(s_g3_obs, t_hdiff,
  419         s_g3_obs_hdiff, s_g3_obs_hdiff_opt, 0,
  420         nullptr, nullptr, &DataParser::g3_obs_hdiff);
  421 
  422    init(s_g3_obs_hdiff, t_from,
  423         s_g3_obs_hdiff_from, 0, s_g3_obs_hdiff_after_from,
  424         nullptr, &DataParser::add_text, nullptr);
  425 
  426    init(s_g3_obs_hdiff_after_from, t_to,
  427         s_g3_obs_hdiff_to, 0, s_g3_obs_hdiff_after_to,
  428         nullptr, &DataParser::add_text, nullptr);
  429 
  430    init(s_g3_obs_hdiff_after_to, t_val,
  431         s_g3_obs_hdiff_val, 0, s_g3_obs_hdiff_opt,
  432         nullptr, &DataParser::add_text, nullptr);
  433 
  434    init(s_g3_obs_hdiff_opt, t_stdev,
  435         s_g3_obs_hdiff_opt_stdev, 0, 0,
  436         nullptr, &DataParser::optional_stdev, nullptr);
  437 
  438    init(s_g3_obs_hdiff_opt, t_variance,
  439         s_g3_obs_hdiff_opt_variance, 0, 0,
  440         nullptr, &DataParser::optional_variance, nullptr);
  441 
  442 //  init(s_g3_obs_hdiff_opt, t_from_dh,
  443 //       s_g3_obs_hdiff_opt_from_dh, 0, 0,
  444 //       0, &DataParser::optional_from_dh, 0);
  445 //
  446 //  init(s_g3_obs_hdiff_opt, t_to_dh,
  447 //       s_g3_obs_hdiff_opt_to_dh, 0, 0,
  448 //       0, &DataParser::optional_to_dh, 0);
  449 
  450    // ..... <g3-model> <obs> <height> ...................................
  451 
  452    init(s_g3_obs, t_height,
  453         s_g3_obs_height, s_g3_obs_height_opt, 0,
  454         nullptr, nullptr, &DataParser::g3_obs_height);
  455 
  456    init(s_g3_obs_height, t_id,
  457         s_g3_obs_height_id, 0, s_g3_obs_height_after_id,
  458         nullptr, &DataParser::add_text, nullptr);
  459 
  460    init(s_g3_obs_height_after_id, t_val,
  461         s_g3_obs_height_val, 0, s_g3_obs_height_opt,
  462         nullptr, &DataParser::add_text, nullptr);
  463 
  464    init(s_g3_obs_height_opt, t_stdev,
  465         s_g3_obs_height_opt_stdev, 0, 0,
  466         nullptr, &DataParser::optional_stdev, nullptr);
  467 
  468    init(s_g3_obs_height_opt, t_variance,
  469         s_g3_obs_height_opt_variance, 0, 0,
  470         nullptr, &DataParser::optional_variance, nullptr);
  471 
  472    // ..... <g3-model> <obs> <angle> ...................................
  473 
  474    init(s_g3_obs, t_angle,
  475         s_g3_obs_angle, s_g3_obs_angle_opt, 0,
  476         nullptr, nullptr, &DataParser::g3_obs_angle);
  477 
  478    init(s_g3_obs_angle, t_from,
  479         s_g3_obs_angle_from, 0, s_g3_obs_angle_after_from,
  480         nullptr, &DataParser::add_text, nullptr);
  481 
  482    init(s_g3_obs_angle_after_from, t_left,
  483         s_g3_obs_angle_left, 0, s_g3_obs_angle_after_left,
  484         nullptr, &DataParser::add_text, nullptr);
  485 
  486    init(s_g3_obs_angle_after_left, t_right,
  487         s_g3_obs_angle_right, 0, s_g3_obs_angle_after_right,
  488         nullptr, &DataParser::add_text, nullptr);
  489 
  490    init(s_g3_obs_angle_after_right, t_val,
  491         s_g3_obs_angle_val, 0, s_g3_obs_angle_opt,
  492         nullptr, &DataParser::add_text, nullptr);
  493 
  494    init(s_g3_obs_angle_opt, t_stdev,
  495         s_g3_obs_angle_opt_stdev, 0, 0,
  496         nullptr, &DataParser::optional_stdev, nullptr);
  497 
  498    init(s_g3_obs_angle_opt, t_variance,
  499         s_g3_obs_angle_opt_variance, 0, 0,
  500         nullptr, &DataParser::optional_variance, nullptr);
  501 
  502    init(s_g3_obs_angle_opt, t_from_dh,
  503         s_g3_obs_angle_opt_from_dh, 0, 0,
  504         nullptr, &DataParser::optional_from_dh, nullptr);
  505 
  506    init(s_g3_obs_angle_opt, t_left_dh,
  507         s_g3_obs_angle_opt_left_dh, 0, 0,
  508         nullptr, &DataParser::optional_left_dh, nullptr);
  509 
  510    init(s_g3_obs_angle_opt, t_right_dh,
  511         s_g3_obs_angle_opt_right_dh, 0, 0,
  512         nullptr, &DataParser::optional_right_dh, nullptr);
  513 }
  514 
  515 int DataParser::g3_model(const char *name, const char **atts)
  516 {
  517   no_attributes( name, atts );
  518   state = next[state][tag(name)];
  519 
  520   g3->model = new g3::Model;
  521 
  522   return 0;
  523 }
  524 
  525 int DataParser::g3_model(const char *name)
  526 {
  527   objects.push_back( new DataObject::g3_model(g3->model) );
  528   g3->model = nullptr;
  529 
  530   return  end_tag(name);
  531 }
  532 
  533 int DataParser::g3_param_unused(const char *name, const char **atts)
  534 {
  535   no_attributes( name, atts );
  536   state = next[state][tag(name)];
  537 
  538   local_state.set_unused();
  539 
  540   return  0;
  541 }
  542 
  543 int DataParser::g3_param_fixed(const char *name, const char **atts)
  544 {
  545   no_attributes( name, atts );
  546   state = next[state][tag(name)];
  547 
  548   local_state.set_fixed();
  549 
  550   return  0;
  551 }
  552 
  553 int DataParser::g3_param_free(const char *name, const char **atts)
  554 {
  555   no_attributes( name, atts );
  556   state = next[state][tag(name)];
  557 
  558   local_state.set_free();
  559 
  560   return  0;
  561 }
  562 
  563 int DataParser::g3_param_constr(const char *name, const char **atts)
  564 {
  565   no_attributes( name, atts );
  566   state = next[state][tag(name)];
  567 
  568   local_state.set_constr();
  569 
  570   return  0;
  571 }
  572 
  573 int DataParser::g3_param_n(const char *name)
  574 {
  575   global_state_N.set_state(local_state);
  576 
  577   return  end_tag(name);
  578 }
  579 
  580 int DataParser::g3_param_e(const char *name)
  581 {
  582   global_state_E.set_state(local_state);
  583 
  584   return  end_tag(name);
  585 }
  586 
  587 int DataParser::g3_param_u(const char *name)
  588 {
  589   global_state_U.set_state(local_state);
  590 
  591   return  end_tag(name);
  592 }
  593 
  594 std::string DataParser::g3_get_id(std::string err)
  595 {
  596   char    c;
  597   string id;
  598   string::const_iterator i=text_buffer.begin();
  599   string::const_iterator e=text_buffer.end();
  600 
  601   while (i!=e &&  isspace((c = *i))) { ++i;          }
  602   while (i!=e && !isspace((c = *i))) { ++i; id += c; }
  603   while (i!=e &&  isspace((c = *i))) { ++i;          }
  604 
  605   if (i!=e || id.empty()) error(err);
  606 
  607   text_buffer.erase();
  608   return id;
  609 }
  610 
  611 int DataParser::g3_point(const char *name)
  612 {
  613   // checks consistency of the current point
  614 
  615   if (!point->N.cmp_state(point->E))
  616     return error("### parameters N and E do not have common status");
  617 
  618   return  end_tag(name);
  619 }
  620 
  621 int DataParser::g3_point_id(const char *name)
  622 {
  623   string id = g3_get_id("### bad point name in <id> tag");
  624 
  625   point = g3->model->get_point(id);
  626 
  627   point->N.set_state(global_state_N);
  628   point->E.set_state(global_state_E);
  629   point->U.set_state(global_state_U);
  630 
  631   return  end_tag(name);
  632 }
  633 
  634 int DataParser::g3_point_param_n(const char *name)
  635 {
  636   point->N.set_state(local_state);
  637 
  638   return  end_tag(name);
  639 }
  640 
  641 int DataParser::g3_point_param_e(const char *name)
  642 {
  643   point->E.set_state(local_state);
  644 
  645   return  end_tag(name);
  646 }
  647 
  648 int DataParser::g3_point_param_u(const char *name)
  649 {
  650   point->U.set_state(local_state);
  651 
  652   return  end_tag(name);
  653 }
  654 
  655 int DataParser::g3_point_b(const char *name)
  656 {
  657   if (!deg2gon(text_buffer, blh.b))
  658     {
  659       return error("### bad format of numerical data in <point> <b> ");
  660     }
  661   text_buffer.erase();
  662 
  663   return  end_tag(name);
  664 }
  665 
  666 int DataParser::g3_point_l(const char *name)
  667 {
  668   if (!deg2gon(text_buffer, blh.l))
  669     {
  670       return error("### bad format of numerical data in <point> <l> ");
  671     }
  672   text_buffer.erase();
  673 
  674   return  end_tag(name);
  675 }
  676 
  677 int DataParser::g3_point_h(const char *name)
  678 {
  679   stringstream istr(text_buffer);
  680   if (!(istr >> blh.h))
  681     {
  682       return error("### bad format of numerical data in <point> <h> ");
  683     }
  684   text_buffer.erase();
  685 
  686   blh.b *= GON_TO_RAD;
  687   blh.l *= GON_TO_RAD;
  688   point->set_blh(blh.b, blh.l, blh.h);
  689 
  690   return  end_tag(name);
  691 }
  692 
  693 int DataParser::g3_point_z(const char *name)
  694 {
  695   stringstream istr(text_buffer);
  696   double x, y, z;
  697 
  698   if (!(istr >> x >> y >> z))
  699     {
  700       return error("### bad format of numerical data in <point> xyz ");
  701     }
  702 
  703   text_buffer.erase();
  704 
  705   point->set_xyz(x, y, z);
  706 
  707   return  end_tag(name);
  708 }
  709 
  710 int DataParser::g3_point_height(const char *name)
  711 {
  712   stringstream istr(text_buffer);
  713   double h;
  714 
  715   if (!(istr >> h))
  716     {
  717       return error("### bad format of numerical data in <point> height ");
  718     }
  719 
  720   text_buffer.erase();
  721 
  722   point->set_height(h);
  723 
  724   return  end_tag(name);
  725 }
  726 
  727 int DataParser::g3_point_geoid(const char *name)
  728 {
  729   stringstream istr(text_buffer);
  730   double g;
  731 
  732   if (!(istr >> g))
  733     {
  734       return error("### bad format of numerical data in <point> geoid ");
  735     }
  736 
  737   text_buffer.erase();
  738 
  739   point->set_geoid(g);
  740 
  741   return  end_tag(name);
  742 }
  743 
  744 int DataParser::g3_point_dl(const char *name)
  745 {
  746   stringstream istr(text_buffer);
  747   double db, dl;
  748 
  749   if (!(istr >> db >> dl))
  750     {
  751       return error("### bad format of numerical data in <point> db dl ");
  752     }
  753   text_buffer.erase();
  754 
  755   point->dB.set_init_value(db*SS_TO_RAD);
  756   point->dL.set_init_value(dl*SS_TO_RAD);
  757 
  758   return  end_tag(name);
  759 }
  760 
  761 int DataParser::g3_obs(const char *name, const char **atts)
  762 {
  763   no_attributes( name, atts );
  764   state = next[state][tag(name)];
  765 
  766   g3->obs_cluster = new g3::ObsCluster(&g3->model->obsdata);
  767   g3->scale.clear();
  768 
  769   return 0;
  770 }
  771 
  772 int DataParser::g3_obs(const char *name)
  773 {
  774   using namespace g3;
  775 
  776   int obs_dim = 0;
  777   for (std::list<g3::Observation*>::const_iterator
  778          i=g3->obs_cluster->observation_list.begin(),
  779          e=g3->obs_cluster->observation_list.end();  i!=e;  ++i)
  780     {
  781       obs_dim += (*i)->dimension();
  782     }
  783 
  784   if (obs_dim != int(g3->scale.size()))
  785     return error("### INTERNAL ERROR IN "
  786                  "int DataParser::g3_obs(const char *name)");
  787 
  788 
  789   int cov_dim  = 0;
  790   int cov_band = 0;
  791   typedef std::list<CovMat<> >::const_iterator Iterator;
  792   for (Iterator i=g3->cov_list.begin(), e=g3->cov_list.end(); i!=e; ++i)
  793     {
  794       const CovMat<>& cov = *i;
  795 
  796       cov_dim += cov.dim();
  797       if (int(cov.bandWidth()) > cov_band) cov_band = cov.bandWidth();
  798     }
  799 
  800   if (obs_dim == 0)       return error("### no observations in <obs>");
  801   if (obs_dim != cov_dim) return error("### bad covariance matrix dimension");
  802 
  803   g3->obs_cluster->covariance_matrix.reset(cov_dim, cov_band);
  804   g3->obs_cluster->covariance_matrix.set_zero();
  805 
  806   int offset = 0;
  807   for (Iterator i=g3->cov_list.begin(), e=g3->cov_list.end(); i!=e; ++i)
  808     {
  809       const CovMat<>& cov = *i;
  810 
  811       for (int i=1; i<=cov.dim(); i++)
  812         for (int j=0; j<=cov.bandWidth() && i+j<=cov.dim(); j++)
  813           g3->obs_cluster->covariance_matrix(offset+i, offset+i+j) = cov(i, i+j);
  814 
  815       offset += cov.dim();
  816     }
  817 
  818   /* TODO: !!! here we should better test Cholesky decomposition !!! */
  819   for (int N=g3->obs_cluster->covariance_matrix.dim(), i=1; i<=N; i++)
  820     if(g3->obs_cluster->covariance_matrix(i,i) <= 0)
  821       return error("### zero or negative variance");
  822 
  823 
  824   // here we scale covariance matrix so that all its elements have the
  825   // same units as their corresponding internal representation of
  826   // observables (linear data are stored in meters, angular values in
  827   // radians)
  828 
  829   DataParser_g3::Scale::const_iterator s = g3->scale.begin();
  830   for (int i=1; i<=obs_dim; i++, s++)
  831     {
  832       if (*s != 1.0) g3->obs_cluster->scaleCov(i, *s);
  833     }
  834   g3->scale.clear();
  835 
  836   g3->obs_cluster->update();
  837   g3->model->obsdata.clusters.push_back(g3->obs_cluster);
  838   g3->cov_list.clear();
  839 
  840   return  end_tag(name);
  841 }
  842 
  843 int DataParser::g3_obs_cov(const char *name)
  844 {
  845   using namespace g3;
  846   stringstream istr(text_buffer);
  847   int     d, b;
  848   double  f;
  849 
  850   if (!(istr >> d >> b))  return error("### bad cov-mat");
  851 
  852   DataParser_g3::Cov cov(d, b);
  853   cov.set_zero();
  854   for (int i=1; i<=d; i++)          // upper triangular matrix by rows
  855     for (int j=i; j<=i+b && j<=d; j++)
  856       if (istr >> f)
  857         cov(i,j) = f;
  858       else        return error("### bad cov-mat / some data missing");
  859 
  860   if (!pure_data(istr)) return error("### bad cov-mat / redundant data");
  861 
  862   text_buffer.clear();
  863   g3->cov_list.push_back(cov);
  864 
  865   return  end_tag(name);
  866 }
  867 
  868 int DataParser::optional_stdev(const char *s, int len)
  869 {
  870   using namespace g3;
  871   stringstream istr(string(s, size_t(len))); // explicit conversion to avoid warning
  872   DataParser_g3::Cov   cov(1,0);
  873   double  f;
  874 
  875   if (!pure_data(istr >> f)) return error("### bad <stdev>");
  876 
  877   cov(1,1) = f*f;
  878   g3->cov_list.push_back(cov);
  879 
  880   return 0;
  881 }
  882 
  883 int DataParser::optional_variance(const char *s, int len)
  884 {
  885   using namespace g3;
  886   stringstream istr(string(s, size_t(len)));
  887   DataParser_g3::Cov   cov(1,0);
  888   double  f;
  889 
  890   if (!pure_data(istr >> f)) return error("### bad <variance>");
  891 
  892   cov(1,1) = f;
  893   g3->cov_list.push_back(cov);
  894 
  895   return 0;
  896 }
  897 
  898 int DataParser::optional_from_dh(const char *s, int len)
  899 {
  900   using namespace g3;
  901   stringstream istr(string(s,size_t(len)));
  902 
  903   if (g3->model != nullptr && pure_data(istr >> g3->from_dh)) return 0;
  904 
  905   return error("### bad data in <from-dh>");
  906 }
  907 
  908 int DataParser::optional_to_dh(const char *s, int len)
  909 {
  910   using namespace g3;
  911   stringstream istr(string(s,size_t(len)));
  912 
  913   if (g3->model != nullptr && pure_data(istr >> g3->to_dh)) return 0;
  914 
  915   return error("### bad data in <to-dh>");
  916 }
  917 
  918 int DataParser::optional_left_dh(const char *s, int len)
  919 {
  920   using namespace g3;
  921   stringstream istr(string(s,size_t(len)));
  922 
  923   if (g3->model != nullptr && pure_data(istr >> g3->left_dh)) return 0;
  924 
  925   return error("### bad data in <left-dh>");
  926 }
  927 
  928 int DataParser::optional_right_dh(const char *s, int len)
  929 {
  930   using namespace g3;
  931   stringstream istr(string(s,size_t(len)));
  932 
  933   if (g3->model != nullptr && pure_data(istr >> g3->right_dh)) return 0;
  934 
  935   return error("### bad data in <right-dh>");
  936 }
  937 
  938 int DataParser::g3_obs_dist(const char *name)
  939 {
  940   using namespace g3;
  941   stringstream istr(text_buffer);
  942   string       from, to;
  943   double       val;
  944 
  945   if (g3->model != nullptr && pure_data(istr >> from >> to >> val))
  946     {
  947       text_buffer.clear();
  948 
  949       Distance* distance = new Distance;
  950       distance->from = from;
  951       distance->to   = to;
  952       distance->set(val);
  953       distance->from_dh = optional(g3->from_dh);
  954       distance->to_dh   = optional(g3->to_dh);
  955       g3->obs_cluster->observation_list.push_back(distance);
  956       g3->scale.push_back(1.0);
  957 
  958       return  end_tag(name);
  959     }
  960 
  961   return error("### bad <distance>");
  962 }
  963 
  964 int DataParser::g3_obs_zenith(const char *name)
  965 {
  966   using namespace g3;
  967   stringstream istr(text_buffer);
  968   string       from, to;
  969   string       sval;
  970 
  971   if (g3->model != nullptr && pure_data(istr >> from >> to >> sval))
  972     {
  973       text_buffer.clear();
  974 
  975       double val;
  976       if (deg2gon(sval, val))
  977         {
  978           g3->scale.push_back(3.0864); // ss --> cc
  979         }
  980       else
  981         {
  982           istringstream istr(sval);
  983           istr >> val;
  984 
  985           g3->scale.push_back(1.0);
  986         }
  987 
  988       ZenithAngle* zenith = new ZenithAngle;
  989       zenith->from = from;
  990       zenith->to   = to;
  991       zenith->set(val*GON_TO_RAD);
  992       zenith->from_dh = optional(g3->from_dh);
  993       zenith->to_dh   = optional(g3->to_dh);
  994       g3->obs_cluster->observation_list.push_back(zenith);
  995 
  996       return  end_tag(name);
  997     }
  998 
  999   return error("### bad <zenith>");
 1000 }
 1001 
 1002 int DataParser::g3_obs_azimuth(const char *name)
 1003 {
 1004   using namespace g3;
 1005   stringstream istr(text_buffer);
 1006   string       from, to;
 1007   string       sval;
 1008 
 1009   if (g3->model != nullptr && pure_data(istr >> from >> to >> sval))
 1010     {
 1011       text_buffer.clear();
 1012 
 1013       double val;
 1014       if (!deg2gon(sval, val))
 1015         {
 1016           istringstream istr(sval);
 1017           istr >> val;
 1018         }
 1019 
 1020       Azimuth* azimuth = new Azimuth;
 1021       azimuth->from = from;
 1022       azimuth->to   = to;
 1023       azimuth->set(val);
 1024       azimuth->from_dh = optional(g3->from_dh);
 1025       azimuth->to_dh   = optional(g3->to_dh);
 1026       g3->obs_cluster->observation_list.push_back(azimuth);
 1027 
 1028       return  end_tag(name);
 1029     }
 1030 
 1031   return error("### bad <azimuth>");
 1032 }
 1033 
 1034 int DataParser::g3_obs_vector(const char *name)
 1035 {
 1036   using namespace g3;
 1037   stringstream istr(text_buffer);
 1038   string from, to;
 1039   double dx, dy, dz;
 1040 
 1041   if (g3->model != nullptr && pure_data(istr >> from >> to >> dx >> dy >> dz))
 1042     {
 1043       text_buffer.clear();
 1044 
 1045       Vector* vector = new Vector;
 1046       vector->from = from;
 1047       vector->to   = to;
 1048       vector->set_dxyz(dx, dy, dz);
 1049       vector->from_dh = optional(g3->from_dh);
 1050       vector->to_dh   = optional(g3->to_dh);
 1051 
 1052       g3->obs_cluster->observation_list.push_back(vector);
 1053       g3->scale.push_back(1.0);
 1054       g3->scale.push_back(1.0);
 1055       g3->scale.push_back(1.0);
 1056 
 1057       return end_tag(name);
 1058     }
 1059 
 1060   return error("### bad <vector> from to dx dy dz : " + text_buffer);
 1061 }
 1062 
 1063 int DataParser::g3_obs_xyz(const char *name)
 1064 {
 1065   using namespace g3;
 1066   stringstream istr(text_buffer);
 1067   string id;
 1068   double x, y, z;
 1069 
 1070   if (g3->model != nullptr && pure_data(istr >> id >> x >> y >> z))
 1071     {
 1072       text_buffer.clear();
 1073 
 1074       XYZ* xyz = new XYZ;
 1075       xyz->id  = id;
 1076       xyz->set_xyz(x, y, z);
 1077 
 1078       g3->obs_cluster->observation_list.push_back(xyz);
 1079       g3->scale.push_back(1.0);
 1080       g3->scale.push_back(1.0);
 1081       g3->scale.push_back(1.0);
 1082 
 1083       return end_tag(name);
 1084     }
 1085 
 1086   return error("### bad <xyz>");
 1087 }
 1088 
 1089 int DataParser::g3_obs_hdiff(const char *name)
 1090 {
 1091   using namespace g3;
 1092   stringstream istr(text_buffer);
 1093   string       from, to;
 1094   double       val;
 1095 
 1096   if (g3->model != nullptr && pure_data(istr >> from >> to >> val))
 1097    {
 1098      text_buffer.clear();
 1099 
 1100      HeightDiff* hdiff = new HeightDiff;
 1101      hdiff->from = from;
 1102      hdiff->to   = to;
 1103      hdiff->set(val);
 1104      hdiff->from_dh = optional(g3->from_dh);
 1105      hdiff->to_dh   = optional(g3->to_dh);
 1106      g3->obs_cluster->observation_list.push_back(hdiff);
 1107      g3->scale.push_back(1.0);
 1108 
 1109      return  end_tag(name);
 1110    }
 1111 
 1112   return error("### bad <hdiff>");
 1113 }
 1114 
 1115 int DataParser::g3_obs_height(const char *name)
 1116 {
 1117   using namespace g3;
 1118   stringstream istr(text_buffer);
 1119   string       id;
 1120   double       val;
 1121 
 1122   if (g3->model != nullptr && pure_data(istr >> id >> val))
 1123    {
 1124      text_buffer.clear();
 1125 
 1126      Height* height = new Height;
 1127      height->id = id;
 1128      height->set(val);
 1129      g3->obs_cluster->observation_list.push_back(height);
 1130      g3->scale.push_back(1.0);
 1131 
 1132      return  end_tag(name);
 1133    }
 1134 
 1135   return error("### bad <height>");
 1136 }
 1137 
 1138 int DataParser::g3_const_apriori_sd(const char *name)
 1139 {
 1140   using namespace g3;
 1141   stringstream istr(text_buffer);
 1142   double       sd;
 1143 
 1144   if (g3->model != nullptr && pure_data(istr >> sd))
 1145    {
 1146      text_buffer.clear();
 1147 
 1148      g3->model->set_apriori_sd(sd);
 1149 
 1150      return  end_tag(name);
 1151    }
 1152 
 1153   return error("### bad <height>");
 1154 }
 1155 
 1156 int DataParser::g3_const_conf_level(const char *name)
 1157 {
 1158   using namespace g3;
 1159   stringstream istr(text_buffer);
 1160   double       cl;
 1161 
 1162   if (g3->model != nullptr && pure_data(istr >> cl))
 1163    {
 1164      text_buffer.clear();
 1165 
 1166      g3->model->set_conf_level(cl);
 1167 
 1168      return  end_tag(name);
 1169    }
 1170 
 1171   return error("### bad <confidence-level>");
 1172 }
 1173 
 1174 int DataParser::g3_const_tol_abs(const char *name)
 1175 {
 1176   using namespace g3;
 1177   stringstream istr(text_buffer);
 1178   double       ta;
 1179 
 1180   if (g3->model != nullptr && pure_data(istr >> ta))
 1181    {
 1182      text_buffer.clear();
 1183 
 1184      g3->model->set_tol_abs(ta);
 1185 
 1186      return  end_tag(name);
 1187    }
 1188 
 1189   return error("### bad <tol-abs>");
 1190 }
 1191 
 1192 int DataParser::g3_const_ellipsoid_id(const char * /*name*/)
 1193 {
 1194   using namespace g3;
 1195   stringstream istr(text_buffer);
 1196   string       s;
 1197 
 1198   if (g3->model != nullptr && pure_data(istr >> s))
 1199    {
 1200      text_buffer.clear();
 1201      const char* const name = s.c_str();
 1202      gama_ellipsoid id = ellipsoid(name);
 1203 
 1204      set(&g3->model->ellipsoid, id);
 1205 
 1206      if (id != ellipsoid_unknown) return end_tag(name);
 1207    }
 1208 
 1209   return error("### bad <ellipsoid> <id>");
 1210 }
 1211 
 1212 int DataParser::g3_const_ellipsoid_b(const char *name)
 1213 {
 1214   using namespace g3;
 1215   stringstream istr(text_buffer);
 1216   double       a, b;
 1217 
 1218   if (g3->model != nullptr && pure_data(istr >> a >> b))
 1219    {
 1220      text_buffer.clear();
 1221 
 1222      set(&g3->model->ellipsoid, ellipsoid_unknown);
 1223      g3->model->ellipsoid.set_ab(a, b);
 1224 
 1225      return end_tag(name);
 1226    }
 1227 
 1228   return error("### bad <ellipsoid> <a> <b>");
 1229 }
 1230 
 1231 int DataParser::g3_const_ellipsoid_inv_f(const char *name)
 1232 {
 1233   using namespace g3;
 1234   stringstream istr(text_buffer);
 1235   double       a, inv_f;
 1236 
 1237   if (g3->model != nullptr && pure_data(istr >> a >> inv_f))
 1238    {
 1239      text_buffer.clear();
 1240 
 1241      set(&g3->model->ellipsoid, ellipsoid_unknown);
 1242      g3->model->ellipsoid.set_af1(a, inv_f);
 1243 
 1244      return end_tag(name);
 1245    }
 1246 
 1247   return error("### bad <ellipsoid> <a> <inv-f>");
 1248 }
 1249 
 1250 int DataParser::g3_const_ang_degrees(const char *name)
 1251 {
 1252   text_buffer.clear();
 1253   g3->model->set_angular_units_degrees();
 1254 
 1255   return end_tag(name);
 1256 }
 1257 
 1258 int DataParser::g3_const_ang_gons(const char *name)
 1259 {
 1260   text_buffer.clear();
 1261   g3->model->set_angular_units_gons();
 1262 
 1263   return end_tag(name);
 1264 }
 1265 
 1266 int DataParser::g3_obs_angle(const char *name)
 1267 {
 1268   using namespace g3;
 1269   stringstream istr(text_buffer);
 1270   string       from, left, right;
 1271   string       sval;
 1272 
 1273   if (g3->model != nullptr && pure_data(istr >> from >> left >> right >> sval))
 1274    {
 1275      text_buffer.clear();
 1276 
 1277      double val;
 1278      if (deg2gon(sval, val))
 1279        {
 1280          g3->scale.push_back(3.0864);   // ss --> cc
 1281        }
 1282      else
 1283        {
 1284           istringstream istr(sval);
 1285           istr >> val;
 1286 
 1287           g3->scale.push_back(1.0);
 1288        }
 1289 
 1290      Angle* angle = new Angle;
 1291      angle->from  = from;
 1292      angle->left  = left;
 1293      angle->right = right;
 1294      angle->set(val*GON_TO_RAD);
 1295      angle->from_dh  = optional(g3->from_dh);
 1296      angle->left_dh  = optional(g3->to_dh);
 1297      angle->right_dh = optional(g3->to_dh);
 1298      g3->obs_cluster->observation_list.push_back(angle);
 1299 
 1300      return  end_tag(name);
 1301    }
 1302 
 1303   return error("### bad <angle>");
 1304 }
 1305