ImageEn Forum
Profile    Join    Active Topics    Forum FAQ    Search
 All Forums  ImageEn Library for Delphi, C++ and .Net  ImageEn and IEvolution Support Forum  TIECanvas: PolylineTo & PolyPolyline New Topic  Reply to Topic
Author  Topic

USA
37 Posts

 Posted - Mar 12 2022 :  17:56:50 Hello,Does TIECanvas have an equivalent for Windows.PolylineTo and Windows.PolyPolyline?If not, does someone have an example of converting these calls to Polyline or LineTo?Thank You,MFM

7028 Posts

 Posted - Mar 12 2022 :  18:09:37 HiSorry, those methods are not supported at this time.Nigel Xequte Softwarewww.imageen.com

USA
37 Posts

 Posted - Mar 15 2022 :  11:57:02 FWIW, here's the procedure I came up with to pass my existing variables to the IECanvas Polygon procedure.procedure PolyPolygonForIE(aDC: HDC; aPtArr: PPoint; aPtCount: PInteger; aPlyCount: Integer); { Draw a series of closed polygons using an array of Points, Integers (no. of pts. per polygon), and an Integer indicating the total number of polygons to draw. } var i, j: Integer; iePtsArr: array of TPoint; TmpCnv: TCanvas; ieCnv: TIECanvas; begin if (aPlyCount = 0) then Exit { Nothing to do } else if (aPtCount^ < 3) then Exit; { Not a valid polygon } { Create temporary IECanvas from Device Context } TmpCnv := TCanvas.Create; TmpCnv.Handle := aDC; ieCnv := TIECanvas.Create(TmpCnv); TmpCnv.Free; { Set unique property of ieCanvas } ieCnv.Brush.Transparency := 64; for i := 0 to Pred(aPlyCount) do begin SetLength(iePtsArr, aPtCount^); for j := 0 to Pred(aPtCount^) do begin iePtsArr[j] := aPtArr^; Inc(aPtArr); end; Inc(aPtCount); ieCnv.Polygon(iePtsArr); { Draw polygons from array one at a time } end; ieCnv.Free; end; { PolyPolygonForIE }

7028 Posts

 Posted - Mar 15 2022 :  19:55:58 Nice work Nigel Xequte Softwarewww.imageen.com

USA
37 Posts

 Posted - Mar 30 2022 :  11:44:45 Thanks Nigel. However, I've found a caveat I'm not sure how to solve yet. When I pass the points array to Windows.PolyPolygon, I believe the order of points (i.e., clockwise versus counter-clockwise) determines whether the polygon is a void.Since I'm drawing each polygon one at a time with TIECanvas.Polygon, the void areas are drawn in the same color as the filled areas.How are voids normally handled with ImageEN?

USA
37 Posts

USA
37 Posts

 Posted - Apr 03 2022 :  13:03:14 FWIW, I've been experimenting with the TImageEnView component and came up with this sequence to create and 'knockout' a polygon. procedure TForm1.KnockOutPolygon(); { Create a polygon with a knockout } var ieBmp: TIEBitmap; begin { Create 'Transparent' Layer } ieBmp := TIEBitmap.Create(512, 512, clWhite, 0); ieView.LayersAddEx(ielkImage, 0, 0, ieBmp.Width, ieBmp.Height, ieBmp, True, False, False); { New Layer } ieView.LayersAdd(ielkPolyline); { Set Fill and Boundary Properties } ieView.CurrentLayer.FillColor := clYellow; ieView.CurrentLayer.FillOpacity := 128; //ieView.CurrentLayer.BorderColor := clRed; ieView.CurrentLayer.BorderWidth := 0; { > 0 will change width/height of layer! } { Add Polygon using image coordinates } TIEPolylineLayer(ieView.CurrentLayer).SetPoints( [ Point(0, 0), Point(256, 256), Point(0, 512) ], True, iepbBitmap ); ieView.Update(); { Merge with 'Transparent' Layer } ieView.LayersMerge(ieView.LayersCurrent - 1, ieView.LayersCurrent, True); { Create 'Transparent' Layer } ieBmp := TIEBitmap.Create(512, 512, clWhite, 0); //ieView.LayersAddEx(ielkImage, -1, -1, ieBmp.Width, ieBmp.Height, ieBmp, True, False, False); ieView.LayersInsertEx(ieView.LayersCurrent + 1, ielkImage, 0{-1}, 0{-1}, ieBmp.Width, ieBmp.Height, ieBmp, True, False, False); { Create Knockout Polygon (after current layer) } ieView.LayersInsert(ieView.LayersCurrent + 1, ielkPolyline); ieView.CurrentLayer.FillColor := clBlack; ieView.CurrentLayer.BorderWidth := 0; TIEPolylineLayer(ieView.CurrentLayer).SetPoints( [ Point(24, 58), Point(222, 256), Point(24, 454) ], True, iepbBitmap ); ieView.Update(); { Merge with 'Transparent' Layer } ieView.LayersMerge(ieView.LayersCurrent - 1, ieView.LayersCurrent, True); SetCurrentLayerAsMask(); { See Layer Masking Demo } ieView.Update(); { Merge with Polygon Layer } ieView.LayersMerge(ieView.LayersCurrent - 1, ieView.LayersCurrent, True); ieView.IO.SaveToFile('C:\Users\mark\Desktop\ieView.png'); end;

USA
37 Posts

 Posted - Apr 03 2022 :  18:12:12 More Knockout Experimentation:Since the Windows.PolyPolygon routine handles knockouts, I thought I might be able to do a work-around by modifying the output from this procedure. Here's what I came up with. Unfortunately, it's not fast enough and the edges of the polygons are 'choppy', but it does work. procedure PolyPolygonForIE_New(aDC: HDC; aPtArr: PPoint; aPtCount: PInteger; aPlyCount: Integer; BrClr: TColor = 0; BrOp: Byte = 255; BmpBrush: Str255 = ''); var TmpCnv: TCanvas; ieBmp: TIEBitmap; DrawFormWidth, DrawFormHeight: Integer; begin { Create temporary from Device Context } TmpCnv := TCanvas.Create; TmpCnv.Handle := aDC; DrawFormWidth := TmpCnv.ClipRect.Right; DrawFormHeight := TmpCnv.ClipRect.Top; { Create ie bitmap, same size as Device Context } ieBmp := TIEBitmap.Create(DrawFormWidth, DrawFormHeight, ie32RGB); ieBmp.Canvas.Brush.Color := BrClr; { Draw on ie bitmap canvas using Windos.PolyPolygon } PolyPolygon(ieBmp.Canvas.Handle, aPtArr^, aPtCount^, aPlyCount); { Set opacity of draw form color to 0 } ieBmp.SetTransparentColors(DrawFormColor, DrawFormColor, 0); { Set opacity of filled area to user-defined value } ieBmp.SetTransparentColors(BrClr, BrClr, BrOp); { Merge transparent fill with knockout into background } ieBmp.RenderToCanvasWithAlpha(TmpCnv, 0, 0, DrawFormWidth, DrawFormHeight, 0, 0, DrawFormWidth, DrawFormHeight, 255, rfFastLinear, ielNormal, 1); ieBmp.Free; TmpCnv.Free; end;

7028 Posts

 Posted - Apr 03 2022 :  18:32:58 Yes, that works nicely.Image + Mask = Nigel Xequte Softwarewww.imageen.com

USA
37 Posts

 Posted - Apr 04 2022 :  11:49:50 I thought this method might be a little quicker but it's not noticeable. procedure PolyPolygonForIE_New(aDC: HDC; aPtArr: PPoint; aPtCount: PInteger; aPlyCount: Integer; BrClr: TColor = 0; BrOp: Byte = 255; BmpBrush: Str255 = ''); var TmpCnv: TCanvas; ieBmp: TIEBitmap; DrawFormWidth, DrawFormHeight: Integer; x, y: Integer; ieRGB_Df: TRGB; begin { Create temporary IECanvas from Device Context } TmpCnv := TCanvas.Create; TmpCnv.Handle := aDC; DrawFormWidth := TmpCnv.ClipRect.Right; DrawFormHeight := TmpCnv.ClipRect.Top; { Create ie bitmap, same size as Device Context } ieBmp := TIEBitmap.Create(DrawFormWidth, DrawFormHeight, ie32RGB); ieBmp.Canvas.Brush.Color := BrClr; { Draw on ie bitmap canvas using Windows.PolyPolygon } PolyPolygon(ieBmp.Canvas.Handle, aPtArr^, aPtCount^, aPlyCount); { Set opacity of DrawForm to 0 and set opacity of filled area to user-defined value } ieRGB_Df := TColor2TRGB(DrawFormColor); for y := 0 to Pred(ieBmp.Height) do begin for x := 0 to Pred(ieBmp.Width) do begin if (ieBmp.Pixels[x, y].r = ieRGB_Df.r) and (ieBmp.Pixels[x, y].g = ieRGB_Df.g) and (ieBmp.Pixels[x, y].b = ieRGB_Df.b) then ieBmp.Alpha[x, y] := 0 else ieBmp.Alpha[x, y] := BrOp; end; end; ieBmp.DrawToCanvasWithAlpha(TmpCnv, 0, 0); ieBmp.Free; TmpCnv.Free; end;

USA
37 Posts

 Posted - Apr 05 2022 :  10:13:07 I had to take the long way around the barn, but I think I've finally figured out how I can draw polygons with voids using the Windows.PolyPolygon procedure. Any ideas on how I can improve the performance of this routine would be appreciated. procedure PolyPolygonForIE_Voids(aDC: HDC; aPtArr: PPoint; aPtCount: PInteger; aPlyCount: Integer; BrClr: TColor = 0; BrOp: Byte = 255; BmpBrush: Str255 = ''); { Draw transparent polygons WITH voids using Windows PolyPolygon procedure & TIEBitmap AlphaChannel } var TmpCnv: TCanvas; aBmp: TBitmap; ieBmp: TIEBitmap; DrawFormWidth, DrawFormHeight: Integer; begin if (aPlyCount = 0) then Exit { Nothing to do } else if (aPtCount^ < 3) then Exit; { Not a valid polygon } { Create temporary canvas from Device Context } TmpCnv := TCanvas.Create; TmpCnv.Handle := aDC; DrawFormWidth := TmpCnv.ClipRect.Right; DrawFormHeight := TmpCnv.ClipRect.Top; { Create Bitmap for Alpha Channel (Mask) } aBmp := TBitmap.Create; aBmp.Canvas.Brush.Style := bsSolid; aBmp.Canvas.Brush.Color := clBlack; { Set color here before width / height } aBmp.Width := DrawFormWidth; aBmp.Height := DrawFormHeight; { Set brush color to grey value from user-defined opacity value } aBmp.Canvas.Brush.Color := RGB(BrOp, BrOp, BrOp); { Draw polygon with voids using Windows.PolyPolygon (Alpha Image) } PolyPolygon(aBmp.Canvas.Handle, aPtArr^, aPtCount^, aPlyCount); { Create 'ie' bitmap, same size as Device Context } ieBmp := TIEBitmap.Create(DrawFormWidth, DrawFormHeight, ie32RGB); { This method seems fastest } { Set compositing mode } ieBmp.IECanvas.SetCompositingMode(ieCompositingModeSourceOver, ieCompositingQualityDefault); { Assign Mask to ieBmp's Alpha Channel } ieBmp.AlphaChannel.Assign(aBmp); ieBmp.SyncAlphaChannel(True); { Set brush color to user-defined value } ieBmp.Canvas.Brush.Color := BrClr; { Draw polygon with voids using Windows.PolyPolygon (Source Image) } PolyPolygon(ieBmp.Canvas.Handle, aPtArr^, aPtCount^, aPlyCount); { Merge result onto our DrawForm canvas } ieBmp.DrawToCanvasWithAlpha(TmpCnv, 0, 0); aBmp.Free; ieBmp.Free; TmpCnv.Free; end; { PolyPolygonForIE_Voids }

7028 Posts

 Posted - Apr 05 2022 :  17:37:39 HiDoes it make any performance difference if you skip the use of the TBitmap, and just interact with TIEBitmap.AlphaChannel.Canvas? Something like (untested): procedure PolyPolygonForIE_Voids(aDC: HDC; aPtArr: PPoint; aPtCount: PInteger; aPlyCount: Integer; BrClr: TColor = 0; BrOp: Byte = 255; BmpBrush: Str255 = ''); { Draw transparent polygons WITH voids using Windows PolyPolygon procedure & TIEBitmap AlphaChannel } var TmpCnv: TCanvas; ieBmp: TIEBitmap; DrawFormWidth, DrawFormHeight: Integer; begin if (aPlyCount = 0) then Exit { Nothing to do } else if (aPtCount^ < 3) then Exit; { Not a valid polygon } { Create temporary canvas from Device Context } TmpCnv := TCanvas.Create; TmpCnv.Handle := aDC; DrawFormWidth := TmpCnv.ClipRect.Right; DrawFormHeight := TmpCnv.ClipRect.Top; { Create 'ie' bitmap, same size as Device Context } ieBmp := TIEBitmap.Create(DrawFormWidth, DrawFormHeight, ie32RGB); { This method seems fastest } { Set compositing mode } ieBmp.IECanvas.SetCompositingMode(ieCompositingModeSourceOver, ieCompositingQualityDefault); { Draw Mask to ieBmp's Alpha Channel } { Set brush color to grey value from user-defined opacity value } ieBmp.AlphaChannel.Canvas.Brush.Color := RGB(BrOp, BrOp, BrOp); { Draw polygon with voids using Windows.PolyPolygon (Alpha Image) } PolyPolygon(ieBmp.AlphaChannel.Canvas.Handle, aPtArr^, aPtCount^, aPlyCount); // Should not be needed??? // ieBmp.SyncAlphaChannel(True); { Set brush color to user-defined value } ieBmp.Canvas.Brush.Color := BrClr; { Draw polygon with voids using Windows.PolyPolygon (Source Image) } PolyPolygon(ieBmp.Canvas.Handle, aPtArr^, aPtCount^, aPlyCount); { Merge result onto our DrawForm canvas } ieBmp.DrawToCanvasWithAlpha(TmpCnv, 0, 0); aBmp.Free; ieBmp.Free; TmpCnv.Free; end; { PolyPolygonForIE_Voids } Ideally you would skip TCanvas completely and use only GDI+ methods (better performance, transparency and anti-aliasing support), but unfortunately there is not a simple equivalent PolyPolyline/PolyPolygon in GDI+You could split your PolyPolygon call into multiple TIECanvas.Polygon calls, but the void handling would be a headache.Nigel Xequte Softwarewww.imageen.com

USA
37 Posts

 Posted - Apr 06 2022 :  10:20:08 Thanks Nigel. This works but I had to add a call to ieBmp.AlphaChannel.Fill(0) after creating ieBmp. Adding a call to ieBmp.Fill(0) doesn't seem to be necessary, nor does the call to SyncAlphaChannel. I also added a call to set ieBmp.Canvas.Pen.Width to 0, otherwise a 'thin' line appears when drawing on a white background. We draw vector boundaries separately from the display list to make sure they are 'on top' of fills.Since we draw one polygon (with or without voids) one at a time, I can easily separate out the voids like this. { Convert DataCAD's point array for Polygon procedure } for i := 0 to Pred(aPlyCount) do begin { x Polygons } SetLength(iePtsArr, aPtCount^); { No. Points in curr. Polygon } for j := 0 to Pred(aPtCount^) do begin iePtsArr[j] := aPtArr^; { Array of points in curr. Polygon. } Inc(aPtArr); end; Inc(aPtCount); if (i = 0) then ieCnv.Polygon(iePtsArr) { Draw Parent Polygon } else begin { Change brush properties here } ieCnv.Polygon(iePtsArr) { Draw Voids from array one at a time } end; end; However, voids can overlap or occur outside of the parent's boundary so I'd have to figure out how to draw areas of voids outside of the parent 'positively' rather than transparently to be consistent with the way they are handled by PolyPolygon.

USA
37 Posts

 Posted - Apr 29 2022 :  05:03:23 I've come up with a faster method that solves my original problem of determining how to use Windows.PolyPolygon to draw transparent fills with (or without) voids. I'm now using my call to draw the polygon to create a clipping path/region instead. I can then simply draw a transparent rectangle over the clipping region.procedure PolyPolygonFills(aDC: HDC; aPtArr: PPoint; aPtCount: PInteger; aPlyCount: Integer; BrClr: TColor = 0; BrOp: Byte = 255; BmpBrush: Str255 = ''); { Draw transparent rectangle over clipping region using ImageEN } var i, j: Integer; ieCnv: TIECanvas; Rgn: HRGN; ClipRect: TRect; begin if (aPlyCount = 0) then Exit { Nothing to do } else if (aPtCount^ < 3) then Exit; { Not a valid polygon } BeginPath(aDC); PolyPolygon(aDC, aPtArr^, aPtCount^, aPlyCount); EndPath(aDC); Rgn := PathToRegion(aDC); SelectClipRgn(aDC, Rgn); GetClipBox(aDC, ClipRect); { Rectangular extents of clipping region / polygon } { Create 'ie' canvas from memory canvas for 'transparent' Polygon procedure } ieCnv := TIECanvas.Create(MemCnv); { Does this help? } ieCnv.SmoothingMode := iesmBestPerformance; ieCnv.Pen.Color := BrClr; ieCnv.Pen.Transparency := BrOp; ieCnv.Pen.Width := 0; { Set unique brush property for ieCanvas } ieCnv.Brush.Color := BrClr; ieCnv.Brush.Transparency := BrOp; { 0 - 255 } ieCnv.Brush.Style := bsSolid; ieCnv.Rectangle(ClipRect); { Draw transparent rectangle over clipping region } ieCnv.Free; SelectClipRgn(aDC, 0); { Clear region from canvas } if (Rgn <> 0) then DeleteObject(Rgn); end; { PolyPolygonFills }

7028 Posts

 Posted - May 01 2022 :  22:40:20 Nice. That should give you much better performance too.How is the quality? Do you need iesmAntialias for anti-aliasing?Nigel Xequte Softwarewww.imageen.com

USA
37 Posts

 Posted - May 04 2022 :  08:09:25 Yes, much faster. The quality with SmoothingMode set to iesmBestPerformance is certainly acceptable on screen. I'll probably end up exposing this to the user so they can adjust it if they want to.
Topic
 New Topic  Reply to Topic Jump To: Select Forum ImageEn Library for Delphi, C++ and .Net       ImageEn and IEvolution Support Forum  -------------------- Home Active Topics Frequently Asked Questions Member Information Search Page