//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // isosurface.cc // // Vincent LE PRINCE // Copyright (C) 2000-2005 Vincent LE PRINCE // This file is part of the TRUEVISION Package // 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. */ //******************************************************************************************* #include "include/isosurface.h" #include "include/viewmanager.h" #include "include/objectlist.h" #include "include/tvio.h" #include "include/impsurface.h" #include "include/preferences.h" //************************************** // Constructeur //************************************** IsoSurface::IsoSurface( app_objs *appref ) : Object3D_with_material( appref ) { type = TV_OBJ3D_ISOSURFACE; category = TV_OBJ3D_OBJECTS; set_name( "Isosurface" ); // Definition threshold = new ObjParam_float( N_("Threshold"), "THRES", NULL, app_ref, true, 0 ); threshold->set_range( 50, -50, 0.1, 5 ); // Transformation location = new ObjParam_point( N_("Translation"), "LOC", NULL, app_ref, true ); location->set( 0, 0, 0 ); size = new ObjParam_scale( N_("Scale"), "SIZE", NULL, app_ref, true ); size->set( 0.2, 0.2, 0.2 ); rotation = new ObjParam_rotation( N_("Rotation"), "ROT", NULL, app_ref, true ); rotation->set( 0, 0, 0 ); // Bounding box corner1 = new ObjParam_point( N_("Corner 1"), "CORN1", NULL, app_ref, true ); corner1->set( 1, 1, 1 ); corner2 = new ObjParam_point( N_("Corner 2"), "CORN2", NULL, app_ref, true ); corner2->set( -1, -1, -1 ); show_bb = new ObjParam_bool( N_("Show"), "BBSHOW", NULL, appref, true, true ); // Function function = new ObjParam_function( N_("Function"), "FUNC", NULL, appref, true ); preview = new ObjParam_bool( N_("Preview"), "PREV", NULL, appref, true, true ); open = new ObjParam_bool( N_("Open"), "OPEN", NULL, appref, true, false ); accuracy = new ObjParam_float( N_("Accuracy"), "ACC", NULL, appref, false, 0.001); accuracy->set_range( 100, 0, 0.0001, 6 ); max_gradient = new ObjParam_float( N_("Max gradient"), "MAXG", NULL, appref, false, 1.1 ); max_gradient->set_range( 10000, 0, 0.01, 5 ); all_intersections = new ObjParam_bool( N_("All intersections"), "ALLINT", NULL, appref, false, false ); } IsoSurface::IsoSurface( IsoSurface & ref ) : Object3D_with_material( ref ) { location = new ObjParam_point( *ref.location ); size = new ObjParam_scale( *ref.size ); rotation = new ObjParam_rotation( *ref.rotation ); corner1 = new ObjParam_point( *ref.corner1 ); corner2 = new ObjParam_point( *ref.corner2 ); show_bb = new ObjParam_bool( *ref.show_bb ); threshold = new ObjParam_float( *ref.threshold ); function = new ObjParam_function( *ref.function ); preview = new ObjParam_bool( *ref.preview ); open = new ObjParam_bool( *ref.open ); accuracy = new ObjParam_float( *ref.accuracy ); max_gradient = new ObjParam_float( *ref.max_gradient ); all_intersections = new ObjParam_bool( *ref.all_intersections ); } IsoSurface::~IsoSurface() { delete location; delete size; delete rotation; delete corner1; delete corner2; delete show_bb; delete threshold; delete function; delete preview; delete open; delete accuracy; delete max_gradient; delete all_intersections; } //************************************** // Display // Dessin de la boite //************************************** void IsoSurface::display( glview *view, bool set_col ) { if ( hidden->value() ) return; if ( location->changed() || size->changed() || rotation->changed() || corner1->changed() || corner2->changed() || show_bb->changed() \ || threshold->changed() || function->changed() || preview->changed() || open->changed() ) list.invalidate(); Object3D::display( view ); if ( set_col ) set_color(); if ( ! list.exec() ) { // mise à zero des parametres location->unchange(); size->unchange(); rotation->unchange(); corner1->unchange(); corner2->unchange(); show_bb->unchange(); threshold->unchange(); function->unchange(); preview->unchange(); open->unchange(); // creation de la liste si necessaire list.begin(); glPushMatrix(); // Position et direction gfloat x, y, z; gfloat a, b, c; location->get( x, y, z ); glTranslatef( x, y, z ); size->get( a, b, c ); glScalef( a, b, c ); rotation->gl_rotate(); corner1->get( a, b, c ); corner2->get( x, y, z ); // Bounding box display if requested if ( show_bb->value() ) { const float div = 4.0; float xrule = (x-a) / div ; float yrule = (y-b) / div ; float zrule = (z-c) / div ; glBegin( GL_LINES ); glVertex3f( x, y, z ); glVertex3f( x-xrule, y, z ); glVertex3f( x, y, z ); glVertex3f( x, y-yrule, z ); glVertex3f( x, y, z ); glVertex3f( x, y, z-zrule ); glVertex3f( x, y, c ); glVertex3f( x-xrule, y, c ); glVertex3f( x, y, c ); glVertex3f( x, y-yrule, c ); glVertex3f( x, y, c ); glVertex3f( x, y, c+zrule ); glVertex3f( a, y, z ); glVertex3f( a+xrule, y, z ); glVertex3f( a, y, z ); glVertex3f( a, y-yrule, z ); glVertex3f( a, y, z ); glVertex3f( a, y, z-zrule ); glVertex3f( a, y, c ); glVertex3f( a+xrule, y, c ); glVertex3f( a, y, c ); glVertex3f( a, y-yrule, c ); glVertex3f( a, y, c ); glVertex3f( a, y, c+zrule ); glVertex3f( a, b, c ); glVertex3f( a+xrule, b, c ); glVertex3f( a, b, c ); glVertex3f( a, b+yrule, c ); glVertex3f( a, b, c ); glVertex3f( a, b, c+zrule ); glVertex3f( x, b, c ); glVertex3f( x-xrule, b, c ); glVertex3f( x, b, c ); glVertex3f( x, b+yrule, c ); glVertex3f( x, b, c ); glVertex3f( x, b, c+zrule ); glVertex3f( a, b, z ); glVertex3f( a+xrule, b, z ); glVertex3f( a, b, z ); glVertex3f( a, b+yrule, z ); glVertex3f( a, b, z ); glVertex3f( a, b, z-zrule ); glVertex3f( x, b, z ); glVertex3f( x-xrule, b, z ); glVertex3f( x, b, z ); glVertex3f( x, b+yrule, z ); glVertex3f( x, b, z ); glVertex3f( x, b, z-zrule ); glEnd(); } float min[3] = { a < x ? a : x, b < y ? b : y , c < z ? c : z }; float max[3] = { a < x ? x : a, b < y ? y : b , c < z ? z : c }; for ( int i = 0 ; i < 3 ; i++ ) { float diff = ( max[i] - min[i] ) / 10.0; max[i] += diff; min[i] -= diff; } if ( function->get_status() && preview->value() ) ImplicitSurface Preview( app_ref, IsoSurfaceTestFunc, this, min, max ); glPopMatrix(); list.end(); } } //*********************************************** // Edit //*********************************************** void IsoSurface::edit_widget( GtkWidget *wid ) { PREF_DEF bool tt = pref->tooltips->value(); // Options communes Object3D::edit_widget( wid ); // Options de geometrie new_table( edit_cont, _("Bounding Box"), 3 ); corner1->get_widget( table, tt, 1 ); corner2->get_widget( table, tt, 2 ); show_bb->get_widget( table, tt, 3 ); new_table( edit_cont, _("General settings"), 7 ); preview->get_widget( table, tt, 1 ); threshold->get_widget( table, tt, 2 ); function->get_widget( table, tt, 3 ); open->get_widget( table, tt, 4 ); accuracy->get_widget( table, tt, 5 ); max_gradient->get_widget( table, tt, 6 ); all_intersections ->get_widget( table, tt, 7 ); new_table( edit_cont, _("Transformation"), 3 ); location->get_widget( table, tt, 1 ); size->get_widget( table, tt, 2 ); rotation->get_widget( table, tt, 3 ); get_texture_widgets( edit_cont, tt ); gtk_widget_show_all( wid ); } //*********************************************** // Mouse drag //*********************************************** void IsoSurface::mouse_drag( struct drag_info *drag ) { VMAN_DEF OBJLIST_DEF switch( vmanager->get_pointer_mode() ) { case TV_PMODE_SELECT: case TV_PMODE_TRANSLATE: location->mouse_drag( drag ); break; case TV_PMODE_SCALE: { size->mouse_drag( drag ); } break; case TV_PMODE_ROTATE: { rotation->mouse_drag( drag ); break; } case TV_PMODE_CUSTOM: ((ObjParam_point*)(objlist->get_current_param()))->mouse_drag( drag ); break; default: break; } } //*********************************************** // Pref_changed //*********************************************** void IsoSurface::pref_changed() { Object3D::pref_changed(); location->pref_changed(); size->pref_changed(); rotation->pref_changed(); corner1->pref_changed(); corner2->pref_changed(); show_bb->pref_changed(); threshold->pref_changed(); function->pref_changed(); preview->pref_changed(); open->pref_changed(); accuracy->pref_changed(); max_gradient->pref_changed(); all_intersections->pref_changed(); } //*********************************************** // Destroy editor //*********************************************** void IsoSurface::destroy_editor() { Object3D::destroy_editor(); location->clear_widget(); size->clear_widget(); texture->clear_widget(); rotation->clear_widget(); corner1->clear_widget(); corner2->clear_widget(); show_bb->clear_widget(); threshold->clear_widget(); function->clear_widget(); preview->clear_widget(); open->clear_widget(); accuracy->clear_widget(); max_gradient->clear_widget(); all_intersections->clear_widget(); } //*********************************************** // Output to povray //*********************************************** void IsoSurface::output_to_povray_pass1( ofstream & file ) { if ( function->value() == NULL ) return; file << "\n\n// Isosurface : " << name->value(); function->define_internals( file ); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nisosurface {"; file << "\n\tfunction{ "; file << function->value() << " }"; file << "\n\tcontained_by{ box{ "; float a, b, c, x, y, z; corner1->get( a, b, c ); corner2->get( x, y, z ); file << '<' << a << ',' << b << ',' << -c << ">,\n\t<" << x << ',' << y << ',' << -z << "> } }\n\t"; file << "\n\tthreshold " << threshold->value(); file << "\n\taccuracy " << accuracy->value(); if ( open->value() ) file << "\n\topen"; file << "\n\tmax_gradient " << max_gradient->value(); if ( all_intersections->value() ) file << "\n\tall_intersections"; Object3D_with_material::output_to_povray_pass1( file ); file << "\t"; rotation->output_to_povray( file ); size->get( x, y, z ); file << "\n\tscale <" << x << ',' << y << ',' << z << ">"; location->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << ">"; file << "\n} "; } //*********************************************** // Save & load //*********************************************** void IsoSurface::save( ofstream & file ) { file << "\nISOSURFACE{\n"; save_basics( file ); corner1->save( file ); corner2->save( file ); show_bb->save( file ); threshold->save( file ); function->save( file ); preview->save( file ); open->save( file ); accuracy->save( file ); max_gradient->save( file ); all_intersections->save( file ); location->save( file ); size->save( file ); rotation->save( file ); texture->save( file ); file << "\n}"; } bool IsoSurface::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "ISOSURFACE" ) ) return false; set_load_progress( file ); char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( location->load( file, tag ) ) continue; if ( size->load( file, tag ) ) continue; if ( rotation->load( file, tag ) ) continue; if ( corner1->load( file, tag ) ) continue; if ( corner2->load( file, tag ) ) continue; if ( show_bb->load( file, tag ) ) continue; if ( threshold->load( file, tag ) ) continue; if ( function->load( file, tag ) ) continue; if ( preview->load( file, tag ) ) continue; if ( open->load( file, tag ) ) continue; if ( accuracy->load( file, tag ) ) continue; if ( max_gradient->load( file, tag ) ) continue; if ( all_intersections->load( file, tag ) ) continue; tvio_skip_section(file ); } while ( tag != NULL ); return true; } bool IsoSurface::is_inside( float x, float y, float z ) { if ( ! open->value() ) { float x1, y1, z1, a, b, c; corner1->get( a, b, c ); corner2->get( x1, y1, z1 ); float min[3] = { a < x1 ? a : x1, b < y1 ? b : y1 , c < z1 ? c : z1 }; float max[3] = { a < x1 ? x1 : a, b < y1 ? y1 : b , c < z1 ? z1 : c }; if ( x >= max[0] || x <= min[0] ) return FALSE; if ( y >= max[1] || y <= min[1] ) return FALSE; if ( z >= max[2] || z <= min[2] ) return FALSE; } float value = function->evaluate( x, y, z ); if ( value < threshold->value() ) return TRUE; return FALSE; }