//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // slopemap.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/slopemap.h" #include "include/dlgutils.h" #include "include/interface.h" #include "include/preferences.h" #include "include/tvio.h" GdkGC *TvWidget_slopemap::grid_style = NULL; const float MAX_SLOPE = 6.0; //********************************************************* // Slope map point //********************************************************* slmap_point::slmap_point() { position = height = 0; slope_up = slope_down = 0; } slmap_point::slmap_point( slmap_point & ref ) { position = ref.position; height = ref.height; slope_up = ref.slope_up; slope_down = ref.slope_down; } void slmap_point::output_to_povray( ofstream & file ) { file << "\n\t\t[ " << position << "\t< " << height << ", " << slope_down << " > ]"; file << "\n\t\t[ " << position << "\t< " << height << ", " << slope_up << " > ]"; } void slmap_point::save( ofstream & file ) { file << " PT{ P=" << position << " H=" << height << " U=" << slope_up << " D=" << slope_down << "}"; } void slmap_point::load( ifstream & file ) { char * val = NULL; do { val = tvio_get_next_val( file ); if ( val == NULL ) return; if ( ! strcmp( val, "P" ) ) { position = tvio_get_value_as_float( file ); continue; } if ( ! strcmp( val, "H" ) ) { height = tvio_get_value_as_float( file ); continue; } if ( ! strcmp( val, "U" ) ) { slope_up = tvio_get_value_as_float( file ); continue; } if ( ! strcmp( val, "D" ) ) { slope_down = tvio_get_value_as_float( file ); continue; } } while ( val != NULL ); } //********************************************************** // Slopemap //********************************************************** // Constructor TvWidget_slopemap::TvWidget_slopemap( const char *name, const char *sname, const char *tooltip, app_objs *appref ) : TvWidget( name, sname, tooltip, appref ) { use = new TvWidget_bool_activator( N_("Use slopemap"), "USED", NULL, app_ref, false ); editor = NULL; pix_buffer = NULL; update = false; edited = 0; slmap_point *pt = new slmap_point(); pt->set( 0, 0.5 ); Points.push_back( pt ); pt = new slmap_point(); pt->set( 0.25, 0.5 ); pt->slope_up = 2; pt->slope_down = -1; Points.push_back( pt ); pt = new slmap_point(); pt->set( 0.75, 0.5 ); pt->slope_up = 1; pt->slope_down = -1; Points.push_back( pt ); pt = new slmap_point(); pt->set( 1, 0.5 ); Points.push_back( pt ); } // Copy Constructor TvWidget_slopemap::TvWidget_slopemap( TvWidget_slopemap & ref ) : TvWidget( ref ) { editor = NULL; pix_buffer = NULL; update = false; use = new TvWidget_bool_activator( *ref.use ); for ( unsigned int i = 0 ; i < ref.Points.size() ; i++ ) { slmap_point *pt = new slmap_point( *ref.Points[i] ); Points.push_back( pt ); } } // Destructor TvWidget_slopemap::~TvWidget_slopemap() { delete use; for ( unsigned int i = 0 ; i < Points.size() ; i++ ) delete Points[i]; if ( pix_buffer != NULL ) gdk_pixmap_unref( pix_buffer ); } // Get widget void TvWidget_slopemap::get_widget_wnframe( GtkWidget *box, bool tt, bool frame ) { if ( frame ) widget = dlg_simple_box_frame( _(name), box ); else { widget = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(box), widget, FALSE, TRUE, 2 ); } use->get_widget_no_toggle( widget, tt ); activated_box = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(widget), activated_box, FALSE, FALSE, 0 ); use->set_target( activated_box ); GtkWidget *button = gtk_button_new_with_label( _("Edit") ); gtk_box_pack_start( GTK_BOX(activated_box), button, FALSE, FALSE, 0 ); gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_slopemap_edit), this ); use->update_widget(); } void TvWidget_slopemap::clear_widget() { widget = NULL; use->clear_widget(); } void TvWidget_slopemap::flush() { if ( widget == NULL ) return; use->flush(); } void TvWidget_slopemap::pref_changed() { PREF_DEF bool tt = pref->tooltips->value(); if ( editor != NULL ) { for ( int i = 0 ; i < MAX_SLMAP_BUT ; i ++ ) if ( tt ) gtk_tooltips_enable( slmap_butt_tt_wid[i] ); else gtk_tooltips_disable( slmap_butt_tt_wid[i] ); } } //********************************* // Editor //********************************* const char *slmap_buttons[MAX_SLMAP_BUT] = { GNOME_STOCK_PIXMAP_NEW, GNOME_STOCK_PIXMAP_CLOSE, GNOME_STOCK_PIXMAP_BACK, GNOME_STOCK_PIXMAP_FORWARD }; const char *slmap_tooltips[MAX_SLMAP_BUT] = { N_("Add control point"), N_("Delete current point"), N_("Previous point"), N_("Next point") }; void TvWidget_slopemap::open_editor() { if ( GTK_IS_DIALOG(editor) ) { gdk_window_raise( editor->window ); return; } editor = gtk_dialog_new_with_buttons( _("Slope map editor"), NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL ); g_signal_connect( G_OBJECT(editor), "response", G_CALLBACK(sign_slopemap_editor_click), this ); g_signal_connect( G_OBJECT(editor), "close", G_CALLBACK(sign_slopemap_editor_destroy), this ); gtk_widget_realize( editor ); GtkWidget *hbox = gtk_hbox_new( FALSE, 2 ); gtk_box_pack_start( GTK_BOX(GTK_DIALOG(editor)->vbox), hbox, FALSE, TRUE, 5 ); // Curve editor curve = gtk_drawing_area_new(); if ( grid_style == NULL ) { grid_style = gdk_gc_new( editor->window ); GdkColor col; col.red = col.green = col.blue = 40000; gdk_colormap_alloc_color( gtk_widget_get_colormap( curve ), &col, FALSE, TRUE ); gdk_gc_set_foreground( grid_style, &col ); gdk_gc_set_line_attributes( grid_style, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_BUTT, GDK_JOIN_MITER ); } gtk_widget_set_events( curve, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK ); gtk_signal_connect( GTK_OBJECT(curve), "realize", GTK_SIGNAL_FUNC(sign_slopecurve_realize), this ); gtk_signal_connect( GTK_OBJECT(curve), "expose_event", GTK_SIGNAL_FUNC(sign_slopecurve_expose), this ); gtk_signal_connect( GTK_OBJECT(curve), "configure_event", GTK_SIGNAL_FUNC(sign_slopecurve_configure), this ); gtk_signal_connect( GTK_OBJECT(curve), "button_press_event", GTK_SIGNAL_FUNC(sign_slopecurve_mouse_click), this ); gtk_signal_connect( GTK_OBJECT(curve), "button_release_event", GTK_SIGNAL_FUNC(sign_slopecurve_mouse_release), this ); gtk_signal_connect( GTK_OBJECT(curve), "motion_notify_event", GTK_SIGNAL_FUNC(sign_slopecurve_mouse_moved), this ); gtk_widget_set_usize( curve, 550, 370 ); gtk_box_pack_start( GTK_BOX(hbox), curve, TRUE, TRUE, 0 ); // Values Editors GtkWidget *valframe = gtk_frame_new( NULL ); gtk_box_pack_start( GTK_BOX(hbox), valframe, TRUE, TRUE, 0 ); GtkWidget *vbox = gtk_vbox_new( FALSE, 5 ); gtk_container_set_border_width( GTK_CONTAINER(vbox), 6 ); gtk_widget_set_usize( vbox, 180, -1 ); gtk_container_add( GTK_CONTAINER(valframe), vbox ); GtkWidget *frame = gtk_frame_new( NULL ); gtk_box_pack_start( GTK_BOX(vbox), frame, FALSE, TRUE, 2 ); GtkWidget *label = gtk_label_new( N_("Point editor") ); gtk_container_add( GTK_CONTAINER(frame), label ); // Point number label GtkWidget *valbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(vbox), valbox, FALSE, TRUE, 10 ); label = gtk_label_new( N_("Point n° : ") ); gtk_box_pack_start( GTK_BOX(valbox), label, FALSE, TRUE, 0 ); point_label = gtk_label_new( N_("0") ); gtk_box_pack_start( GTK_BOX(valbox), point_label, TRUE, TRUE, 5 ); // Position valbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(vbox), valbox, FALSE, TRUE, 4 ); label = gtk_label_new( N_("Position") ); gtk_box_pack_start( GTK_BOX(valbox), label, FALSE, TRUE, 0 ); posadj = gtk_adjustment_new( 0, 0, 1, 0.1, 0.2, 0 ); position = gtk_spin_button_new( GTK_ADJUSTMENT(posadj), 0, 4 ); gtk_box_pack_start( GTK_BOX(valbox), position, TRUE, TRUE, 5 ); gtk_signal_connect( GTK_OBJECT(posadj), "value-changed", GTK_SIGNAL_FUNC(sign_slmap_value_changed), this ); // Height valbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(vbox), valbox, FALSE, TRUE, 4 ); label = gtk_label_new( N_("Height") ); gtk_box_pack_start( GTK_BOX(valbox), label, FALSE, TRUE, 0 ); GtkObject *adj = gtk_adjustment_new( 0, 0, 1, 0.1, 0.2, 0 ); height = gtk_spin_button_new( GTK_ADJUSTMENT(adj), 0, 4 ); gtk_box_pack_start( GTK_BOX(valbox), height, TRUE, TRUE, 5 ); gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(sign_slmap_value_changed), this ); // Slope up valbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(vbox), valbox, FALSE, TRUE, 4 ); label = gtk_label_new( N_("Slope right") ); gtk_box_pack_start( GTK_BOX(valbox), label, FALSE, TRUE, 0 ); adj = gtk_adjustment_new( 0, - MAX_SLOPE, MAX_SLOPE, 0.1, 0.2, 0 ); slopeup = gtk_spin_button_new( GTK_ADJUSTMENT(adj), 0, 4 ); gtk_box_pack_start( GTK_BOX(valbox), slopeup, TRUE, TRUE, 5 ); gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(sign_slmap_value_changed), this ); // Slope down valbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(vbox), valbox, FALSE, TRUE, 4 ); label = gtk_label_new( N_("Slope left") ); gtk_box_pack_start( GTK_BOX(valbox), label, FALSE, TRUE, 0 ); adj = gtk_adjustment_new( 0, -MAX_SLOPE, MAX_SLOPE, 0.1, 0.2, 0 ); slopedown = gtk_spin_button_new( GTK_ADJUSTMENT(adj), 0, 4 ); gtk_box_pack_start( GTK_BOX(valbox), slopedown, TRUE, TRUE, 5 ); gtk_signal_connect( GTK_OBJECT(adj), "value-changed", GTK_SIGNAL_FUNC(sign_slmap_value_changed), this ); // Bouttons de manipulation des objets GtkWidget *bbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_end( GTK_BOX(vbox), bbox, FALSE, TRUE, 2 ); //INTERF_DEF PREF_DEF //GtkWidget *win = interf->get_gtkwin(); GtkWidget *pix; for ( int i = 0 ; i < MAX_SLMAP_BUT ; i ++ ) { slmap_butt_wid[i] = gtk_button_new(); gtk_box_pack_start( GTK_BOX(bbox), slmap_butt_wid[i], TRUE, FALSE, 0 ); gtk_signal_connect( GTK_OBJECT(slmap_butt_wid[i]), "clicked", GTK_SIGNAL_FUNC(sign_slmap_button_clicked), this ); pix = gtk_image_new_from_stock( slmap_buttons[i], GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER(slmap_butt_wid[i]), pix ); slmap_butt_tt_wid[i] = gtk_tooltips_new(); gtk_tooltips_set_tip( slmap_butt_tt_wid[i], slmap_butt_wid[i], _(slmap_tooltips[i]), NULL ); if ( !pref->tooltips->value() ) gtk_tooltips_disable( slmap_butt_tt_wid[i] ); } set_edited( edited ); gtk_widget_show_all(editor); } void TvWidget_slopemap::close_editor() { if ( editor == NULL ) return; if ( GTK_IS_DIALOG(editor) ) gtk_widget_destroy( editor ); editor = NULL; if ( pix_buffer != NULL ) gdk_pixmap_unref( pix_buffer ); pix_buffer = NULL; } void TvWidget_slopemap::editor_clicked( int button ) { close_editor(); } // Points manipulation void TvWidget_slopemap::button_clicked( GtkWidget *wid ) { int button = 0; for ( register int i = 0 ; i < MAX_SLMAP_BUT ; i++ ) if ( wid == slmap_butt_wid[i] ) { button = i; break; } switch ( button ) { // New point case 0: { if ( edited == (int)Points.size() - 1 ) return; vector::iterator it = Points.begin() + edited + 1; slmap_point *pt = new slmap_point(); float pos = ( Points[edited]->position + Points[edited+1]->position ) / 2.0; float hei = ( Points[edited]->height + Points[edited+1]->height ) / 2.0; pt->set( pos, hei ); pt->slope_down =( Points[edited]->slope_up + Points[edited+1]->slope_down ) / 2.0; pt->slope_up = - pt->slope_down; Points.insert( it, pt ); set_edited( edited+1); } break; // Delete point case 1: { if ( edited == 0 ) return; if ( edited == (int)Points.size() - 1 ) return; vector::iterator it = Points.begin() + edited; slmap_point *target = Points[edited]; Points.erase( it ); delete target; set_edited( edited - 1 ); } break; // Previous point case 2: set_edited( edited -1 ); break; // Next point case 3: set_edited( edited + 1 ); break; } } //****************************** // Set edited point //****************************** void TvWidget_slopemap::set_edited( int num ) { if ( num < 0 ) return; if ( num > (int)Points.size() - 1 ) return; update = true; edited = num; char str[10]; sprintf( str, "%u", edited ); gtk_label_set_text( GTK_LABEL(point_label), str ); gtk_spin_button_set_value( GTK_SPIN_BUTTON(position), Points[edited]->position ); GTK_ADJUSTMENT(posadj)->upper = ( edited == (int)Points.size() - 1 ) ? 1.0 : Points[edited+1]->position; GTK_ADJUSTMENT(posadj)->lower = ( edited == 0 ) ? 0.0 : Points[edited-1]->position; gtk_spin_button_set_value( GTK_SPIN_BUTTON(position), Points[edited]->position ); gtk_spin_button_set_value( GTK_SPIN_BUTTON(height), Points[edited]->height ); gtk_spin_button_set_value( GTK_SPIN_BUTTON(slopeup), Points[edited]->slope_up ); gtk_spin_button_set_value( GTK_SPIN_BUTTON(slopedown), Points[edited]->slope_down ); redraw_curve(); update = false; } //********************************* // Value changed //********************************* void TvWidget_slopemap::value_changed() { if ( update ) return; Points[edited]->position = gtk_spin_button_get_value_as_float( GTK_SPIN_BUTTON(position) ); Points[edited]->height = gtk_spin_button_get_value_as_float( GTK_SPIN_BUTTON(height) ); Points[edited]->slope_up = gtk_spin_button_get_value_as_float( GTK_SPIN_BUTTON(slopeup) ); Points[edited]->slope_down = gtk_spin_button_get_value_as_float( GTK_SPIN_BUTTON(slopedown) ); redraw_curve(); } //********************************* // Resdraw curve //********************************* void TvWidget_slopemap::redraw_curve() { GdkRectangle rect; rect.x = 0; rect.y = 0; rect.width = curve->allocation.width; rect.height = curve->allocation.height; gtk_widget_draw( curve, &rect ); } //****************************** // Expose //****************************** const int margin = 40; const int step = 10; const int point_size = 3; const double slope_lon = 70; void TvWidget_slopemap::expose( GdkEventExpose *ev ) { // Geometry int x = ev->area.x; int y = ev->area.y; int width = curve->allocation.width; //ev->area.width; int height = curve->allocation.height; //ev->area.height; int area_width = width - margin*2; int area_height = height - margin * 2; int left = x + margin; int right = width - margin; int top = y + margin; int bottom = height - margin; // Double buffer if ( pix_buffer == NULL ) pix_buffer = gdk_pixmap_new( curve->window, width, height, -1 ); // Clean & draw basics gdk_draw_rectangle( pix_buffer, curve->style->bg_gc[curve->state], TRUE, x, y, width, height ); gdk_draw_rectangle( pix_buffer, curve->style->fg_gc[curve->state], FALSE, left, top, right - margin, bottom - margin ); // Labels gdk_draw_text( pix_buffer, gtk_style_get_font(curve->style), curve->style->fg_gc[curve->state], left - 10, y + margin, "1", 1 ); gdk_draw_text( pix_buffer, gtk_style_get_font(curve->style), curve->style->fg_gc[curve->state], x + width - margin, y + height - margin + 15, "1", 1 ); gdk_draw_text( pix_buffer, gtk_style_get_font(curve->style), curve->style->fg_gc[curve->state], left, y + height - margin + 15, "0", 1 ); gdk_draw_text( pix_buffer, gtk_style_get_font(curve->style), curve->style->fg_gc[curve->state], left - 10, y + height - margin, "0", 1 ); // Grids int xinc = area_width / step; int yinc = area_height / step; for ( register int i = 1 ; i < step ; i++ ) { int xpos = left + xinc * i; int ypos = top + yinc *i; gdk_draw_line( pix_buffer, grid_style, xpos, top, xpos , bottom ); gdk_draw_line( pix_buffer, grid_style, left, ypos, right , ypos ); } // Points int size = point_size*2; for ( unsigned int i = 0 ; i < Points.size() ; i ++ ) { int xpos = left + (int)((float)area_width * Points[i]->position); int ypos = top + (int)((float)area_height * ( 1.0 - Points[i]->height )); gdk_draw_rectangle( pix_buffer, curve->style->fg_gc[curve->state], TRUE, xpos-point_size, ypos-point_size, size, size ); if ( i == (unsigned int)edited ) { double slopeu = atan( Points[i]->slope_up ); double sloped = atan( Points[i]->slope_down ); if ( edited != (int)Points.size() - 1 ) { gdk_draw_rectangle( pix_buffer, curve->style->fg_gc[curve->state], FALSE, xpos - point_size + (int)(slope_lon*cos( slopeu ) ), ypos - point_size + (int)( slope_lon * sin( slopeu ) ), size, size ); gdk_draw_line( pix_buffer, curve->style->fg_gc[curve->state], xpos, ypos, xpos + (int)(slope_lon * cos( slopeu )), ypos + (int)(slope_lon * sin( slopeu )) ); } if ( edited != 0 ) { gdk_draw_line( pix_buffer, curve->style->fg_gc[curve->state], xpos, ypos, xpos - (int)(slope_lon * cos( sloped )), ypos + (int)(slope_lon * sin( sloped )) ); gdk_draw_rectangle( pix_buffer, curve->style->fg_gc[curve->state], FALSE, xpos - point_size - (int)( slope_lon * cos( sloped) ), ypos - point_size + (int)( slope_lon * sin( sloped)), size, size ); } } // Bezier curves if ( i == Points.size() -1 ) break; int xpos2 = left + (int)((float)area_width * Points[i+1]->position); int ypos2 = top + (int)((float)area_height * ( 1.0 - Points[i+1]->height )); int segment = xpos2 - xpos; int xslope1= xpos + segment/2; int yslope1= ypos + (int)((float)(segment/2)*Points[i]->slope_up); int xslope2= xpos2- segment/2; int yslope2= ypos2 + (int)((float)(segment/2)*Points[i+1]->slope_down); int old_xcurve = xpos; int old_ycurve = ypos; for ( register int i = 0 ; i < segment ; i++ ) { float t = (float)i / segment; int abx = xpos + (int)((float)( xslope1 - xpos ) * t); int aby = ypos + (int)((float)( yslope1 - ypos ) * t); int bcx = xslope1 + (int)((float)( xslope2 - xslope1 ) * t); int bcy = yslope1 + (int)((float)( yslope2 - yslope1 ) * t); int cdx = xslope2 + (int)((float)( xpos2 - xslope2 ) * t); int cdy = yslope2 + (int)((float)( ypos2 - yslope2 ) * t); int abbcx = abx + (int)((float)( bcx - abx ) * t); int abbcy = aby + (int)((float)( bcy - aby ) * t); int bccdx = bcx + (int)((float)( cdx - bcx ) * t); int bccdy = bcy + (int)((float)( cdy - bcy ) * t); int xcurve = abbcx + (int)((float)( bccdx - abbcx ) * t); int ycurve = abbcy + (int)((float)( bccdy - abbcy ) * t); gdk_draw_line( pix_buffer, curve->style->fg_gc[curve->state], old_xcurve, old_ycurve, xcurve, ycurve ); old_xcurve = xcurve; old_ycurve = ycurve; } gdk_draw_line( pix_buffer, curve->style->fg_gc[curve->state], old_xcurve, old_ycurve, xpos2, ypos2 ); } gdk_gc_set_clip_rectangle( curve->style->fg_gc[curve->state], &ev->area ); gdk_draw_pixmap( curve->window, curve->style->fg_gc[curve->state], pix_buffer, ev->area.x, ev->area.y, ev->area.x, ev->area.y, ev->area.width, ev->area.height ); gdk_gc_set_clip_rectangle( curve->style->fg_gc[curve->state], NULL ); } void TvWidget_slopemap::configure() {} void TvWidget_slopemap::realize() {} //************************************** // Mouse //************************************** void TvWidget_slopemap::mouse_moved( GdkEventMotion *ev ) { int xpos, ypos; GdkModifierType state; if ( ev->is_hint ) gdk_window_get_pointer( ev->window, &xpos, &ypos, &state ); else { xpos = (int)ev->x; ypos = (int)ev->y; state = (GdkModifierType)ev->state; } int width = curve->allocation.width; //ev->area.width; int height = curve->allocation.height; //ev->area.height; int area_width = width - margin*2; int area_height = height - margin * 2; int left = margin; //int right = width - margin; int top = margin; //int bottom = height - margin; switch ( drag_type ) { default: case -1: return; break; // Move case 1: { float position = (float)( xpos - left ) / (float)area_width; if ( edited == 0 ) position = 0; else if ( position < Points[edited-1]->position ) position = Points[edited-1]->position; if ( edited == (int)Points.size() - 1 ) position = 1.0; else if ( position > Points[edited+1]->position ) position = Points[edited+1]->position; float height = 1.0 - (float)( ypos - top ) / (float)area_height; if ( height < 0.0 ) height = 0.0; if ( height > 1.0 ) height = 1.0; Points[edited]->set( position, height ); set_edited( edited ); } break; // Edit slope up case 2: { int xori = left + (int)((float)area_width * Points[edited]->position); int yori = top + (int)((float)area_height * ( 1.0 - Points[edited]->height )); float xslope = xpos - xori; if ( xslope < 0 ) break; float yslope = ypos - yori; Points[edited]->slope_up = yslope / xslope; if ( Points[edited]->slope_up > MAX_SLOPE ) Points[edited]->slope_up = MAX_SLOPE; if ( Points[edited]->slope_up < - MAX_SLOPE ) Points[edited]->slope_up = - MAX_SLOPE; set_edited( edited ); } break; // Edit slope down case 3: { int xori = left + (int)((float)area_width * Points[edited]->position); int yori = top + (int)((float)area_height * ( 1.0 - Points[edited]->height )); float xslope = - xpos + xori; if ( xslope < 0 ) break; float yslope = ypos - yori; Points[edited]->slope_down = yslope / xslope; if ( Points[edited]->slope_down > MAX_SLOPE ) Points[edited]->slope_down = MAX_SLOPE; if ( Points[edited]->slope_down < - MAX_SLOPE ) Points[edited]->slope_down = - MAX_SLOPE; set_edited( edited ); } break; } } // Click void TvWidget_slopemap::mouse_click( GdkEventButton *ev ) { drag_type = -1; if ( ev->button != 1 ) return; GdkModifierType state; int drag_x, drag_y; gdk_window_get_pointer( ev->window, &drag_x, &drag_y, &state ); int width = curve->allocation.width; //ev->area.width; int height = curve->allocation.height; //ev->area.height; int area_width = width - margin*2; int area_height = height - margin * 2; int left = margin; //int right = width - margin; int top = margin; //int bottom = height - margin; // Position test ( for selection + move ) for ( unsigned int i = 0 ; i < Points.size() ; i++ ) { int xpos = left + (int)((float)area_width * Points[i]->position); if ( drag_x > xpos + point_size ) continue; if ( drag_x < xpos - point_size ) continue; int ypos = top + (int)((float)area_height * ( 1.0 - Points[i]->height )); if ( drag_y > ypos + point_size ) continue; if ( drag_y < ypos - point_size ) continue; drag_type = 1; set_edited( i ); return; } // Slope cursor position test double slopeu = atan( Points[edited]->slope_up ); double sloped = atan( Points[edited]->slope_down ); if ( edited != (int)Points.size() - 1 ) { bool test = true; int xpos = left + (int)((float)area_width * Points[edited]->position) + (int)(slope_lon * cos( slopeu )); if ( drag_x > xpos + point_size ) test = false; if ( drag_x < xpos - point_size ) test = false; int ypos = top + (int)((float)area_height * ( 1.0 - Points[edited]->height )) + (int)(slope_lon * sin( slopeu )); if ( drag_y > ypos + point_size ) test = false; if ( drag_y < ypos - point_size ) test = false; if ( test ) { drag_type = 2; return; } } if ( edited != 0 ) { bool test = true; int xpos = left + (int)((float)area_width * Points[edited]->position) - (int)(slope_lon * cos( sloped )); if ( drag_x > xpos + point_size ) test = false; if ( drag_x < xpos - point_size ) test = false; int ypos = top + (int)((float)area_height * ( 1.0 - Points[edited]->height )) + (int)(slope_lon * sin( sloped )); if ( drag_y > ypos + point_size ) test = false; if ( drag_y < ypos - point_size ) test = false; if ( test ) { drag_type = 3; return; } } // Else create a new point float pos = (float)( drag_x - left ) / (float)area_width; float hei = 1.0 - (float)( drag_y - top ) / (float)area_height; if ( hei < 0.0 ) hei = 0.0; if ( hei > 1.0 ) hei = 1.0; slmap_point *pt = new slmap_point(); pt->set( pos, hei ); unsigned int i = 0; for ( i = 0 ; i < Points.size() ; i++ ) if ( Points[i]->position > pos ) break; vector::iterator it = Points.begin() + i; Points.insert( it, pt ); set_edited(i); drag_type = 1; } void TvWidget_slopemap::mouse_release() { drag_type = -1; } //******************* // output to povray //******************* void TvWidget_slopemap::output_to_povray( ofstream & file ) { if ( use->value() == false ) return; file << "\n\tslope_map {"; for ( unsigned int i = 0 ; i < Points.size() ; i++ ) Points[i]->output_to_povray( file ); file << "\n\t}"; } //******************* // Save //******************* void TvWidget_slopemap::save( ofstream & file ) { TvWidget::save( file ); use->save( file ); for ( unsigned int i = 0 ; i < Points.size() ; i ++ ) Points[i]->save( file ); file << "} "; } bool TvWidget_slopemap::load( ifstream & file, char * ltag ) { if ( strcmp( sname, ltag ) ) return false; for ( unsigned int i = 0 ; i < Points.size() ; i ++ ) delete Points[i]; Points.clear(); edited = 0; char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) return true; if ( use->load( file, tag ) ) continue; if ( ! strcmp( tag, "PT" ) ) { slmap_point *pt = new slmap_point(); pt->load( file ); Points.push_back( pt ); continue; } tvio_skip_section( file ); } while( tag != NULL ); return true; } //************************************ // COPY //************************************ void TvWidget_slopemap::copy( TvWidget *smap ) { TvWidget_slopemap *slope = (TvWidget_slopemap*)smap; editor = NULL; pix_buffer = NULL; edited = slope->edited; use->copy( slope->use ); for ( unsigned int i = 0 ; i < Points.size() ; i++ ) delete Points[i]; Points.clear(); for ( unsigned int i = 0 ; i < slope->Points.size() ; i++ ) { slmap_point *pt = new slmap_point( *slope->Points[i] ); Points.push_back( pt ); } }