lazarus-ccr/applications/fpvviewer/fpvv_mainform.pas
sekelsenmat af849d1377 fpvviewer: Updates to latest fpvectorial
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@5112 8e941d3f-bd1b-0410-a28a-d453659cc2b4
2016-08-29 15:34:51 +00:00

637 lines
19 KiB
ObjectPascal

unit fpvv_mainform;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, EditBtn,
StdCtrls, Spin, ExtCtrls, ComCtrls, Grids, ColorBox, Math,
Printers, PrintersDlgs, LCLIntf, LCLType,
fpvv_drawer, fpimage, fpcanvas, coreconrec, fpvutils,
fpvectorial, lasvectorialreader, svgvectorialwriter,
svgvectorialreader_rsvg, svgvectorialreader,
dxfvectorialreader, epsvectorialreader, fpvtocanvas, dxftokentotree;
type
{ TfrmFPVViewer }
TfrmFPVViewer = class(TForm)
btnContourLines: TButton;
btnSearchInTokens: TButton;
btnViewDXFTokens: TButton;
btnVisualize: TButton;
buttonConvertToSVG: TButton;
buttonViewFPVTokens: TButton;
buttonAutoFit: TButton;
buttonPrint: TButton;
buttonAdjust: TButton;
buttonViewDebugInfo: TButton;
buttonAutoFitView: TButton;
checkboxSVGviaRSVG: TCheckBox;
checkboxForceBottomLeftOrigin: TCheckBox;
checkShowPage: TCheckBox;
checkForceWhiteBackground: TCheckBox;
comboEncoding: TComboBox;
editFileName: TFileNameEdit;
editSearchInTokens: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
labelFileEncoding: TLabel;
memoDebug: TMemo;
notebook: TNotebook;
pageDebug: TPage;
pageViewer: TPage;
pageTreeData: TPage;
Panel1: TPanel;
spinAdjustX: TSpinEdit;
spinAdjustY: TSpinEdit;
spinScale: TFloatSpinEdit;
TokensTreeView: TTreeView;
procedure btnContourLinesClick(Sender: TObject);
procedure btnSearchInTokensClick(Sender: TObject);
procedure btnVisualizeClick(Sender: TObject);
procedure btnViewDXFTokensClick(Sender: TObject);
procedure buttonConvertToSVGClick(Sender: TObject);
procedure buttonViewFPVTokensClick(Sender: TObject);
procedure buttonAdjustClick(Sender: TObject);
procedure buttonAutoFitClick(Sender: TObject);
procedure buttonPrintClick(Sender: TObject);
procedure buttonAutoFitViewClick(Sender: TObject);
procedure buttonViewDebugInfoClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure spinAdjustXChange(Sender: TObject);
procedure spinAdjustYChange(Sender: TObject);
procedure spinScaleChange(Sender: TObject);
private
FVec: TvVectorialDocument;
procedure MyContourLineDrawingProc(z,x1,y1,x2,y2: Double);
function FPVDebugAddItemProc(AStr: string; AParent: Pointer): Pointer;
procedure HandleDrawerMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure HandleDrawerPosChanged(Sender: TObject);
procedure HandleDrawerRedraw(Sender: TObject);
procedure ViewerDebugOutCallback(AStr: string);
//
procedure Render_PrepareFile();
procedure Render_Calc_Drawer_Size();
procedure Render_DoRender(ACanvasSizeX, ACanvasSizeY,
ADrawerPosX, ADrawerPosY: Integer; AScale: Double);
procedure Render_FreeFile();
public
{ public declarations }
Drawer: TFPVVDrawer;
end;
var
frmFPVViewer: TfrmFPVViewer;
implementation
{$R *.lfm}
{ TfrmFPVViewer }
procedure TfrmFPVViewer.btnVisualizeClick(Sender: TObject);
var
lPage: TvPage;
YAxisMultiplier: Double = -1;
lPageHeight: Integer;
begin
Render_PrepareFile();
try
Render_Calc_Drawer_Size();
Drawer.Drawing.Canvas.Brush.Color := clWhite;
Drawer.Drawing.Canvas.Brush.Style := bsSolid;
Drawer.Drawing.Canvas.FillRect(0, 0, Drawer.Drawing.Width, Drawer.Drawing.Height);
if FVec = nil then Exit;
lPage := FVec.GetPage(0);
if lPage = nil then
Exception.Create('The document has no pages');
lPageHeight := Drawer.Drawing.Height;
lPage.GetNaturalRenderPos(lPageHeight, YAxisMultiplier);
if checkForceWhiteBackground.Checked then lPage.BackgroundColor := colWhite;
if not checkForceWhiteBackground.Checked then
lPage.DrawBackground(Drawer.Drawing.Canvas);
lPage.Render(
Drawer.Drawing.Canvas,
Drawer.PosX,
lPageHeight + Drawer.PosY,
spinScale.Value,
YAxisMultiplier * spinScale.Value);
if checkShowPage.Checked then
lPage.RenderPageBorder(
Drawer.Drawing.Canvas,
Drawer.PosX,
lPageHeight + Drawer.PosY,
spinScale.Value,
YAxisMultiplier * spinScale.Value);
Drawer.Invalidate;
// Show debug tokens
TokensTreeView.Items.Clear;
FVec.GenerateDebugTree(@FPVDebugAddItemProc);
memoDebug.Lines.AddStrings(lPage.RenderInfo.Errors);
finally
Render_FreeFile();
end;
end;
procedure TfrmFPVViewer.btnContourLinesClick(Sender: TObject);
const
dimx = 1024; // dimension west - east
dimy = 1024; // dimenstion north west
dimh = 20; // dimension for contour levels
var
Mat:TMatrix; // 2D - Datafield
scx:TVector; // scaling vector west - east
scy:TVector; // scaling vector north - west
hgt:TVector; // vector for the countur levels
i,j:Integer; // adress indexes
x,y:Double; // coord. values
mi,ma:Double; // for minimum & maximum
Vec: TvVectorialDocument;
lPage: TvVectorialPage;
lRasterImage: TvRasterImage;
begin
// Drawing size setting and initialization
Drawer.Drawing.Width := Drawer.Width;
Drawer.Drawing.Height := Drawer.Height;
Drawer.Drawing.Canvas.Brush.Color := clWhite;
Drawer.Drawing.Canvas.Brush.Style := bsSolid;
Drawer.Drawing.Canvas.FillRect(0, 0, Drawer.Drawing.Width, Drawer.Drawing.Height);
Vec := TvVectorialDocument.Create;
Vec.ReadFromFile(editFileName.FileName);
lPage := Vec.GetPageAsVectorial(0);
lRasterImage := TvRasterImage(lPage.GetEntity(0));
// create dynamicaly the vectors and datafield
setlength(scx,dimx);
setlength(scy,dimy);
setlength(hgt,dimh);
setlength(mat,dimx);
for i:=0 to dimx-1 do Setlength(mat[i],dimy);
try
for i:=0 to dimx-1 do scx[i]:= i * 10; // set scaling vector west - east
for i:=0 to dimy-1 do scy[i]:= i * 10; // set scaling vector north - south
for i:=0 to dimx-1 do // ----------------------------------- set 2d data field
for j:=0 to dimy-1 do
begin
x:=i-dimx/2;
y:=j-dimy/2;
mat[i,j]:= Round(lRasterImage.RasterImage.Colors[i, j].red * dimh / $FFFF);
{ (sin(x/dimx*4*pi) * cos(y/dimy*4*pi)) +
(sin(x/dimx*2*pi) * cos(y/dimy*2*pi)) +
(sin(x/dimx*1*pi) * cos(y/dimy*1*pi)) +
(sin(x/dimx*0.5*pi) * cos(y/dimy*0.5*pi))+
(sin(x/dimx*0.25*pi) * cos(y/dimy*0.25*pi));}
end; // -----------------------------------------------------------------------
mi:=1e16; // ------------ Set the minimunm and maximum fof the data field
ma:=-1e16;
for i:=0 to dimx-1 Do
for j:=0 to dimy-1 do
begin
if mat[i,j]<mi then mi:=mat[i,j];
if mat[i,j]>ma then ma:=mat[i,j];
end; //----------------------------------------------------------------
For i:=0 to dimh-1 Do hgt[i]:=mi+i*(ma-mi)/(dimh-1); // ----- create cut levels
ContourLineDrawingProc := @MyContourLineDrawingProc;
// call the contour algorithm
conrec(mat,0,dimx-1,0,dimy-1,scx,scy,dimh,hgt);
finally
// Finalization of allocated memory
setlength(scx, 0);
setlength(scy, 0);
setlength(hgt, 0);
For i:=0 to dimx-1 Do Setlength(mat[i], 0);
setlength(mat, 0);
Vec.Free;
end;
Drawer.Invalidate;
end;
procedure TfrmFPVViewer.btnSearchInTokensClick(Sender: TObject);
var
lTokenWithText, lCurNode: TTreeNode;
// minimal positions, based on the currently selected item to do "search next"
lSearchStart: Word = 0;
i, j: Integer;
lStr, lText: TCaption;
lNodesCount: Integer;
begin
lText := editSearchInTokens.Text;
// if something is selected, set this position as a minimum
if TokensTreeView.Selected <> nil then
lSearchStart := TokensTreeView.Selected.AbsoluteIndex;
// Now do the actual search
lTokenWithText := nil;
lNodesCount := TokensTreeView.Items.Count-1;
for i := 0 to lNodesCount do
begin
lCurNode := TokensTreeView.Items.Item[i];
if lCurNode = nil then Continue;
// Check the minimum level first
if lSearchStart >= lCurNode.AbsoluteIndex then Continue;
// Check the text
lStr := lCurNode.Text;
if System.Pos(lText, lStr) > 0 then
begin
lTokenWithText := lCurNode;
Break;
end;
end;
if lTokenWithText <> nil then
begin
TokensTreeView.Selected := lTokenWithText;
end;
end;
procedure TfrmFPVViewer.btnViewDXFTokensClick(Sender: TObject);
var
Reader: TvDXFVectorialReader;
Vec: TvVectorialDocument;
begin
// First check the in input
//if not CheckInput() then Exit;
notebook.PageIndex := 1;
Reader := TvDXFVectorialReader.Create;
Vec := TvVectorialDocument.Create;
try
Reader.ReadFromFile(editFileName.FileName, Vec);
ConvertDXFTokensToTreeView(Reader.Tokenizer.Tokens, TokensTreeView);
finally
Reader.Free;
Vec.Free;
end;
end;
procedure TfrmFPVViewer.buttonConvertToSVGClick(Sender: TObject);
var
Vec: TvVectorialDocument;
begin
Vec := TvVectorialDocument.Create;
try
Vec.ReadFromFile(editFileName.FileName);
Vec.WriteToFile(ChangeFileExt(editFileName.FileName, '.svg'));
finally
Vec.Free;
end;
end;
procedure TfrmFPVViewer.buttonViewFPVTokensClick(Sender: TObject);
begin
notebook.PageIndex := 1;
end;
procedure TfrmFPVViewer.buttonAdjustClick(Sender: TObject);
const
FPVVIEWER_MAX_IMAGE_SIZE = 1000;
FPVVIEWER_MIN_IMAGE_SIZE = 100;
FPVVIEWER_SPACE_FOR_NEGATIVE_COORDS = 100;
var
lSpaceForNegCoords: TPoint;
lCurPage: TvPage;
lZoom: Double;
lCanvasWidth: Integer;
begin
Render_PrepareFile();
try
lCurPage := FVec.GetPage(0);
lCurPage.CalculateDocumentSize();
lCanvasWidth := Drawer.Width;
lZoom := (Drawer.Width / lCurPage.Width) * 0.8;
spinScale.Value := lZoom;
// Centralizes the image in the canvas
lSpaceForNegCoords.X := Round(lCurPage.MinX * -1 * lZoom + Drawer.Width * 0.1);
lSpaceForNegCoords.Y := Round(lCurPage.MinY * lZoom - Drawer.Height * 0.1);
spinAdjustX.Value := lSpaceForNegCoords.X - FPVVIEWER_SPACE_FOR_NEGATIVE_COORDS;
spinAdjustY.Value := lSpaceForNegCoords.Y + FPVVIEWER_SPACE_FOR_NEGATIVE_COORDS;
Render_DoRender(Drawer.Width, Drawer.Height, lSpaceForNegCoords.X, lSpaceForNegCoords.Y, lZoom);
finally
Render_FreeFile();
end;
end;
procedure TfrmFPVViewer.buttonAutoFitClick(Sender: TObject);
var
lPage: TvPage;
lDeltaX, lDeltaY: Integer;
lZoom: Double;
begin
Render_PrepareFile();
try
Render_Calc_Drawer_Size();
lPage := FVec.GetPage(0);
lPage.AutoFit(Drawer.Drawing.Canvas, Drawer.Width, Drawer.Height,
Drawer.Drawing.Height, lDeltaX, lDeltaY, lZoom);
if Sender <> nil then Drawer.Invalidate;
spinAdjustX.Value := lDeltaX;
spinAdjustY.Value := lDeltaY;
spinScale.Value := lZoom;
spinAdjustXChange(nil);
spinAdjustYChange(nil);
spinScaleChange(nil);
finally
Render_FreeFile();
end;
end;
procedure TfrmFPVViewer.buttonPrintClick(Sender: TObject);
var
printDialog: TPrintDialog;
ScaleX, ScaleY, lScale: Double;
lRectSrc, lRectDest: TRect;
begin
// Create a printer selection dialog
printDialog := TPrintDialog.Create(Self);
// Set up print dialog options
printDialog.Options := [];
// if the user has selected a printer (or default), then print!
if printDialog.Execute then
begin
// Generate the image
btnVisualizeClick(Sender);
// Start printing
Printer.BeginDoc;
// Draw the image
{$IFDEF OLD_PRINT_CODE}
ScaleX := LCLIntf.GetDeviceCaps(Handle, logPixelsX) / PixelsPerInch; // Don't know why, but GetDeviceCaps is returning zero...
ScaleY := LCLIntf.GetDeviceCaps(Handle, logPixelsY) / PixelsPerInch;
lRectSrc := Bounds(0, 0, Drawer.Drawing.Width, Drawer.Drawing.Height);
lRectDest := Bounds(0, 0, Printer.PageWidth, Printer.PageHeight);
{$ELSE}
ScaleX := Printer.PageWidth / Drawer.Drawing.Width;
ScaleY := Printer.PageHeight / Drawer.Drawing.Height;
lScale := Min(ScaleX, ScaleY);
lRectSrc := Bounds(0, 0, Drawer.Drawing.Width, Drawer.Drawing.Height);
lRectDest := Bounds(0, 0,
Round(Drawer.Drawing.Width * lScale),
Round(Drawer.Drawing.Height * lScale));
{$ENDIF}
Printer.Canvas.StretchDraw(
lRectDest,
Drawer.Drawing);
// Finish printing
Printer.EndDoc;
end;
printDialog.Free;
end;
procedure TfrmFPVViewer.buttonAutoFitViewClick(Sender: TObject);
begin
buttonAutoFitClick(nil);
btnVisualizeClick(nil);
end;
{var
VecDoc: TvVectorialDocument;
Vec: TvVectorialPage;
begin
notebook.PageIndex := 0;
Drawer.Clear;
VecDoc := TvVectorialDocument.Create;
Vec := VecDoc.AddPage();
try
Vec.AddAlignedDimension(Make2DPoint(100, 50), Make2DPoint(200, 100), Make2DPoint(100, 150), Make2DPoint(200, 150));
Vec.AddAlignedDimension(Make2DPoint(50, 250), Make2DPoint(100, 200), Make2DPoint(150, 250), Make2DPoint(150, 200));
Vec.StartPath(0, 0);
Vec.SetPenColor(colYellow);
Vec.SetPenWidth(1);
Vec.AddLineToPath(100, 100);
Vec.EndPath();
Drawer.Drawing.Width := 400;
Drawer.Drawing.Height := 400;
Drawer.Drawing.Canvas.Brush.Color := clWhite;
Drawer.Drawing.Canvas.Brush.Style := bsSolid;
Drawer.Drawing.Canvas.FillRect(0, 0, Drawer.Drawing.Width, Drawer.Drawing.Height);
DrawFPVectorialToCanvas(
Vec,
Drawer.Drawing.Canvas,
0,
Drawer.Drawing.Height,
spinScale.Value,
-1 * spinScale.Value);
Drawer.Invalidate;
finally
Vec.Free;
end;
end;}
procedure TfrmFPVViewer.buttonViewDebugInfoClick(Sender: TObject);
begin
notebook.PageIndex := 2;
end;
procedure TfrmFPVViewer.FormCreate(Sender: TObject);
const
FPVVIEWER_SPACE_FOR_NEGATIVE_COORDS = 100;
begin
Drawer := TFPVVDrawer.Create(Self);
Drawer.Parent := pageViewer;
Drawer.Top := 5;
Drawer.Left := 5;
Drawer.AnchorClient(5);
Drawer.TabStop := True;
Drawer.OnMouseWheel := @HandleDrawerMouseWheel;
Drawer.PosChangedCallback := @HandleDrawerPosChanged;
Drawer.RedrawCallback := @HandleDrawerRedraw;
Drawer.PosX := FPVVIEWER_SPACE_FOR_NEGATIVE_COORDS;
Drawer.PosY := -1 * FPVVIEWER_SPACE_FOR_NEGATIVE_COORDS;
HandleDrawerPosChanged(nil);
FPVUDebugOutCallback := @ViewerDebugOutCallback;
end;
procedure TfrmFPVViewer.FormDestroy(Sender: TObject);
begin
Drawer.Free;
end;
procedure TfrmFPVViewer.spinAdjustXChange(Sender: TObject);
begin
Drawer.PosX := spinAdjustX.Value;
end;
procedure TfrmFPVViewer.spinAdjustYChange(Sender: TObject);
begin
Drawer.PosY := spinAdjustY.Value;
end;
procedure TfrmFPVViewer.spinScaleChange(Sender: TObject);
begin
if spinScale.Value <= 0.2 then spinScale.Increment := 0.01
else if spinScale.Value <= 2 then spinScale.Increment := 0.1
else spinScale.Increment := 1;
end;
procedure TfrmFPVViewer.MyContourLineDrawingProc(z, x1, y1, x2, y2: Double);
begin
Drawer.Drawing.Canvas.Pen.Style := psSolid;
Drawer.Drawing.Canvas.Pen.Color := clBlack;
Drawer.Drawing.Canvas.Line(
Round(x1 * spinScale.Value / 20),
Round(y1 * spinScale.Value / 20),
Round(x2 * spinScale.Value / 20),
Round(y2 * spinScale.Value / 20));
end;
function TfrmFPVViewer.FPVDebugAddItemProc(AStr: string; AParent: Pointer): Pointer;
var
lTreeItem: TTreeNode;
begin
lTreeItem := TokensTreeView.Items.AddChild(TTreeNode(AParent), AStr);
Result := lTreeItem;
end;
procedure TfrmFPVViewer.HandleDrawerMouseWheel(Sender: TObject;
Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint;
var Handled: Boolean);
begin
if WheelDelta > 0 then
spinScale.Value := spinScale.Value + spinScale.Increment
else
spinScale.Value := spinScale.Value - spinScale.Increment;
btnVisualize.Click();
end;
procedure TfrmFPVViewer.HandleDrawerPosChanged(Sender: TObject);
begin
spinAdjustX.Value := Drawer.PosX;
spinAdjustY.Value := Drawer.PosY;
end;
procedure TfrmFPVViewer.HandleDrawerRedraw(Sender: TObject);
begin
btnVisualizeClick(Sender);
end;
procedure TfrmFPVViewer.ViewerDebugOutCallback(AStr: string);
begin
memoDebug.Lines.Add(AStr);
end;
procedure TfrmFPVViewer.Render_PrepareFile;
begin
// First check the in input
if editFileName.FileName = '' then Exit; // silent exit in this simple case
//if not CheckInput() then Exit;
notebook.PageIndex := 0;
FVec := TvVectorialDocument.Create;
// If we desire, force a encoding for the read operation
if comboEncoding.ItemIndex > 0 then
FVec.ForcedEncodingOnRead := comboEncoding.Text
else FVec.ForcedEncodingOnRead := '';
// checkbox options
{$ifdef Windows}
FVec.ReaderSettings.HelperToolPath := ExtractFilePath(paramstr(0))+'rsvg\rsvg-convert.exe';
{$endif}
if checkboxForceBottomLeftOrigin.Checked then
FVec.ReaderSettings.VecReaderFlags := [vrfSVG_UseBottomLeftCoords]
else
FVec.ReaderSettings.VecReaderFlags := [];
if checkboxSVGviaRSVG.Checked then
RegisterVectorialReader(TvSVGVectorialReader_RSVG, vfSVG)
else
RegisterVectorialReader(TvSVGVectorialReader, vfSVG);
// Actual reading process
FVec.ReadFromFile(editFileName.FileName);
// some formats like HTML need an input of control size to render themselves
FVec.Width := Drawer.Width;
FVec.Height := Drawer.Height;
// Show document properties
labelFileEncoding.Caption := 'File encoding: ' + FVec.Encoding;
end;
procedure TfrmFPVViewer.Render_Calc_Drawer_Size;
const
FPVVIEWER_MAX_IMAGE_SIZE = 1000;
FPVVIEWER_MIN_IMAGE_SIZE = 100;
var
CanvasSize: TPoint;
begin
if FVec = nil then Exit;
// We need to be robust, because sometimes the document size won't be given
// also give up drawing everything if we need more then 4MB of RAM for the image
// and also give some space in the image to allow for negative coordinates
if FVec.Width * spinScale.Value > FPVVIEWER_MAX_IMAGE_SIZE then CanvasSize.X := FPVVIEWER_MAX_IMAGE_SIZE
else if FVec.Width < FPVVIEWER_MIN_IMAGE_SIZE then CanvasSize.X := Drawer.Width
else CanvasSize.X := Round(FVec.Width * spinScale.Value);
if CanvasSize.X < Drawer.Width then CanvasSize.X := Drawer.Width;
if FVec.Height * spinScale.Value > FPVVIEWER_MAX_IMAGE_SIZE then CanvasSize.Y := FPVVIEWER_MAX_IMAGE_SIZE
else if FVec.Height < FPVVIEWER_MIN_IMAGE_SIZE then CanvasSize.Y := Drawer.Height
else CanvasSize.Y := Round(FVec.Height * spinScale.Value);
if CanvasSize.Y < Drawer.Height then CanvasSize.Y := Drawer.Height;
Drawer.Drawing.Width := CanvasSize.X;
Drawer.Drawing.Height := CanvasSize.Y;
end;
procedure TfrmFPVViewer.Render_DoRender(ACanvasSizeX, ACanvasSizeY,
ADrawerPosX, ADrawerPosY: Integer; AScale: Double);
const
FPVVIEWER_MAX_IMAGE_SIZE = 1000;
FPVVIEWER_MIN_IMAGE_SIZE = 100;
begin
Drawer.Drawing.Width := ACanvasSizeX;
Drawer.Drawing.Height := ACanvasSizeY;
Drawer.Drawing.Canvas.Brush.Color := clWhite;
Drawer.Drawing.Canvas.Brush.Style := bsSolid;
Drawer.Drawing.Canvas.FillRect(0, 0, Drawer.Drawing.Width, Drawer.Drawing.Height);
if checkForceWhiteBackground.Checked then FVec.GetPageAsVectorial(0).BackgroundColor := colWhite;
if not checkForceWhiteBackground.Checked then
FVec.GetPageAsVectorial(0).DrawBackground(Drawer.Drawing.Canvas);
FVec.GetPageAsVectorial(0).Render(
Drawer.Drawing.Canvas,
ADrawerPosX,
Drawer.Drawing.Height + ADrawerPosY,
AScale,
-1 * AScale);
Drawer.Invalidate;
end;
procedure TfrmFPVViewer.Render_FreeFile;
begin
FVec.Free;
end;
end.