Main Page   Namespace List   Class Hierarchy   Compound List   File List   Header Files   Sources   Namespace Members   Compound Members   File Members  

MapDataDocument_update.cpp

00001 //$Header: /home/ben/Mapper/c++/RCS/MapDataDocument_update.cpp,v 6.14 2002/07/14 19:17:57 ben Exp $
00002 // Copyright Benedict Adamson 2002.
00003 // This file is part of Mapper.
00004 
00005 // Mapper is free software; you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation; either version 2 of the License, or
00008 // (at your option) any later version.
00009 
00010 // Mapper is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 
00015 // You should have received a copy of the GNU General Public License
00016 // along with Mapper; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00030 #include <cmath>
00031 #include <cstdio>
00032 
00033 #include <dom/DOM_Element.hpp>
00034 #include <dom/DOM_Document.hpp>
00035 #include <dom/DOM_NodeList.hpp>
00036 
00037 #include "MapDataDocument.h"
00038 #include "constraint.h"
00039 #include "curve.h"
00040 #include "curve_segment.h"
00041 #include "vector2.h"
00042 
00043 
00044 
00045 
00046 void MapDataDocument::set_attribute(
00047    DOM_Element &elem, //input, output
00048    const string &attr,
00049    const double x,
00050    const unsigned precision
00051    )
00052 {
00053    const char format[] = "%0.*f";
00054    int p = precision; //kludge to workaround printf expectation
00055    unsigned buflen = 6U + precision;
00056    char *buffer = new char[buflen];
00057    while( -1 == snprintf( buffer, buflen, format, p, x ) ){//too long
00058      //expand buffer
00059      delete buffer;
00060      buflen *= 2;
00061      buffer = new char[buflen];
00062    };
00063    elem.setAttribute( DOMString( attr.c_str() ), buffer );
00064    delete buffer;
00065 }
00066 
00067 
00068 
00069 void MapDataDocument::update_points(
00070    const DOM_NodeList &nodes, //input, output
00071    unsigned &n_points, //input, output
00072    double &left, //input, output
00073    double &right, //input, output
00074    double & top, //input, output
00075    double &bottom //input, output
00076    )
00077 {
00078    for( unsigned i = 0; i < nodes.getLength(); i++ ){
00079       DOM_Node node( nodes.item(i) );
00080       assert( node.getNodeType() == DOM_Node::ELEMENT_NODE );
00081       DOM_Element &elem( static_cast< DOM_Element & >( node ) );
00082       vector2 * p = static_cast< vector2 * >( elem.getUserData() );
00083       if( p ){
00084          set_attribute( elem, "x", p->x, this->precision );
00085          set_attribute( elem, "y", p->y, this->precision );
00086          if( 0 < n_points ){
00087             left = min( left, p->x );
00088             right = max( right, p->x );
00089             top = max( top, p->y );
00090             bottom = min( bottom, p->y );
00091          }else{//first point
00092             left = p->x;
00093             right = p->x;
00094             top = p->y;
00095             bottom = p->y;
00096          };
00097          n_points++;
00098       }; //else earlier error(s) or no point
00099    };
00100 };
00101 
00102 
00103 
00104 void MapDataDocument::update_constraints(
00105    const double tol,
00106    const DOM_NodeList &nodes //input, output
00107    )
00108 {
00109    {//preconditions
00110       assert( 0 < tol && tol < 1 );
00111    };
00112    for( unsigned i = 0; i < nodes.getLength(); i++ ){
00113       DOM_Node node( nodes.item(i) );
00114       assert( node.getNodeType() == DOM_Node::ELEMENT_NODE );
00115       DOM_Element &elem( static_cast< DOM_Element & >( node ) );
00116       constraint * c = static_cast< constraint * >( elem.getUserData() );
00117       if( c )
00118          set_attribute( elem, "e", c->energy( tol ), 2U );
00119       ;//else earlier error(s)
00120    };
00121 };
00122    
00123 
00124 
00125 void MapDataDocument::update_child_Coord(
00126    DOM_Document &doc, //input
00127    DOM_Element &elem, //input
00128    DOM_Node &child, //input, output
00129    const vector2 &p
00130    )
00131 {
00132    static const DOMString Coord( "Coord" ) ;
00133    while(
00134       child.isNull() ||
00135       child.getNodeType() != DOM_Node::ELEMENT_NODE ||
00136       !static_cast< DOM_Element & >( child ).getTagName().equals( Coord )
00137       ){ //not a Coord element
00138       if( child.isNull() ){
00139          //create a new child
00140          DOM_Element n( doc.createElement( Coord ) );
00141          elem.appendChild( n );
00142          child = n;
00143       }else
00144          child = child.getNextSibling();
00145       ;
00146    };
00147    DOM_Element n( static_cast< DOM_Element & >( child ) );
00148    set_attribute( n, "x", p.x, this->precision + 3 );
00149    set_attribute( n, "y", p.y, this->precision + 3 );
00150    child = child.getNextSibling();
00151 }
00152 
00153 
00154 
00155 void MapDataDocument::update_curve_segments(
00156    const DOM_NodeList &nodes //input
00157    )
00158 {
00159    for( unsigned i = 0; i < nodes.getLength(); i++ ){
00160       DOM_Node node( nodes.item(i) );
00161       if( node.getNodeType() != DOM_Node::ELEMENT_NODE )
00162          continue; //syntax error
00163       DOM_Element &elem( static_cast< DOM_Element & >( node ) );
00164       curve_segment *s = static_cast< curve_segment * >(
00165          elem.getUserData()
00166          );
00167       if( !s || !s->along || !s->from || !s->to )
00168          continue; //conversion error
00169       double t0, t1; //range of parameter values
00170       {
00171          const double tol = 1E-8;
00172          const unsigned max_iter = 100U;
00173          unsigned iter; //discarded
00174          double d20, d21; //discarded
00175          nearest_point(
00176             *(s->along),
00177             *(s->from),
00178             tol, max_iter,
00179             t0, d20, iter
00180             );
00181          nearest_point(
00182             *(s->along),
00183             *(s->to),
00184             tol, max_iter,
00185             t1, d21, iter
00186             );
00187       };
00188       unsigned n_spline; //number of splines along the curve
00189       {
00190          if( s->along->param.size() <= 2 ) //straight line
00191             n_spline = 1;
00192          else{
00193             n_spline = (unsigned)(
00194                4.0 * double(s->along->param.size() - 2) *
00195                fabs( t1 - t0 )
00196                );
00197             if( n_spline < 1 ) n_spline = 1;
00198          };
00199       };
00200       const double f = (t1 - t0)/(3.0 * double(n_spline)); //scaling factor
00201       vector2 p3;
00202       vector2 dpdt3;
00203       DOM_Node cnode( elem.getFirstChild() );
00204       DOM_Document doc( elem.getOwnerDocument() );
00205       {//update the start point
00206          s->along->position(
00207             t0, p3, dpdt3
00208             );
00209          update_child_Coord( doc, elem, cnode, p3 );
00210       };
00211       for( unsigned spline = 1; spline <= n_spline; spline++ ){
00212          //update the control points for one spline
00213          vector2 p0, p1, p2;
00214          vector2 dpdt0;
00215          {//determine the control points
00216             p0 = p3;
00217             dpdt0 = dpdt3;
00218             p1 = p0 + f*dpdt0;
00219             const double t = t0 + (t1-t0) * double(spline)/
00220                double(n_spline);
00221             s->along->position(
00222                t, p3, dpdt3
00223                );
00224             p2 = p3 - f*dpdt3;
00225          };
00226          update_child_Coord( doc, elem, cnode, p1 );
00227          update_child_Coord( doc, elem, cnode, p2 );
00228          update_child_Coord( doc, elem, cnode, p3 );
00229       };
00230       {//kill excess Coord children
00231          while( !cnode.isNull() ){
00232             if( cnode.getNodeType() != DOM_Node::ELEMENT_NODE )
00233                cnode = cnode.getNextSibling();
00234             else{
00235                DOM_Element child( static_cast< DOM_Element & >(
00236                   cnode )       );
00237                if( child.getTagName().equals( DOMString( "Coord" ) ) ){
00238                   cnode = cnode.getNextSibling();
00239                   elem.removeChild( child );
00240                }else
00241                   cnode = cnode.getNextSibling();
00242                ;
00243             };
00244          };
00245       };
00246    };
00247 }
00248 
00249 
00250 
00251 void MapDataDocument::update(
00252    const double tol
00253    )
00254 {
00255    {//preconditions
00256       assert( 0 < tol && tol < 1 );
00257    };
00258    DOM_Element root( this->doc.getDocumentElement() );
00259    unsigned n_points = 0;
00260    double left;
00261    double right;
00262    double top;
00263    double bottom;
00264    update_points(
00265       root.getElementsByTagName( DOMString("Point" ) ),
00266       n_points, left, right, top, bottom
00267       );
00268    update_points(
00269       root.getElementsByTagName( DOMString("Node" ) ),
00270       n_points, left, right, top, bottom
00271       );
00272    update_points(
00273       root.getElementsByTagName( DOMString("Line-segment" ) ),
00274       n_points, left, right, top, bottom
00275       );
00276    update_points(
00277       root.getElementsByTagName( DOMString("Traced-point" ) ),
00278       n_points, left, right, top, bottom
00279       );
00280    {
00281       DOM_NodeList nodes( root.getElementsByTagName( DOMString("Curve" ) ) );
00282       for( unsigned i = 0; i < nodes.getLength(); i++ ){
00283          DOM_Node node( nodes.item(i) );
00284          if( node.getNodeType() != DOM_Node::ELEMENT_NODE )
00285             break; //syntax error
00286          DOM_Element &elem( static_cast< DOM_Element & >( node ) );
00287          update_points(
00288             elem.getElementsByTagName( DOMString("Coord" ) ),
00289             n_points, left, right, top, bottom
00290             );
00291       };
00292    };
00293    if( 0 < n_points ){//update the attributes of the root tag
00294       assert( left <= right );
00295       assert( bottom <= top );
00296       set_attribute( root, "x", left, this->precision );
00297       set_attribute( root, "y", top, this->precision );
00298       set_attribute( root, "width", right - left, this->precision );
00299       set_attribute( root, "height", top - bottom, this->precision );
00300    };
00301    update_constraints(
00302       tol,
00303       root.getElementsByTagName( DOMString("Angle" ) )
00304       );
00305    update_constraints(
00306       tol,
00307       root.getElementsByTagName( DOMString("Bearing" ) )
00308       );
00309    update_constraints(
00310       tol,
00311       root.getElementsByTagName( DOMString("Distance" ) )
00312       );
00313    update_constraints(
00314       tol,
00315       root.getElementsByTagName( DOMString("Through" ) )
00316       );
00317    update_constraints(
00318       tol,
00319       root.getElementsByTagName( DOMString("Vector" ) )
00320       );
00321    update_curve_segments(
00322       root.getElementsByTagName( DOMString("Curve-segment" ) )
00323       );
00324 }

Generated at Sun Jul 14 20:38:09 2002 for Mapper by doxygen 1.0.0 written by Dimitri van Heesch, © 1997-1999