// splittris.cxx -- read in a .ele/.node file pair generated by the // triangle program and output a simple Wavefront .obj // file for the north, south, east, and west edge // verticies ... including the normals. // // Written by Curtis Olson, started January 1998. // // Copyright (C) 1997 Curtis L. Olson - curt@infoplane.com // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // $Id$ // (Log is kept at end of this file) #include #include #include // for atoi() #include #include // for stat() #include // for stat() #include "splittris.hxx" #include #include #include #include #include #include // int nodecount, tricount; double xmin, xmax, ymin, ymax; // static double nodes_orig[MAX_NODES][3]; // static fgPoint3d nodes_cart[MAX_NODES]; // static int tris[MAX_TRIS][3]; container_3d nodes_orig; container_3d nodes_cart; container_tri tri_list; fgBUCKET ne_index, nw_index, sw_index, se_index; fgBUCKET north_index, south_index, east_index, west_index; // convert a geodetic point lon(arcsec), lat(arcsec), elev(meter) to a // cartesian point fgPoint3d geod_to_cart(fgPoint3d geod) { fgPoint3d cp; fgPoint3d pp; double gc_lon, gc_lat, sl_radius; // printf("A geodetic point is (%.2f, %.2f, %.2f)\n", // geod[0], geod[1], geod[2]); gc_lon = geod.lon * ARCSEC_TO_RAD; fgGeodToGeoc(geod.lat * ARCSEC_TO_RAD, geod.radius, &sl_radius, &gc_lat); // printf("A geocentric point is (%.2f, %.2f, %.2f)\n", gc_lon, // gc_lat, sl_radius+geod[2]); pp.lon = gc_lon; pp.lat = gc_lat; pp.radius = sl_radius + geod.radius; cp = fgPolarToCart3d(pp); // printf("A cart point is (%.8f, %.8f, %.8f)\n", cp.x, cp.y, cp.z); return(cp); } // given three points defining a triangle, calculate the normal void calc_normal(fgPoint3d p1, fgPoint3d p2, fgPoint3d p3, double normal[3]) { double v1[3], v2[3]; double temp; v1[0] = p2.x - p1.x; v1[1] = p2.y - p1.y; v1[2] = p2.z - p1.z; v2[0] = p3.x - p1.x; v2[1] = p3.y - p1.y; v2[2] = p3.z - p1.z; MAT3cross_product(normal, v1, v2); MAT3_NORMALIZE_VEC(normal,temp); // printf(" Normal = %.2f %.2f %.2f\n", normal[0], normal[1], normal[2]); } // return the file base name ( foo/bar/file.ext = file.ext ) string extract_file(const string& input) { int pos; pos = input.rfind("/"); ++pos; return input.substr(pos); } // return the file path name ( foo/bar/file.ext = foo/bar ) string extract_path(const string& input) { int pos; pos = input.rfind("/"); return input.substr(0, pos); } // return the index of all triangles containing the specified node void find_tris(int n, int *t1, int *t2, int *t3, int *t4, int *t5) { int i; *t1 = *t2 = *t3 = *t4 = *t5 = 0; i = 1; iterator_tri last = tri_list.end(); iterator_tri current = tri_list.begin(); // skip first null record ++current; for ( ; current != last; ++current ) { if ( (n == (*current).n1) || (n == (*current).n2) || (n == (*current).n3) ) { if ( *t1 == 0 ) { *t1 = i; } else if ( *t2 == 0 ) { *t2 = i; } else if ( *t3 == 0 ) { *t3 = i; } else if ( *t4 == 0 ) { *t4 = i; } else { *t5 = i; } } ++i; } } // Initialize a new mesh structure void triload(const string& basename) { string nodename, elename; fgPoint3d node1, node2; triangle tri; FILE *node_file, *ele_file; int nodecount, tricount, dim, junk1, junk2; int i; nodename = basename + ".node"; elename = basename + ".ele"; cout << "Loading node file: " + nodename + " ...\n"; if ( (node_file = fopen(nodename.c_str(), "r")) == NULL ) { cout << "Cannot open file " + nodename + "\n"; exit(-1); } // the triangle program starts counting at 1 by default which is // pretty obnoxious. Let's just push null record zero's onto our // list to compensate nodes_orig.push_back(node1); nodes_cart.push_back(node1); tri_list.push_back(tri); fscanf(node_file, "%d %d %d %d", &nodecount, &dim, &junk1, &junk2); cout << " Expecting " << nodecount << " nodes\n"; for ( i = 1; i <= nodecount; i++ ) { fscanf(node_file, "%d %lf %lf %lf %d\n", &junk1, &(node1.x), &(node1.y), &(node1.z), &junk2); printf("%d %.2f %.2f %.2f\n", junk1, node1.x, node1.y, node1.z); nodes_orig.push_back(node1); node2 = geod_to_cart(node1); nodes_cart.push_back(node2); printf("%d %.2f %.2f %.2f\n", junk1, node2.x, node2.y, node2.z); if ( i == 1 ) { xmin = xmax = node1.x; ymin = ymax = node1.y; } else { if ( node1.x < xmin ) { xmin = node1.x; } if ( node1.x > xmax ) { xmax = node1.x; } if ( node1.y < ymin ) { ymin = node1.y; } if ( node1.y > ymax ) { ymax = node1.y; } } } fclose(node_file); cout << "Loading element file: " + elename + " ...\n"; if ( (ele_file = fopen(elename.c_str(), "r")) == NULL ) { cout << "Cannot open file " + elename + "\n"; exit(-1); } fscanf(ele_file, "%d %d %d", &tricount, &junk1, &junk2); cout << " Expecting " << tricount << " elements\n"; for ( i = 1; i <= tricount; i++ ) { fscanf(ele_file, "%d %d %d %d\n", &junk1, &(tri.n1), &(tri.n2), &(tri.n3)); printf("%d %d %d %d\n", junk1, tri.n1, tri.n2, tri.n3); tri_list.push_back(tri); } fclose(ele_file); } // check if a file exists int file_exists(char *file) { struct stat stat_buf; int result; cout << "checking " << file << " ... "; result = stat(file, &stat_buf); if ( result != 0 ) { // stat failed, no file cout << "not found.\n"; return 0; } else { // stat succeeded, file exists cout << "exists.\n"; return 1; } } // check to see if a shared object exists int shared_object_exists(const char *basepath, const string& ext) { char file[256], scene_path[256]; long int index; if ( ext == ".sw" ) { fgBucketGenBasePath(&west_index, scene_path); index = fgBucketGenIndex(&west_index); sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&sw_index, scene_path); index = fgBucketGenIndex(&sw_index); sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&south_index, scene_path); index = fgBucketGenIndex(&south_index); sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } if ( ext == ".se" ) { fgBucketGenBasePath(&east_index, scene_path); index = fgBucketGenIndex(&east_index); sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&se_index, scene_path); index = fgBucketGenIndex(&se_index); sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&south_index, scene_path); index = fgBucketGenIndex(&south_index); sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } if ( ext == ".ne" ) { fgBucketGenBasePath(&east_index, scene_path); index = fgBucketGenIndex(&east_index); sprintf(file, "%s/%s/%ld.1.nw", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&ne_index, scene_path); index = fgBucketGenIndex(&ne_index); sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&north_index, scene_path); index = fgBucketGenIndex(&north_index); sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } if ( ext == ".nw" ) { fgBucketGenBasePath(&west_index, scene_path); index = fgBucketGenIndex(&west_index); sprintf(file, "%s/%s/%ld.1.ne", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&nw_index, scene_path); index = fgBucketGenIndex(&nw_index); sprintf(file, "%s/%s/%ld.1.se", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } fgBucketGenBasePath(&north_index, scene_path); index = fgBucketGenIndex(&north_index); sprintf(file, "%s/%s/%ld.1.sw", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } if ( ext == ".south" ) { fgBucketGenBasePath(&south_index, scene_path); index = fgBucketGenIndex(&south_index); sprintf(file, "%s/%s/%ld.1.north", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } if ( ext == ".north" ) { fgBucketGenBasePath(&north_index, scene_path); index = fgBucketGenIndex(&north_index); sprintf(file, "%s/%s/%ld.1.south", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } if ( ext == ".west" ) { fgBucketGenBasePath(&west_index, scene_path); index = fgBucketGenIndex(&west_index); sprintf(file, "%s/%s/%ld.1.east", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } if ( ext == ".east" ) { fgBucketGenBasePath(&east_index, scene_path); index = fgBucketGenIndex(&east_index); sprintf(file, "%s/%s/%ld.1.west", basepath, scene_path, index); if ( file_exists(file) ) { return(1); } } return(0); } // my custom file opening routine ... don't open if a shared edge or // vertex alread exists FILE *my_open(const string& basename, const string& basepath, const string& ext) { FILE *fp; string filename; // create the output file name filename = basename + ext; // check if a shared object already exist from a different tile if ( shared_object_exists(basepath.c_str(), ext) ) { // not an actual file open error, but we've already got the // shared edge, so we don't want to create another one cout << "not opening\n"; return(NULL); } else { // open the file fp = fopen(filename.c_str(), "w"); cout << "Opening " + filename + "\n"; return(fp); } } // dump in WaveFront .obj format void dump_obj(const string& basename, const string& basepath) { fgPoint3d node; double n1[3], n2[3], n3[3], n4[3], n5[3], norm[3], temp; FILE *fp, *sw, *se, *ne, *nw, *north, *south, *east, *west, *body; int i, t1, t2, t3, t4, t5, count, size; sw = my_open(basename, basepath, ".sw"); se = my_open(basename, basepath, ".se"); ne = my_open(basename, basepath, ".ne"); nw = my_open(basename, basepath, ".nw"); north = my_open(basename, basepath, ".north"); south = my_open(basename, basepath, ".south"); east = my_open(basename, basepath, ".east"); west = my_open(basename, basepath, ".west"); body = my_open(basename, basepath, ".body"); cout << "Dumping edges file basename: " + basename + " ...\n"; // dump vertices cout << " writing vertices\n"; iterator_3d last = nodes_orig.end(); iterator_3d current = nodes_orig.begin(); ++current; for ( ; current != last; ++current) { node = *current; if ( (fabs(node.y - ymin) < FG_EPSILON) && (fabs(node.x - xmin) < FG_EPSILON) ) { fp = sw; } else if ( (fabs(node.y - ymin) < FG_EPSILON) && (fabs(node.x - xmax) < FG_EPSILON) ) { fp = se; } else if ( (fabs(node.y - ymax) < FG_EPSILON) && (fabs(node.x - xmax) < FG_EPSILON)) { fp = ne; } else if ( (fabs(node.y - ymax) < FG_EPSILON) && (fabs(node.x - xmin) < FG_EPSILON) ) { fp = nw; } else if ( fabs(node.x - xmin) < FG_EPSILON ) { fp = west; } else if ( fabs(node.x - xmax) < FG_EPSILON ) { fp = east; } else if ( fabs(node.y - ymin) < FG_EPSILON ) { fp = south; } else if ( fabs(node.y - ymax) < FG_EPSILON ) { fp = north; } else { fp = body; } if ( fp != NULL ) { fprintf(fp, "gdn %.2f %.2f %.2f\n", node.x, node.y, node.z); } } cout << " calculating and writing normals\n"; // calculate and generate normals size = nodes_orig.size(); for ( i = 1; i < size; i++ ) { // printf("Finding normal\n"); find_tris(i, &t1, &t2, &t3, &t4, &t5); n1[0] = n1[1] = n1[2] = 0.0; n2[0] = n2[1] = n2[2] = 0.0; n3[0] = n3[1] = n3[2] = 0.0; n4[0] = n4[1] = n4[2] = 0.0; n5[0] = n5[1] = n5[2] = 0.0; count = 1; calc_normal(nodes_cart[tri_list[t1].n1], nodes_cart[tri_list[t1].n2], nodes_cart[tri_list[t1].n3], n1); if ( t2 > 0 ) { calc_normal(nodes_cart[tri_list[t2].n1], nodes_cart[tri_list[t2].n2], nodes_cart[tri_list[t2].n3], n2); count = 2; } if ( t3 > 0 ) { calc_normal(nodes_cart[tri_list[t3].n1], nodes_cart[tri_list[t3].n2], nodes_cart[tri_list[t3].n3], n3); count = 3; } if ( t4 > 0 ) { calc_normal(nodes_cart[tri_list[t4].n1], nodes_cart[tri_list[t4].n2], nodes_cart[tri_list[t4].n3], n4); count = 4; } if ( t5 > 0 ) { calc_normal(nodes_cart[tri_list[t5].n1], nodes_cart[tri_list[t5].n2], nodes_cart[tri_list[t5].n3], n5); count = 5; } // printf(" norm[2] = %.2f %.2f %.2f\n", n1[2], n2[2], n3[2]); norm[0] = ( n1[0] + n2[0] + n3[0] + n4[0] + n5[0] ) / (double)count; norm[1] = ( n1[1] + n2[1] + n3[1] + n4[1] + n5[1] ) / (double)count; norm[2] = ( n1[2] + n2[2] + n3[2] + n4[2] + n5[2] ) / (double)count; // printf(" count = %d\n", count); // printf(" Ave. normal = %.4f %.4f %.4f\n", norm[0], norm[1], // norm[2]); MAT3_NORMALIZE_VEC(norm, temp); // printf(" Normalized ave. normal = %.4f %.4f %.4f\n", // norm[0], norm[1], norm[2]); fp = NULL; if ( (fabs(nodes_orig[i].y - ymin) < FG_EPSILON) && (fabs(nodes_orig[i].x - xmin) < FG_EPSILON) ) { fp = sw; } else if ( (fabs(nodes_orig[i].y - ymin) < FG_EPSILON) && (fabs(nodes_orig[i].x - xmax) < FG_EPSILON) ) { fp = se; } else if ( (fabs(nodes_orig[i].y - ymax) < FG_EPSILON) && (fabs(nodes_orig[i].x - xmax) < FG_EPSILON)) { fp = ne; } else if ( (fabs(nodes_orig[i].y - ymax) < FG_EPSILON) && (fabs(nodes_orig[i].x - xmin) < FG_EPSILON) ) { fp = nw; } else if ( fabs(nodes_orig[i].x - xmin) < FG_EPSILON ) { fp = west; } else if ( fabs(nodes_orig[i].x - xmax) < FG_EPSILON ) { fp = east; } else if ( fabs(nodes_orig[i].y - ymin) < FG_EPSILON ) { fp = south; } else if ( fabs(nodes_orig[i].y - ymax) < FG_EPSILON ) { fp = north; } if ( fp != NULL ) { fprintf(fp, "vn %.4f %.4f %.4f\n", norm[0], norm[1], norm[2]); } } if ( sw ) { fclose(sw); } if ( se ) { fclose(se); } if ( ne ) { fclose(ne); } if ( nw ) { fclose(nw); } if ( north ) { fclose(north); } if ( south ) { fclose(south); } if ( east ) { fclose(east); } if ( west ) { fclose(west); } if ( body ) { fclose(body); } } int main(int argc, char **argv) { string basename, basepath, temp; fgBUCKET p; long int index; int len; basename = argv[1]; // find the base path of the file basepath = extract_path(basename); basepath = extract_path(basepath); basepath = extract_path(basepath); cout << "basepath = " + basepath + "\n"; // find the index of the current file temp = extract_file(basename); len = temp.length(); if ( len >= 2 ) { temp = temp.substr(0, len-2); } index = atoi( temp.c_str() ); cout << "index = " << index << "\n"; fgBucketParseIndex(index, &p); cout << "bucket = " << p.lon << " " << p.lat << " " << p.x << " " << p.y << "\n"; // generate the indexes of the neighbors fgBucketOffset(&p, &ne_index, 1, 1); fgBucketOffset(&p, &nw_index, -1, 1); fgBucketOffset(&p, &se_index, 1, -1); fgBucketOffset(&p, &sw_index, -1, -1); fgBucketOffset(&p, &north_index, 0, 1); fgBucketOffset(&p, &south_index, 0, -1); fgBucketOffset(&p, &east_index, 1, 0); fgBucketOffset(&p, &west_index, -1, 0); // printf("Corner indexes = %ld %ld %ld %ld\n", // ne_index, nw_index, sw_index, se_index); // printf("Edge indexes = %ld %ld %ld %ld\n", // north_index, south_index, east_index, west_index); // load the input data files triload(basename); // dump in WaveFront .obj format dump_obj(basename, basepath); return(0); } // $Log$ // Revision 1.3 1998/09/22 23:49:56 curt // C++-ified, STL-ified, and string-ified. // // Revision 1.2 1998/09/21 23:16:23 curt // Converted to c++ style comments. // // Revision 1.1 1998/07/08 14:59:13 curt // *.[ch] renamed to *.[ch]xx // // Revision 1.11 1998/07/04 00:56:40 curt // typedef'd struct fgBUCKET. // // Revision 1.10 1998/05/02 01:54:37 curt // Converting to polar3d.h routines. // // Revision 1.9 1998/04/18 04:01:20 curt // Now use libMath rather than having local copies of math routines. // // Revision 1.8 1998/04/14 02:26:08 curt // Code reorganizations. Added a Lib/ directory for more general libraries. // // Revision 1.7 1998/04/08 23:21:13 curt // Adopted Gnu automake/autoconf system. // // Revision 1.6 1998/03/03 15:36:13 curt // Tweaks for compiling with g++ // // Revision 1.5 1998/03/03 03:37:04 curt // Cumulative tweaks. // // Revision 1.4 1998/01/31 00:41:26 curt // Made a few changes converting floats to doubles. // // Revision 1.3 1998/01/27 18:37:04 curt // Lots of updates to get back in sync with changes made over in .../Src/ // // Revision 1.2 1998/01/14 15:54:43 curt // Initial revision completed. // // Revision 1.1 1998/01/14 02:11:31 curt // Initial revision. //