/*
* surf - visualizing algebraic curves and algebraic surfaces
* Copyright (C) 1996-1997 Friedrich-Alexander-Universitaet
* Erlangen-Nuernberg
* 1997-2000 Johannes Gutenberg-Universitaet Mainz
* Authors: Stephan Endrass, Hans Huelf, Ruediger Oertel,
* Kai Schneider, Ralf Schmitt, Johannes Beigel
*
* 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 <assert.h>
#include <stdio.h>
#include <errno.h>
#include <iostream.h>
#include <sys/stat.h>
#include <unistd.h>
#include "FileWriter.h"
#include "TreePolynom.h"
#include "Misc.h"
#include "Script.h"
#include "polylexyacc.h"
#include "gui_config.h"
#include "init_parser.h"
#include "DrawFunc.h"
#include "TSDrawingArea.h"
#include "SurfaceCalc.h"
#include "DrawCurve.h"
#include "SymbolTable.h"
#include "addDefaultSymbols.h"
#include "bit_buffer.h"
#include "float_buffer.h"
#include "dither.h"
#include "ps.h"
#include "eps.h"
#include "xbitmap.h"
#include "tiffprint.h"
#include "Thread.h"
#include "MultiVariatePolynom.h"
#include "RootFinder3d.h"
#include "GuiThread.h"
#include "SymbolTable.h"
#include "symtab.h"
// #define DEBUG
#include "debug.h"
TSDrawingArea *Script::display = 0;
RgbBuffer *Script::buffer = 0;
bit_buffer *Script::bitbuffer = 0;
float_buffer *Script::zbuffer = 0;
float_buffer *Script::zbuffer3d = 0;
SymbolTable *Script::defaultValues = 0;
Preview Script::preview;
Condition scriptRunning;
/* extern "C" */ void symtab_delete_element(symtab *);
static void replaceCommand (const char *name, void (*func) (void))
{
symtab *st = symtab_find_name (name);
if (st) {
DMESS("replacing command " << name);
symtab_delete_element(st);
} else {
DMESS("adding new command " << name);
}
symtab_add_surface_name (name, SYM_COMMAND, 1, (void*)func);
}
SymbolTable &Script::getDefaultValues()
{
if (defaultValues == 0) {
defaultValues = new SymbolTable();
addDefaultSymbols(*defaultValues);
}
return *defaultValues;
}
void *Script::startThread (void *data)
{
ExecuteScriptStruct *ess = (ExecuteScriptStruct *) data;
// int i;
// for (i=0; i<4; i++) {
// main_mosaic_choice_data[i] = ess->preview[i];
// }
preview = ess->preview;
beforeScriptExecution();
if (ess->firstPart) {
if (internalExecuteScript (ess->firstPart)!=0) {
Misc::alert ("internal error.");
}
}
assert(ess->secondPart);
ess->parse_result = internalExecuteScript (ess->secondPart, ess->executeUserScriptCommands);
ess->error_begin = error_begin_char;
ess->error_end = char_number;
ess->errorString = yyerrorstring;
if (ess->parse_result == 0) {
internalExecuteScript (ess->thirdPart);
}
scriptRunning.lock();
scriptRunning.value = 0;
scriptRunning.unlock();
if (ess->doneCallback) {
ess->doneCallback (ess);
}
return 0;
}
bool Script::isScriptRunning ()
{
if (!scriptRunning.tryLock()) {
return true;
} else if (scriptRunning.value != 0) {
scriptRunning.unlock();
return true;
} else {
scriptRunning.unlock();
return false;
}
}
bool Script::startScriptExecution(ExecuteScriptStruct *ess)
{
if (!scriptRunning.tryLock()) {
Misc::alert("another script is running.");
} else if (scriptRunning.value != 0) {
scriptRunning.unlock();
Misc::alert("another script is running.");
} else {
scriptRunning.value = 1;
scriptRunning.unlock();
setDisplay (ess->drawingArea);
ess->thread = new Thread();
ess->thread->start (startThread, ess);
return true;
}
return false;
}
TSDrawingArea *Script::getDisplay()
{
return display;
}
void Script::setDisplay (TSDrawingArea *_display)
{
display = _display;
}
void Script::beforeScriptExecution()
{
int i;
for( i=0; i<MAIN_SURFACE_AMOUNT_NUM; i++ ) {
main_formula_pxyz_data[i].n = 0;
}
ostrstream str;
str << getDefaultValues() << ends;
internalExecuteScript (str.str());
// symtab_set_default();
error_begin_char = 0;
char_number=0;
symtab_delete_user_names( );
*zbuffer = -10.0;
}
int Script::internalExecuteScript (const char *str, bool runCommands)
{
if (str==0)
return 0;
char *main_formula_data = 0;
surface_run_commands = runCommands;
int parse_result;
main_formula_data = (char *) str;
set_the_yyinput (main_formula_data, 1, 1 );
scan_labels( main_formula_data );
do {
if (Thread::shouldStop()) {
parse_result = 0;
break;
}
yyrestart( stdin );
goto_flag = FALSE;
parse_result = yyparse( );
if( goto_flag ) {
set_the_yyinput( &(main_formula_data[goto_label]), goto_label+1,goto_line );
}
} while ( goto_flag );
// if (parse_result) {
// Misc::alert("Syntax error in script");
// printf ("%20s\n", str+char_number);
// }
return parse_result;
}
char *Script::readFile (const char *name)
{
BEGIN("readFile");
struct stat buf;
if (stat(name, &buf) != 0) {
ostrstream ostr;
ostr << "Canīt stat file ī" << name << "ī" << " (" << strerror(errno) << ")" << ends;
Misc::alert (ostr);
return 0;
}
unsigned int size = buf.st_size;
FILE *f=fopen(name, "r");
if (f==0) {
ostrstream ostr;
ostr << "Canīt open file ī" << name << "ī" << " (" << strerror(errno) << ")";
Misc::alert (ostr);
return 0;
}
char *str = new char [size+1];
if (fread(str, 1, size, f) != size) {
ostrstream ostr;
ostr << "Could not read from file ī" << name << "ī" << " (" << strerror(errno) << ")";
Misc::alert(ostr);
delete str;
fclose(f);
return 0;
}
fclose(f);
str[size]=0;
if (strlen(str) < size) {
delete str;
ostrstream ostr;
ostr << "\"" << name << "\" contains binary data.";
Misc::alert(ostr);
return 0;
}
return str;
}
void Script::executeScriptFromFile (const char *name)
{
BEGIN("Script::executeScriptFromFile");
Thread::setDoing ("executing script...");
const char *str = readFile(name);
display=0;
beforeScriptExecution();
internalExecuteScript(str);
delete str;
}
void Script::init()
{
BEGIN("Script::init");
// addDefaultSymbols (getDefaultValues());
init_surface_main_commands();
init_surface_main_variables();
draw_func_init_parser();
addNewCommands();
buffer = new RgbBuffer (main_width_data, main_height_data);
bitbuffer = new bit_buffer();
bitbuffer->setSize (main_width_data, main_height_data);
zbuffer = new float_buffer (main_width_data, main_height_data);
*zbuffer = -10.0; // FIXME
}
void Script::deinit()
{
delete buffer;
delete bitbuffer;
delete zbuffer;
delete defaultValues;
symtab_delete_total();
}
void Script::addNewCommands()
{
replaceCommand("set_size", setSize);
replaceCommand("draw_surface", drawSurface);
replaceCommand("save_color_image", saveColorImage);
replaceCommand("clear_screen", clearScreen);
replaceCommand("save_dithered_image", saveDitheredImage);
replaceCommand("dither_surface", ditherSurface);
replaceCommand("cut_with_surface", cutWithSurface);
replaceCommand("resultant", computeResultant);
replaceCommand("dither_curve", ditherCurve);
replaceCommand("clear_pixmap", clearPixmap);
}
//
// --- Commands
//
void Script::setSize()
{
checkVariables();
BEGIN("Script::setSize");
if(buffer->getWidth() != main_width_data ||
buffer->getHeight() != main_height_data) {
buffer->Realloc(main_width_data, main_height_data);
if (display) {
display->setSize(main_width_data, main_height_data);
}
buffer->Realloc(main_width_data, main_height_data);
}
}
extern double Y_AXIS_LR_ROTATE;
void Script::drawSurface()
{
checkVariables();
setSize();
BEGIN("Script::drawSurface");
TRACE(main_width_data);
TRACE(main_height_data);
if (getDisplay()) {
getDisplay()->showColorAreaWindow();
getDisplay()->setSize (main_width_data, main_height_data);
}
Y_AXIS_LR_ROTATE = 0.0;
SurfaceCalc sc;
sc.setDisplay (getDisplay());
sc.setPreview (getPreview());
getBuffer()->clearTags();
*getZBuffer() = -10.0;
sc.surface_calculate(0, 0, main_width_data, main_height_data, *getBuffer());
if( display_numeric.stereo_eye ) {
// -----------------
// Draw a 3D image
// -----------------
RgbBuffer *intensity = getBuffer();
*Script::getZBuffer3d() = -10.0;
Y_AXIS_LR_ROTATE= 2*atan( display_numeric.stereo_eye/
(2*position_numeric.spectator_z) );
intensity->StereoLeft( );
int back =(int)( 0.299*((float)(color_background_data[RED]))
+0.587*((float)(color_background_data[GREEN]))
+0.114*((float)(color_background_data[BLUE])));
float distf = display_numeric.stereo_z*display_numeric.stereo_eye/
position_numeric.spectator_z;
int dist = (int)(distf*((float)
(min(main_width_data,main_height_data)))/20.0);
SurfaceCalc sc;
sc.setDisplay (getDisplay());
sc.setPreview (getPreview());
sc.surface_calculate(0, 0, main_width_data, main_height_data,*getBuffer());
intensity->StereoRight( display_numeric.stereo_red,display_numeric.stereo_green,
display_numeric.stereo_blue,dist,back );
if (GuiThread::haveGUI())
getDisplay()->drawRgbBuffer (*intensity);
}
}
void Script::saveColorImage ()
{
if (Thread::shouldStop())
return;
checkVariables();
BEGIN("Script::saveColorImage");
Thread::setDoing ("saving color image...");
if (!surface_filename_data) {
Misc::alert ("no filename given.");
}
// const char *name = surface_filename_data;
/* Fuck, fuck, fuck...why canīt I just have working exceptions with
* every every version of gcc I can think of (especially 2.7.x)...
* I got internal compiler errors when trying to use them.
* I could have just thrown an exception in FileWriter if the file couldnīt
* be opened. But now Iīve got to open the file too early...
*/
FileWriter fw (surface_filename_data);
FILE *f = fw.openFile();
if (f==0) {
Misc::alert ("Could not open file for writing...");
return;
}
if (color_output_data == color_output_xwd_data) {
if (colormap_output_data == colormap_output_true_color_data) {
buffer->write_as_xwd24 (fw.openFile());
} else if (colormap_output_data==colormap_output_optimized_data) {
buffer->write_as_xwd8_optimized (fw.openFile(), !display_color_dither_data, display_dither_value_data);
} else {
buffer->write_as_xwd8_netscape (fw.openFile());
}
} else if (color_output_data == color_output_sun_data) {
if (colormap_output_data == colormap_output_true_color_data) {
buffer->write_as_sun24 (fw.openFile());
} else if (colormap_output_data==colormap_output_optimized_data) {
buffer->write_as_sun8_optimized (fw.openFile(), !display_color_dither_data, display_dither_value_data);
} else {
buffer->write_as_sun8_netscape (fw.openFile());
}
} else if (color_output_data == color_output_ppm_data) {
buffer->write_as_ppm (fw.openFile());
} else if (color_output_data == color_output_jpeg_data) {
buffer->write_as_jpeg (fw.openFile());
}
}
void Script::clearScreen()
{
if (Thread::shouldStop())
return;
checkVariables();
// FIXME: clearing visible parts ???
RgbBuffer *intensity = getBuffer();
float_buffer *zbuffer = getZBuffer();
*intensity = (byte)(-print_background_data);
if (getDisplay()) {
getDisplay()->showColorAreaWindow();
getDisplay()->setSize(main_width_data, main_height_data);
getDisplay()->drawSquare(0,0, intensity->getWidth(),0,0,0);
getDisplay()->displayRectangle(0,0,intensity->getWidth(), intensity->getHeight());
GuiThread::executeCommands();
}
// main_newcolor_init ( );
intensity->NullInit_three( );
*zbuffer = (float)clip_numeric.clip_back;
}
// should there really be any difference between the two ????
void Script::clearPixmap()
{
if (Thread::shouldStop())
return;
checkVariables();
// FIXME: clearing visible parts ???
RgbBuffer *intensity = getBuffer();
float_buffer *zbuffer = getZBuffer();
*intensity = (byte)(-print_background_data);
if (getDisplay()) {
getDisplay()->showColorAreaWindow();
// getDisplay()->setSize(main_width_data, main_height_data);
getDisplay()->drawSquare(0, 0, intensity->getWidth(),0.0,0,0);
// getDisplay()->displayRectangle(0,0,intensity->getWidth(), intensity->getHeight());
// GuiThread::executeCommands();
}
// main_newcolor_init ( );
intensity->NullInit_three( );
intensity->clearTags();
*zbuffer = (float)clip_numeric.clip_back;
}
void Script::saveDitheredImage()
{
if (Thread::shouldStop())
return;
checkVariables();
BEGIN("Script::saveDitheredImage");
Thread::setDoing ("saving dithered image...");
bit_buffer *pixel = getBitBuffer();
char *name = surface_filename_data;
if (name == 0)
return;
FileWriter fw (name);
// see comments above in saveColorImage
FILE *f=fw.openFile();
if (f==0) {
Misc::alert ("Could not open file for writing...");
return;
}
switch( print_output_data ) {
case 0 :
psprint (*pixel, fw.openFile(),
print_resolution_array_data[print_resolution_data]);
break;
case 1 :
epsprint (*pixel, fw.openFile(),
print_resolution_array_data[print_resolution_data] );
break;
case 2 :
bitmapprint (*pixel, fw.openFile(), fw.getName());
break;
case 3 :
if (fw.isWritingToPipe()) {
Misc::alert ("Tiff images can only be written to a file.");
return;
}
tiffprint (*pixel, name,
print_resolution_array_data[print_resolution_data]);
break;
case 5:
pixel->write_as_pgm (fw.openFile());
break;
case 6:
pixel->write_as_pbm (fw.openFile());
break;
default :
Misc::alert ("dither_file_format out of range. no saving done.");
break;
}
}
void Script::ditherSurface()
{
if (Thread::shouldStop())
return;
checkVariables();
BEGIN("ditherSurface");
Thread::setDoing ("dithering surface...");
float_buffer fbuffer (main_width_data, main_height_data);
bit_buffer *pixel = getBitBuffer();
pixel->setSize (main_width_data, main_height_data);
// sk :copy gray_values from rgb_buffer to buffer(float_buffer)
copy_rgb_to_float(*getBuffer(), fbuffer, print_background_data);
if( print_enhance_data == 0) {
fbuffer.EnhanceEdges( print_alpha_data );
}
if( print_tone_data == 0) {
fbuffer.AdjustToneScale();
}
if( print_gamma_data != 1.0 && print_gamma_correction_data == 1) {
fbuffer.CorrectGamma( 1.0/print_gamma_data );
}
dither_pixel_radius_adjust (fbuffer, (float)print_p_radius_data/100.0);
if (print_dither_data == print_dither_floyd_steinberg_data) {
dither_floyd_steinberg (fbuffer, *pixel, print_random_weights_data, print_weight_data, print_serpentine_raster_data);
} else if (print_dither_data == print_dither_jarvis_judis_ninke_data) {
dither_jarvis_judis_ninke (fbuffer, *pixel, print_random_weights_data, print_weight_data, print_serpentine_raster_data);
} else if (print_dither_data == print_dither_stucki_data) {
dither_stucki (fbuffer, *pixel, print_random_weights_data, print_weight_data, print_serpentine_raster_data);
} else if (print_dither_data == print_dither_ordered_dither_data) {
dither_clustered (fbuffer, *pixel, print_pattern_size_data);
} else if (print_dither_data == print_dither_dispersed_dither_data) {
dither_dispersed (fbuffer, *pixel, print_pattern_size_data);
} else if (print_dither_data == print_dither_dot_diffusion_data) {
dither_dot_diffusion (fbuffer, *pixel, print_barons_data);
} else if (print_dither_data == print_dither_smooth_dot_diffusion_data) {
dither_smooth_dot_diffusion (fbuffer, *pixel, print_barons_data);
} else {
Misc::alert ("dithering_method out of range. no dithering done.");
}
if (getDisplay()) {
getDisplay()->showDitherAreaWindow();
getDisplay()->drawBitbuffer(*pixel);
}
}
void Script::ditherCurve()
{
int width = getBuffer()->getWidth();
int height = getBuffer()->getHeight();
std::cerr << width << ", " << height << "\n";
float_buffer buffer (width, height);
// copy gray_values from rgb_buffer to float_buffer
copy_rgb_to_float_curve(*getBuffer(), buffer);
dither_brute (buffer, *getBitBuffer());
if (getDisplay()) {
getDisplay()->showDitherAreaWindow();
getDisplay()->setSize(width, height);
getDisplay()->drawBitbuffer(*getBitBuffer());
}
}
void Script::checkVariables()
{
if (numeric_epsilon_data <= 0) {
ostrstream cerr;
cerr << "WARNING: epsilon = " << numeric_epsilon_data << " <= 0. Setting epsilon to 0.00001" << endl;
numeric_epsilon_data = 0.00001;
Misc::alert(cerr);
}
if (main_width_data <= 0) {
ostrstream cerr;
cerr << "WARNING: width = " << main_width_data << " <= 0. Setting width to 200" << endl;
main_width_data = 200;
Misc::alert(cerr);
}
if (main_height_data <= 0) {
ostrstream cerr;
cerr << "WARNING: height = " << main_height_data << " <= 0. Setting height to 200" << endl;
main_height_data = 200;
Misc::alert(cerr);
}
}
#include "resultant.h"
void Script::computeResultant()
{
SurfaceCalc sc;
Polyxyz p1 (sc.sf_ds.getFormula (curve_surface_nr_data)->pxyz);
CanvasDataStruct cds;
cds.initWith_polyxyz (&sym_cutsurfaces[0]);
Polyxyz p2 (cds.pxyz);
resultant(p1,p2);
return;
}
void Script::cutWithSurface()
{
setSize();
if (getDisplay()) {
getDisplay()->showColorAreaWindow();
getDisplay()->setSize (main_width_data, main_height_data);
}
WindowGeometry wingeo = WindowGeometry(main_width_data, main_height_data);
Y_AXIS_LR_ROTATE = 0.0;
checkVariables();
Script::getBuffer()->clearCurveTags( );
Polyx::SetStatics( numeric_epsilon_data, numeric_iterations_data,
numeric_root_finder_data, true );
Script::getZBuffer()->Realloc(main_width_data, main_height_data);
SurfaceCalc sc;
sc.setDisplay(Script::getDisplay());
Polyxyz p1 (sc.sf_ds.getFormula (curve_surface_nr_data)->pxyz);
CanvasDataStruct cds;
cds.initWith_polyxyz (&sym_cutsurfaces[0]);
Polyxyz p2 (cds.pxyz);
DrawCurve dc;
dc.setCurveWidthAndGamma (curve_width_data, curve_gamma_data);
NewClip *clip = NewClip::createSimpleClip (position_perspective_data, clip_data);
clip->init();
dc.setClip (clip);
dc.setGeometry (wingeo);
dc.setPolys (p1,p2);
for (int i=1; i<sizeof(sym_cutsurfaces)/sizeof(sym_cutsurfaces[0]); i++) {
if (sym_cutsurfaces[i].n > 0) {
CanvasDataStruct cds;
cds.initWith_polyxyz (&sym_cutsurfaces[i]);
Polyxyz p3 (cds.pxyz);
dc.setAdditionalPoly (p3);
}
}
dc.setBuffers (Script::getBuffer(), Script::getZBuffer());
dc.drawCurve(0,0,main_width_data, main_height_data, sym_cut_distance);
sc.CalculateCurveOnSurface(0,0,main_width_data,main_height_data,*Script::getBuffer(), *Script::getZBuffer() );
delete clip;
if( display_numeric.stereo_eye ) {
// -----------------
// Draw a 3D image
// -----------------
// Script::getBuffer()->clearTags( );
Script::getBuffer()->clearCurveTags( );
Y_AXIS_LR_ROTATE= 2*atan( display_numeric.stereo_eye/
(2*position_numeric.spectator_z) );
//int back =(int)( 0.299*((float)(color_background_data[RED]))
// +0.587*((float)(color_background_data[GREEN]))
// +0.114*((float)(color_background_data[BLUE])));
//float distf = display_numeric.stereo_z*display_numeric.stereo_eye/
// position_numeric.spectator_z;
//int dist = (int)(distf*((float)
// (min(main_width_data,main_height_data)))/20.0);
SurfaceCalc sc;
sc.setDisplay(Script::getDisplay());
Polyxyz p1 (sc.sf_ds.getFormula (curve_surface_nr_data)->pxyz);
CanvasDataStruct cds;
cds.initWith_polyxyz (&sym_cutsurfaces[0]);
Polyxyz p2 (cds.pxyz);
DrawCurve dc;
dc.setCurveWidthAndGamma (curve_width_data, curve_gamma_data);
NewClip *clip = NewClip::createSimpleClip (position_perspective_data, clip_data);
clip->init();
dc.setClip (clip);
dc.setGeometry (wingeo);
dc.setPolys (p1,p2);
for (int i=1; i<sizeof(sym_cutsurfaces)/sizeof(sym_cutsurfaces[0]); i++) {
if (sym_cutsurfaces[i].n > 0) {
CanvasDataStruct cds;
cds.initWith_polyxyz (&sym_cutsurfaces[i]);
Polyxyz p3 (cds.pxyz);
dc.setAdditionalPoly (p3);
}
}
Script::getZBuffer3d()->Realloc(main_width_data, main_height_data);
dc.setBuffers (Script::getBuffer(), Script::getZBuffer3d());
dc.drawCurve(0,0,main_width_data, main_height_data,sym_cut_distance );
sc.CalculateCurveOnSurface(0,0,main_width_data,main_height_data,*Script::getBuffer(), *Script::getZBuffer3d() );
delete clip;
}
}
syntax highlighted by Code2HTML, v. 0.9.1