Recent

Author Topic: Solved: Porting efg2 Snowflake Curve Drawer  (Read 6713 times)

Boleeman

  • Hero Member
  • *****
  • Posts: 711
Solved: Porting efg2 Snowflake Curve Drawer
« on: August 02, 2023, 04:00:23 pm »
Had a go at porting a Delphi efg2 lab Koch Snowflake Curve Drawer.
This was an old Delphi sample program I got off WebArchive

Had a couple of errors with TRect and so included Uses Windows; which fixed that problem.

Also came up with an error at

ASSERT(GetDeviceCaps(Printer.Handle, LOGPIXELSX) =
               GetDeviceCaps(Printer.handle, LOGPIXELSY)

and replaced with:

        ASSERT(GetDeviceCaps(printer.XDPI, LOGPIXELSX) =
               GetDeviceCaps(printer.YDPI, LOGPIXELSY),
               'Printer pixels are not square');

Now the code compiles but I just get a black image. What could be the possible problem?

I am not sure if I used printer.XDPI and printer.YDPI properly? I read a couple of threads which suggested to use printer.XDPI and printer.YDPI instead of Printer.Handle

The program uses a TImage named ImageVonKoch but I can't see the code where the lines are drawn to this TImage.

Thanks in advance.

« Last Edit: August 04, 2023, 06:04:32 am by Boleeman »

Thaddy

  • Hero Member
  • *****
  • Posts: 16138
  • Censorship about opinions does not belong here.
Re: Porting efg2 Snowflake Curve Drawer
« Reply #1 on: August 02, 2023, 04:17:36 pm »
Code: Pascal  [Select][+][-]
  1. ASSERT(GetDeviceCaps(Printer.Handle, LOGPIXELSX) =
  2.                GetDeviceCaps(Printer.handle, LOGPIXELSY));
Missing close ) in the code?
If I smell bad code it usually is bad code and that includes my own code.

Boleeman

  • Hero Member
  • *****
  • Posts: 711
Re: Porting efg2 Snowflake Curve Drawer
« Reply #2 on: August 02, 2023, 04:22:26 pm »
Thanks Thaddy but I

Still get a problem with Printer.handle not being recognized?


Compile Project, Target: lib\i386-win32\KochCurve.exe: Exit code 1, Errors: 2
ScreenKochCurve.pas(160,43) Error: identifier idents no member "Handle"
ScreenKochCurve.pas(161,42) Error: identifier idents no member "handle"



 I read a couple of threads which suggested to use printer.XDPI and printer.YDPI instead of Printer.Handle?

Getting late here so I will get back to the forum tomorrow (it's 12.30 am)
« Last Edit: August 02, 2023, 04:31:48 pm by Boleeman »

wp

  • Hero Member
  • *****
  • Posts: 12457
Re: Porting efg2 Snowflake Curve Drawer
« Reply #3 on: August 02, 2023, 04:32:53 pm »
This is one difference between Delphi and Lazarus: In Delphi, a bitmap is initialized filled with white color, while in Lazarus it is filled with black. Since you are setting the Pen.Color to black you are drawing black on black... Either change Pen.Color to something different from black, or fill the bitmap immediately after creating:

Code: Pascal  [Select][+][-]
  1.   PROCEDURE TFormVonKoch.DrawVonKoch;
  2.     VAR
  3.       Bitmap:  TBitmap;
  4.       Curve :  TVonKochCurve;
  5.   BEGIN
  6.     Bitmap := TBitmap.Create;
  7.     TRY
  8.       Bitmap.Width  := ImageVonKoch.Width;
  9.       Bitmap.Height := ImageVonKoch.Height;
  10.       Bitmap.PixelFormat := pf24bit;
  11.       Bitmap.Canvas.Pen.Color := clBlack;
  12.       Bitmap.Canvas.Pen.Width := 1;
  13.  
  14.       Bitmap.canvas.Brush.Color := clSilver;
  15.       Bitmap.canvas.FillRect(0, 0, Bitmap.Width, Bitmap.Height);
  16.  
  17.       Curve := TvonKochCurve.Create(Bitmap.Canvas, Bitmap.Canvas.ClipRect);    
  18. [...]

The Assert code referring to printer pixels is not correct. As Thaddy noted, you do need the Printer.Handle - but not in every Widgetset the printer has a Handle... Since you are on Windows you could add unit OSPrinters to uses, and cast the Printer to TWinPrinter: Assert(GetDeviceCaps(TWinPrinter(Printer).Handle), LOGPIXELS...). Or much butter to do it in the Lazarus way: Query the x resolution from the XDPI property of the printer, likewise with the y resolution, and compare them directly:
Code: Pascal  [Select][+][-]
  1.         Assert(printer.XDPI = printer.YDPI, 'Printer pixels are not square');

General comment on the code:
I see that your uses clause contains both Windows and LCLIntf/LCLType. This could lead to conflicts because LCLIntf and LCLType are the "same" (well: almost...) as the Windows unit but are valid for all platforms. Simply remove the Windows unit, as well as the Messages unit (the cross-platform counterpart is LMessages). However, after removal of Windows your code will not compile any more since the TRect type is no longer declared - you must add unit Types to used to fix this.

wp

  • Hero Member
  • *****
  • Posts: 12457
Re: Porting efg2 Snowflake Curve Drawer
« Reply #4 on: August 02, 2023, 04:42:58 pm »
Two more comments:
Your form comes up in the exciting style of Windows 95. If you want a modern look, like other current applications, you should check the box "Use manifest resource" in the "Project options" > "Application". And since people today have high-resolution monitors you should also check "Use LCL scaling (Hi-DPI)" and pick one of the "on" settings in the "DPI awareness" combobox on the same options page.

The other comment refers to the pixelated MS Sans Serif font which was nice at Windows 95 times but looks terribly out-dated today. Open the form in the Object Inspector, go to the Font property, set Name to "default" and "Size" to 0 - these settings make the form select the default font provided by the operating system, and this is propagated to all controls which have ParentFont = true.

Boleeman

  • Hero Member
  • *****
  • Posts: 711
Re: Porting efg2 Snowflake Curve Drawer
« Reply #5 on: August 03, 2023, 03:26:36 pm »
Many thanks WP and Thaddy for your replies. Been a bit sick with a ticklish cough/congestion, so sorry about the late reply.

"The difference between Delphi and Lazarus: In Delphi, a bitmap is initialized filled with white color, while in Lazarus it is filled with black." That explains the Black image. Wow I did not know that.

Assert(printer.XDPI = printer.YDPI, 'Printer pixels are not square');   so that is how to use printer.XDPI and printer.YDPI
I read about printer.XDPI and printer.YDPI in some threads but did not know how to implement it. I was trying all sorts of combinations and not really going in the right direction.

Your uses clause contains both Windows and LCLIntf/LCLType. This could lead to conflicts because LCLIntf and LCLType are the "same"  Thanks for the Uses Windows clause info. I Googled what to include for TRect and it suggested the Uses Windows, with Windows put at the start. you must add unit Types to used to fix this I read about that but did not understand that from the threads that I had read (until now that I get it).

The reason for playing around with the old is that it contains a unit called MapWorldToPixel which may help me with another LSystem Fractals program in which I was searching for some sort of scaling feature. Each time you increase the level of recursion of a fractal the image gets bigger so I thought of looking at what programmers did years ago to deal with the problem of an increasing size of an image.



I went through all your recommendations WP and have got a great improvement in the program. Still getting a Black image when saving to BMP so I guess there is still that  initialized filled with white color Delphi Problem in the save to BMP part (but can print to PDF).

Also: I Opened the form in the Object Inspector and went to the Font property, but could not set set Name to "default" and "Size" to 0. Could not see where to set "default"?



I was playing with the Delphi to Lazarus conversion facility in Lazarus and have been tinkering with different Delphi codes. Kinda really cool. Had problems with Delphi graphics source code containing scanline code (looks like other people have had similar problems). Anyhow the more I play around the more I learn. With your knowledge that helps to explain things a bit better. Thanks for for great help.
« Last Edit: August 03, 2023, 04:07:49 pm by Boleeman »

wp

  • Hero Member
  • *****
  • Posts: 12457
Re: Porting efg2 Snowflake Curve Drawer
« Reply #6 on: August 03, 2023, 04:35:54 pm »
I went through all your recommendations WP and have got a great improvement in the program. Still getting a Black image when saving to BMP so I guess there is still that  initialized filled with white color Delphi Problem in the save to BMP part (but can print to PDF).
Yes, it's the same story again. The button's OnClick handler creates a new bitmap which you have to fill with the background color again.

Also: I Opened the form in the Object Inspector and went to the Font property, but could not set set Name to "default" and "Size" to 0. Could not see where to set "default"?
Load the project. Make sure that the main form is selected. Click somewhere on the form where there is no control (or select the form in the tree above the property grid of the object inspector). Scroll down the property grid until you see the property "Font" in the left column. The down-arrow at the left of "Font" indicates that this property has sub-properties. Click on the arrow to drop down the sub-properties. Among them you find "Name" which is "MS Sans Serif" now. Click on the dropdown arrow at the right of "MS Sans Serif", scroll to the very top - here you can find the entry "default". Or simply click inside the name field and begin typing "default" (without quotes), press ENTER to select it. The same with the "Size" property where you simply type "0" + ENTEr.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11930
  • FPC developer.
Re: Porting efg2 Snowflake Curve Drawer
« Reply #7 on: August 03, 2023, 07:57:43 pm »
(afaik in recent versions of FPC (3.2.0+), Windows.Trect and types.trect are one and the same)

Boleeman

  • Hero Member
  • *****
  • Posts: 711
Re: Porting efg2 Snowflake Curve Drawer
« Reply #8 on: August 04, 2023, 05:50:45 am »
Thanks WP for the extra guided info. and screenshot. Got the default setting done properly now and the font setting=0.
Did not realize there was a drop down arrow to the left of Font (possibly late at night sleepiness!)
Also got the image saving to bmp properly.

Thanks Marcov for the info. as well. I have version 2.2.4 Lazarus installed. May try to install the updated version of Lazarus.

Once again thanks to all for helping me out. I learnt some new skills from this exercise which will definitely help me in other projects. I am used to programming in VB6 so the extra Lazarus hints were very much appreciated.
« Last Edit: August 04, 2023, 05:58:48 am by Boleeman »

Boleeman

  • Hero Member
  • *****
  • Posts: 711
Re: Solved: Porting efg2 Snowflake Curve Drawer
« Reply #9 on: August 04, 2023, 09:29:30 pm »
Here is the efg2 Sierpinski Triangle converted to Lazarus.

I added a line border width spinbox to make it look even better.







« Last Edit: August 05, 2023, 03:18:14 pm by Boleeman »

Boleeman

  • Hero Member
  • *****
  • Posts: 711
Re: Solved: Porting efg2 Snowflake Curve Drawer
« Reply #10 on: August 05, 2023, 01:16:41 pm »
Added a line thickness and line colour change to the original Koch Snowflake Maker.



« Last Edit: August 05, 2023, 03:18:53 pm by Boleeman »

wp

  • Hero Member
  • *****
  • Posts: 12457
Re: Solved: Porting efg2 Snowflake Curve Drawer
« Reply #11 on: August 05, 2023, 02:18:17 pm »
Added a line thickness and line colour change to the original Koch Snowflake Maker.

Unfortunately the printed version does not have the thicker line. Can't figure out why?

You are passing the same linewidth to the printer that you have on the screen. But on both devices there is a largely different resolution. With a screen solution of 97 pixels per inch a 2-pixel wide line is 2/97 inches wide (or 2/97*25.4 mm = 0.5 mm, roughly). My PDF printer runs at 1200 ppi, and the two pixels are only 2/1200*25.4 = 0,04 mm. The solution: Simply scale the linewidth that you pass to the printer-output by the ratio of resolution. Or use this function:

Code: Pascal  [Select][+][-]
  1. function PrinterPixels(ScreenPixels: Integer): Integer;
  2. begin
  3.   Result := ScreenPixels * Printer.XDPI div Screen.PixelsPerInch;
  4. end;  
  5. ...
  6.           Curve.Draw(SpinEditMaxLevel.Value,
  7.                       SpinEditNgon.Value,
  8.                       SpinEditRadius.Value,
  9.                       SpinEditRotationDegrees.Value,
  10.                       CheckBoxModified.Checked,
  11.                       ShapePenColor.Brush.Color,
  12.                       PrinterPixels(SpinEditBorderlinewidth.Value));

Boleeman

  • Hero Member
  • *****
  • Posts: 711
Re: Solved: Porting efg2 Snowflake Curve Drawer
« Reply #12 on: August 05, 2023, 03:10:21 pm »
Wow. Once again WP thanks for that help on the printing issue.

I was doing it all wrong. I tried all sorts of things but got nowhere in solving the printer issue.

Now the printing works well, thanks to your excellent advice..

I have now learnt some more interesting printer resolution things when printing.

Thanks once again WP.

Below is the expected result.

« Last Edit: August 05, 2023, 03:14:34 pm by Boleeman »

wp

  • Hero Member
  • *****
  • Posts: 12457
Re: Solved: Porting efg2 Snowflake Curve Drawer
« Reply #13 on: August 05, 2023, 03:22:56 pm »
Maybe one more note: When you look at the printout, the linewidth still maybe too thin compared to the screen display. This is because the difference in width of the paper compared to the width on the screen. On the screen, the width is ImageVonKoch.Width, on the printer it is the width of the PlotRect. Depending on the paper and the window size, both may be much different.

Therefore, if you want to have the same visual impression in both screen and printout you should not scale by pixels-per-inch but by pixelwidth of the output canvas. Try this - it results in the attached screenshot: In the foreground you see the screen output, in the background the print-out to pdf scaled such that the shapes have about the same size:

Code: Pascal  [Select][+][-]
  1.           Curve.Draw(SpinEditMaxLevel.Value,
  2.                       SpinEditNgon.Value,
  3.                       SpinEditRadius.Value,
  4.                       SpinEditRotationDegrees.Value,
  5.                       CheckBoxModified.Checked,
  6.                       ShapePenColor.Brush.Color,
  7.                       round(SpinEditBorderLineWidth.value * PlotRect.Width / ImageVonKoch.Width));    


Boleeman

  • Hero Member
  • *****
  • Posts: 711
Re: Solved: Porting efg2 Snowflake Curve Drawer
« Reply #14 on: August 05, 2023, 03:29:25 pm »
I was printing to PDF using the PDF printer in Windows and noticed the line width was a little thinner.

I am impressed with your new solution. I tried printing to a higher recursion level.

I applied the new fix to both the Koch Snowflake and the Sieripinski Triangle Maker.
Attached is the latest Koch Snowflake Drawer and a test print to pdf of the Sieripinski Triangle..

Thanks WP.

« Last Edit: August 05, 2023, 04:00:38 pm by Boleeman »

 

TinyPortal © 2005-2018