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 }