ultimatepp/examples/GeoFun/GeoFun.cpp
cxl d34313b049 examples: GeoFun updated
git-svn-id: svn://ultimatepp.org/upp/trunk@7744 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2014-09-29 10:39:33 +00:00

818 lines
17 KiB
C++

#include "GeoFun.h"
#define IMAGECLASS GFImg
#define IMAGEFILE <GeoFun/GeoFun.iml>
#include <Draw/iml_source.h>
//When idraw = 1 it will create image at actual size based on radius values
//Else image created to screen window diaplay size
template <class T>
void DrawCanvas::DoPaint0 ( T& sw, int idraw )
{
double x1, y1;
int cnt1, cnt2;
int RunTo ;
Size sz;
if ( idraw == 1 )
{
sz = Size ( 2 * Radius1 + 20, 2 * Radius1 + 20 );
}
else
{
sz = GetSize();
}
sw.Clear ( White() );
x1 = sz.cx / 2 ;
y1 = sz.cy / 2 ;
// Show color fill. Draw bacground circle with color
if ( ColorFill )
{
if ( ShowGradient )
{
sw.Ellipse ( x1, y1, Radius1, Radius1 ).Fill ( x1, y1, fcolorB1, Radius1, fcolorB2 );
}
else
{
sw.Ellipse ( x1, y1, Radius1, Radius1 ).Fill ( fcolorB1 );
}
}
cnt1 = data.GetCount();
for ( int i = 0; i < data.GetCount(); i++ )
{
Vector<Pointf>& p = data[i].point;
sw.Move ( x1 + p[0].x, y1 + p[0].y );
cnt2 = p.GetCount();
// If animation flag set do incremental display of curve
// elase show all curve points.
if ( ShowAnimation )
{
RunTo = ShowTo ;
}
else
{
RunTo = cnt2 ;
}
if ( RunTo > cnt2 ) RunTo = cnt2 ;
for ( int j = 1; j < RunTo; j++ )
sw.Line ( x1 + p[j].x, y1 + p[j].y );
sw.Stroke ( data[i].penwidth, data[i].lcolor );
sw.EvenOdd ( true );
if ( ColorFill )
{
if ( ShowGradient )
{
sw.Fill ( x1, y1, data[i].fcolorM1, Radius1, data[i].fcolorM2, GRADIENT_REFLECT );
}
else
{
sw.Fill ( data[i].fcolorM1 );
}
}
// Show if option animation set
if ( ShowAnimation )
{
sw.BeginOnPath ( 1.0 );
sw.DrawImage ( 0, -GFImg::Bee().GetHeight() / 2, GFImg::Bee() );
sw.End();
sw.Ellipse ( x1, y1, BaseR, BaseR ).Stroke ( 3, Blue() );
sw.Ellipse ( x1 + data[i].CenR[RunTo-2].x, y1 + data[i].CenR[RunTo-2].y, RollR, RollR ).Stroke ( 3, LtBlue() );
sw.Move ( x1, y1 );
sw.Line ( x1 + data[i].CenR[RunTo-2].x, y1 + data[i].CenR[RunTo-2].y );
sw.Line ( x1 + data[i].point[RunTo-2].x, y1 + data[i].point[RunTo-2].y );
sw.Stroke ( 3, Red() );
ColorFill = false ; // this is required to stop colorfill if other options are changed during animation
}
}
}
DrawCanvas::DrawCanvas()
{
}
// at present this function is redundant but kept here to improve printing in future
void DrawCanvas::DoPaint ( Painter& sw )
{
bool painting = false ;
if ( painting )
{
PaintingPainter h ( 4000, 4000 );
DoPaint0 ( h, 0 );
sw.Paint ( h );
}
else
DoPaint0 ( sw, 0 );
}
void DrawCanvas::Paint ( Draw& drw )
{
Size sz = GetSize();
ImageBuffer ib ( sz );
BufferPainter sw ( ib );
bool transparent = false ;
DoPaint ( sw );
drw.DrawImage ( 0, 0, ib );
}
Image GeoFun::GetImage()
{
Size sz = Size ( dc1.Radius1 * 2 + 20, dc1.Radius1 * 2 + 20 );
ImageBuffer ib ( sz );
BufferPainter bp ( ib, MODE_ANTIALIASED );
dc1.DoPaint0 ( bp, 1 );
return ib;
}
void GeoFun::SaveToImageFile ( String fileName )
{
GuiLock __;
if ( IsNull ( fileName ) )
{
FileSel fs;
fs.Type ( "PNG file", "*.png" );
fs.Type ( "JPEG file", "*.jpg" );
if ( !fs.ExecuteSaveAs ( t_ ( "Saving plot to PNG or JPEG file" ) ) )
{
Exclamation ( t_ ( "Plot has not been saved" ) );
return;
}
fileName = fs;
}
if ( GetFileExt ( fileName ) == ".png" )
{
PNGEncoder encoder;
encoder.SaveFile ( fileName, GetImage() );
}
else
if ( GetFileExt ( fileName ) == ".jpg" )
{
JPGEncoder encoder ( 90 );
encoder.SaveFile ( fileName, GetImage() );
}
else
Exclamation ( Format ( t_ ( "File format \"%s\" not found" ), GetFileExt ( fileName ) ) );
}
void GeoFun::SaveToAutoCadScript ( String fileName )
{
if ( IsNull ( fileName ) )
{
FileSel fs;
fs.Type ( "SCR file", "*.scr" );
if ( !fs.ExecuteSaveAs ( t_ ( "Saving plot to Polyline -- AutoCAD Script " ) ) )
{
Exclamation ( t_ ( "Plot has not been saved" ) );
return;
}
fileName = fs;
}
if ( GetFileExt ( fileName ) == ".scr" )
{
String sScr ;
for ( int i = 0; i < dc1.data.GetCount(); i++ )
{
sScr << "PLINE\n" ;
Vector<Pointf>& p = dc1.data[i].point;
for ( int j = 0; j < p.GetCount(); j++ )
sScr << p[j].x << "," << p[j].y << "\n";
sScr << "\nZ\nE\n";
}
FileOut fo ;
fo.Open ( fileName );
fo.Put ( sScr );
fo.Close();
}
}
void GeoFun::SaveToSVG ( String fileName )
{
if ( IsNull ( fileName ) )
{
FileSel fs;
fs.Type ( "SVG file", "*.svg" );
if ( !fs.ExecuteSaveAs ( t_ ( "Saving as SVG file " ) ) )
{
Exclamation ( t_ ( "SVG has not been saved" ) );
return;
}
fileName = fs;
}
if ( GetFileExt ( fileName ) == ".svg" )
{
String sXML ;
sXML.Clear();
sXML << "<?xml version=\"1.0\" standalone=\"no\"?>" ;
sXML << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" " ;
sXML << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" ;
sXML << "<svg width=\"100%\" height=\"100%\" version=\"1.1\" " ;
sXML << "xmlns=\"http://www.w3.org/2000/svg\"> \n \n" ;
for ( int i = 0; i < dc1.data.GetCount(); i++ )
{
sXML << "\n<polygon points=\" ";
Vector<Pointf>& p = dc1.data[i].point;
for ( int j = 0; j < p.GetCount(); j++ )
sXML << Format ( "%0.4f", p[j].x ) << "," << Format ( "%0.4f", p[j].y ) << " ";
sXML << "\" style=\"fill:none;stroke:#00C000;stroke-width:0.4\" />\n" ;
}
sXML << "</svg>\n";
FileOut fo ;
fo.Open ( fileName );
fo.Put ( sXML );
fo.Close();
}
}
void GeoFun::Print()
{
Report r;
String sQtf;
r.SetPageSize ( 4400, 4400 );
Size sz = Size ( 4200, 4200 );
Image im = GetImage();
qtfim = CreatePNGObject ( im, Size ( 600, 600 ), sz );
sQtf << "[s0;= " ;
sQtf << qtfim << " ]";
r << sQtf ;
Perform ( r );
}
// This function calculates curve data points for display
void GeoFun::PrepareData0()
{
int p, q, pw;
double a, b, h ;
double x, y;
double Period, step, t ;
static int prepd = 0;
step = 1.0 ; // value in deg
int q1 = InputPane.edValP ;
if ( q1 > 0 )
{
p = InputPane.edValP ;
}
else
{
p = 1 ;
InputPane.edValP.SetData ( p ) ;
}
q1 = InputPane.edValQ ;
if ( q1 > 0 )
{
q = InputPane.edValQ ;
}
else
{
q = 1 ;
InputPane.edValQ.SetData ( q ) ;
}
q1 = InputPane.edPenWidth ;
if ( q1 > 0 )
{
pw = InputPane.edPenWidth ;
}
else
{
pw = 1 ;
InputPane.edPenWidth.SetData ( pw ) ;
}
Period = 2 * M_PI * p ;
int iCrv = ~InputPane.CurveType;
if ( ( iCrv == 1 ) || ( iCrv == 3 ) )
{
p = -p ;
}
double tmp = InputPane.edBaseCircleRad;
if ( tmp < 10 )
{
a = 10 ;
InputPane.edBaseCircleRad.SetData ( a );
}
else
{
a = InputPane.edBaseCircleRad;
}
b = ( double ) p * a / ( double ) q;
dc1.BaseR = a ;
dc1.RollR = fabs ( b );
if ( iCrv < 2 )
{
h = fabs ( b );
}
else
{
tmp = InputPane.edArmLength ;
if ( tmp < 0 )
{
h = 0 ;
InputPane.edArmLength.SetData ( h ) ;
}
else
{
h = InputPane.edArmLength ;
}
}
dc1.Radius1 = fabs ( a + b ) + h ;
InputPane.RollingRad = "Rolling Radius : " + Format ( "%0.2f", b ) ;
// ShowAnimation = ~InputPane.optAnimate ;
dc1.Zoomed = InputPane.optZoom.GetData();
if ( dc1.Zoomed )
{
Size sz = dc1.GetSize();
double dmax = sz.cx ;
if ( sz.cy < dmax )
dmax = sz.cy;
dmax -= 10 ;
double zScale = fabs ( dmax / ( 2 * dc1.Radius1 ) );
a = a * zScale;
h = h * zScale;
b = b * zScale;
dc1.BaseR = a ;
dc1.RollR = fabs ( b );
dc1.Radius1 = fabs ( a + b ) + h ;
}
dc1.data.Clear();
dc1.data.Add();
dc1.data[0].point.Clear();
dc1.data[0].CenR.Clear();
dc1.data[0].lcolor = ~InputPane.LineColor;
dc1.data[0].fcolorM1 = ~InputPane.FillColorM1;
dc1.data[0].fcolorM2 = ~InputPane.FillColorM2;
dc1.data[0].penwidth = pw;
dc1.fcolorB1 = ~InputPane.FillColorB1;
dc1.fcolorB2 = ~InputPane.FillColorB2;
dc1.ShowGradient = ~InputPane.optGradient;
dc1.ColorFill = ~InputPane.optColorFill;
int NumSteps = abs ( ( int ) ( 2.0 * ( double ) p * 180.0 / step ) ) + 1 ;
for ( int i = 0; i < NumSteps; i++ )
{
t = ( double ) i / ( double ) NumSteps * Period ;
x = ( a + b ) * cos ( t ) + h * cos ( ( ( a + b ) / b ) * t ) ;
y = ( a + b ) * sin ( t ) + h * sin ( ( ( a + b ) / b ) * t );
Pointf p1;
p1.Clear();
p1.x = x ;
p1.y = y ;
dc1.data[0].point.Add ( p1 );
p1.Clear();
x = ( a + b ) * cos ( t );
y = ( a + b ) * sin ( t );
p1.x = x ;
p1.y = y ;
dc1.data[0].CenR.Add ( p1 );
}
Pointf p1;
p1.x = dc1.data[0].point[0].x ;
p1.y = dc1.data[0].point[0].y ;
dc1.data[0].point.Add ( p1 );
prepd++;
}
void GeoFun::PrepareData()
{
PrepareData0();
dc1.Refresh();
}
void GeoFun::ShowAnimated()
{
int MaxCnt = dc1.data[0].point.GetCount();
// static dword LastTickCount = GetTickCount() ;
if ( dc1.ShowAnimation )
{
if ( dc1.ShowTo < MaxCnt )
{
dc1.Refresh();
dc1.ShowTo += dc1.AnimSpeed ;
}
else
{
dc1.ShowAnimation = false ;
dc1.ColorFill = ~InputPane.optColorFill ;
dc1.Refresh();
}
}
// RLOG("TickCount - " <<( GetTickCount() - LastTickCount));
// LastTickCount = GetTickCount();
}
void GeoFun::SetAnimation()
{
dc1.AnimSpeed = InputPane.edAnimSpeed.GetData();
dc1.ShowTo = 5 ;
dc1.ShowAnimation = true ;
dc1.ColorFill = false ;
}
void GeoFun::FirstDraw()
{
First = false ;
PrepareData();
SetTimeCallback ( -30, THISBACK ( ShowAnimated ), 50 );
}
void GeoFun::Serialize ( Stream& s )
{
s
% InputPane.edArmLength
% InputPane.edBaseCircleRad
% InputPane.edPenWidth
% InputPane.edValP
% InputPane.edValQ
% InputPane.LineColor
% InputPane.FillColorM1
% InputPane.FillColorM2
% InputPane.FillColorB1
% InputPane.FillColorB2
% InputPane.optGradient
% InputPane.optColorFill
% InputPane.CurveType
% InputPane.optZoom
% InputPane.edAnimSpeed
;
SerializePlacement ( s );
}
// Using layout to redraw on windows resize
void GeoFun::Layout()
{
if ( !First )
{
PrepareData0();
}
TopWindow::Layout();
}
void GeoFun::About()
{
WithAboutLayout<TopWindow> dlg;
dlg.AboutText = GetTopic ( "topic://GeoFun/app/About$en-us" ).text;
CtrlLayoutOK ( dlg, "About" );
dlg.CenterScreen();
dlg.Run();
}
void GeoFun::Help()
{
HelpWindow helpme;
helpme.GoTo ( "topic://GeoFun/app/Help$en-us" );
helpme.Execute();
}
void GeoFun::Exit()
{
Close();
}
void GeoFun::SetAnimationSpeed()
{
dc1.AnimSpeed = InputPane.edAnimSpeed.GetData();
if ( dc1.AnimSpeed < 1 ) dc1.AnimSpeed = 1;
if ( dc1.AnimSpeed > 20 ) dc1.AnimSpeed = 20;
InputPane.edAnimSpeed.SetData ( dc1.AnimSpeed );
}
void GeoFun::OptionColorFill()
{
int i = InputPane.optColorFill.Get();
i = i ? 0 : 1;
InputPane.optColorFill.Set ( i ) ;
PrepareData();
}
void GeoFun::OptionGradient()
{
int i = InputPane.optGradient.Get();
i = i ? 0 : 1;
InputPane.optGradient.Set ( i ) ;
PrepareData();
}
void GeoFun::OptionZoom()
{
int i = InputPane.optZoom.Get();
i = i ? 0 : 1;
InputPane.optZoom.Set ( i ) ;
PrepareData();
}
void GeoFun::SetCurveType ( int CrvType )
{
InputPane.CurveType.SetData ( CrvType );
SetCurveTypeMenu ( CrvType );
}
void GeoFun::SetCurveTypeMenu1 ( )
{
int CrvType = InputPane.CurveType.GetData();
SetCurveTypeMenu ( CrvType );
}
void GeoFun::SetCurveTypeMenu ( int CrvType )
{
EpiCyclo = HypoCyclo = EpiTroch = HypoTroch = false ;
switch ( CrvType )
{
case 1 : HypoCyclo = true ; break ;
case 2 : EpiTroch = true ; break ;
case 3 : HypoTroch = true ; break ;
default : EpiCyclo = true ;
}
PrepareData();
}
// Menu Functions
void GeoFun::SettingsMenu ( Bar& bar )
{
bar.Add ( t_ ( "Color Fill" ), THISBACK ( OptionColorFill ) ).Check ( dc1.ColorFill )
.Help ( t_ ( "Change settings" ) );
bar.Add ( t_ ( "Gradient Fill" ), THISBACK ( OptionGradient ) ).Check ( dc1.ShowGradient )
.Help ( t_ ( "Change settings" ) );
bar.Add ( t_ ( "Zoom Fit" ), THISBACK ( OptionZoom ) ).Check ( dc1.Zoomed )
.Help ( t_ ( "Zoom fit to window area" ) );
}
void GeoFun::FileMenu ( Bar& bar )
{
bar.Add ( t_ ( "Save Image" ), CtrlImg::save_as(), THISBACK1 ( SaveToImageFile, "" ) )
.Help ( t_ ( "Save Image as PNG or JPG" ) );
bar.Add ( t_ ( "Save AutoCAD Script" ), CtrlImg::save(), THISBACK1 ( SaveToAutoCadScript, "" ) )
.Help ( t_ ( "Save as AutoCAD Script (.scr) file" ) );
bar.Add ( t_ ( "Save as SVG" ), CtrlImg::save(), THISBACK1 ( SaveToSVG, "" ) )
.Help ( t_ ( "Save as Scalable vector graphics (.svg) file" ) );
bar.Separator();
bar.Add ( t_ ( "Print" ), CtrlImg::print() , THISBACK ( Print ) )
.Help ( t_ ( "Print the image , will fit to A4 page" ) );
bar.Separator();
bar.Add ( t_ ( "Exit" ), THISBACK ( Exit ) )
.Help ( t_ ( "Exit the application" ) );
}
void GeoFun::CurvesMenu ( Bar& bar )
{
bar.Add ( t_ ( "Epicycloid" ), THISBACK1 ( SetCurveType, 0 ) )
.Help ( t_ ( "Plot Epicycloid curve" ) ).Check(EpiCyclo);
bar.Add ( t_ ( "Hypocycloid" ), THISBACK1 ( SetCurveType, 1 ) )
.Help ( t_ ( "Plot Hypocycloid curve" ) ).Check(HypoCyclo);
bar.Add ( t_ ( "Epitrochoid" ), THISBACK1 ( SetCurveType, 2 ) )
.Help ( t_ ( "Plot Epitrochoid curve" ) ).Check(EpiTroch);
bar.Add ( t_ ( "Hypotrochoid" ), THISBACK1 ( SetCurveType, 3 ) )
.Help ( t_ ( "Plot Hypotrochoid curve" ) ).Check(HypoTroch);
bar.Separator();
bar.Add ( t_ ( "Animated Plot" ), THISBACK ( SetAnimation ) )
.Help ( t_ ( "Show animation of the curve drawing" ) ).Check(AnimMn);
}
void GeoFun::MainMenu ( Bar& bar )
{
bar.Add ( t_ ( "File" ), THISBACK ( FileMenu ) );
bar.Add ( t_ ( "Curves" ), THISBACK ( CurvesMenu ) );
bar.Add ( t_ ( "Options" ), THISBACK ( SettingsMenu ) );
bar.Add ( t_ ( "Assist" ), THISBACK ( HelpMenu ) );
}
void GeoFun::HelpMenu ( Bar& bar )
{
bar.Add ( t_ ( "About" ), CtrlImg::information(), THISBACK ( About ) )
.Help ( t_ ( "About GeoFun" ) );
bar.Separator();
bar.Add ( t_ ( "Help" ), CtrlImg::help(), THISBACK ( Help ) )
.Help ( t_ ( "Help GeoFun" ) );
}
GeoFun::GeoFun()
{
CtrlLayout ( *this, "GeoFun : Enjoy Geometric Curves" );
Icon ( GFImg::gficon() );
CtrlLayout ( InputPane );
Sizeable().Zoomable();
InputPane.btnImg << THISBACK1 ( SaveToImageFile, "" );
InputPane.btnPrint << THISBACK ( Print );
InputPane.btnShowAnimation << THISBACK ( SetAnimation );
Add ( dc1.HSizePosZ ( 5, 160 ).VSizePosZ ( 25, 5 ) );
Add ( InputPane.RightPosZ ( 5, 150 ).VSizePosZ ( 2, 5 ) );
BackPaint();
dc1.data.Clear();
// Check config file available else set default data
if ( !cfgAvailable )
{
InputPane.edArmLength.SetData ( 112 ) ;
InputPane.edBaseCircleRad.SetData ( 145 );
InputPane.edPenWidth.SetData ( 3 );
InputPane.edValP.SetData ( 5 );
InputPane.edValQ.SetData ( 12 );
InputPane.edAnimSpeed.SetData ( 5 );
InputPane.LineColor.SetData ( Blue() ) ;
InputPane.FillColorM1.SetData ( LtGreen() ) ;
InputPane.FillColorM2.SetData ( Yellow() ) ;
InputPane.FillColorB1.SetData ( Blue() ) ;
InputPane.FillColorB2.SetData ( LtCyan() ) ;
InputPane.optGradient.Set ( 1 );
InputPane.optColorFill.Set ( 1 );
InputPane.CurveType.SetData ( 2 );
}
InputPane.CurveType.WhenAction << THISBACK (SetCurveTypeMenu1);
InputPane.optGradient.WhenAction << THISBACK ( PrepareData );
InputPane.optColorFill.WhenAction << THISBACK ( PrepareData );
InputPane.FillColorB1.WhenAction << THISBACK ( PrepareData );
InputPane.FillColorB2.WhenAction << THISBACK ( PrepareData );
InputPane.FillColorM1.WhenAction << THISBACK ( PrepareData );
InputPane.FillColorM2.WhenAction << THISBACK ( PrepareData );
InputPane.LineColor.WhenAction << THISBACK ( PrepareData );
InputPane.edPenWidth.WhenAction << THISBACK ( PrepareData );
InputPane.edValP.WhenAction << THISBACK ( PrepareData );
InputPane.edValQ.WhenAction << THISBACK ( PrepareData );
InputPane.edArmLength.WhenAction << THISBACK ( PrepareData );
InputPane.edBaseCircleRad.WhenAction << THISBACK ( PrepareData );
InputPane.edAnimSpeed.WhenAction << THISBACK ( SetAnimationSpeed );
InputPane.optZoom.WhenAction << THISBACK ( PrepareData );
// Set timercallback to do first painting with calculations
// You can not call this directly from constructor
SetTimeCallback ( 200, THISBACK ( FirstDraw ) );
dc1.ShowTo = 5 ; // start point of animation.
menu.Set ( THISBACK ( MainMenu ) );
}
GUI_APP_MAIN
{
GeoFun gf ;
gf.First = true ;
String cfgfile = ConfigFile();
if ( FileExists ( cfgfile ) )
{
cfgAvailable = true ;
if ( !LoadFromFile ( gf, cfgfile ) )
{
cfgAvailable = false ;
Exclamation ( "Error loading configuration file!" );
}
}
else
{
cfgAvailable = false ;
}
// gf.Icon(Image::(5555, true), Image::ICON(5555, false));
gf.Run();
StoreToFile ( gf );
}