HighTechTalks DotNet Forums  

Understanding GDI+ Transfomations (or not)

Dotnet Framework (Drawing) microsoft.public.dotnet.framework.drawing


Discuss Understanding GDI+ Transfomations (or not) in the Dotnet Framework (Drawing) forum.



Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old   
Stephany Young
 
Posts: n/a

Default Understanding GDI+ Transfomations (or not) - 12-31-2007 , 07:43 PM






I am having trouble, I think, dealing with GDI+ transformations.

I have read all that I can find on the subject, (including Bob Powell's
excellent FAQ and primer), but I appear to be missing some fundamental or I
just don't get it.

What I am attempting to do is illustrated in the VB.NET code shown below,
but can be summarised as follows:

The coordinates for 2 polygons are specified in metres. For those who are
really interested they are actually in respect of the New Zealand Map Grid
projection.

The origin for both polygons is the bottom left corner.

It seems to me that I should be able to define a series of tranformations
that will do the whole job rather than having to execute a number of steps
where I have to re-process the data a number of times.

If anyone can help me to understand this better then I will be very
grateful.

The code ....

Dim m_polygons As List(Of List(Of PointF))

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
Handles Me.Load

m_polygons = New List(Of List(Of PointF))

m_polygons.Add(New List(Of PointF)(New PointF() {New PointF(2727597.42,
6106293.737), New PointF(2727652.434, 6106195.849), New PointF(2727694.003,
6106123.506), New PointF(2727763.29, 6106001.696), New PointF(2727788.363,
6105957.847), New PointF(2727798.628, 6105940.072), New PointF(2727910.42,
6106001.514), New PointF(2727993.563, 6106049.8), New PointF(2727902.583,
6106207.581), New PointF(2727810.943, 6106366.357), New PointF(2727775.272,
6106428.556), New PointF(2727690.896, 6106574.859), New PointF(2727654.082,
6106638.411), New PointF(2727646.77, 6106590.058), New PointF(2727617.795,
6106416.15), New PointF(2727610.378, 6106371.589), New PointF(2727597.42,
6106293.737)}))

m_polygons.Add(New List(Of PointF)(New PointF() {New PointF(2727597.42,
6106293.737), New PointF(2727569.482, 6106122.587), New PointF(2727548.613,
6106002.36), New PointF(2727524.538, 6105854.383), New PointF(2727516.172,
6105802.327), New PointF(2727788.363, 6105957.847), New PointF(2727763.29,
6106001.696), New PointF(2727694.003, 6106123.506), New PointF(2727652.434,
6106195.849), New PointF(2727597.42, 6106293.737)}))

End Sub

Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As
PaintEventArgs) Handles Panel1.Paint

' Construct a 'canvas' being the bounds of the target 'surface' with a 5
pixel buffer at each edge.

Dim _canvas As RectangleF = Panel1.Bounds

_canvas.Inflate(-10, -10)

' Construct a GraphicsPath object comprising the shapes to be drawn ,
using the raw data (in metres).

Dim _gp As New GraphicsPath

For Each _polygon As List(Of PointF) In m_polygons
_gp.AddPolygon(_polygon.ToArray)
Next

' Retrieve a rectangle being the bounds of the GraphicsPath object.

Dim _extent As RectangleF = _gp.GetBounds()

' Compute the 'scale factor' being the number of pixels required to
represent 1 metre.
' This must take into account the orientation of both the 'canvas' and
the GraphicsPath object.

Dim _scalefactor As Single = Math.Min(_canvas.Width / _extent.Width,
_canvas.Height / _extent.Height)

' Now scale the raw data using the computed 'scale factor' and construct
a new GraphicsPath object.

Dim _polygons As New List(Of List(Of PointF))

_gp = New GraphicsPath

For Each _polygon As List(Of PointF) In m_polygons
Dim _newpolygon As New List(Of PointF)
For Each _pointf As PointF In _polygon
_newpolygon.Add(New PointF(_pointf.X * _scalefactor, _pointf.Y *
_scalefactor))
Next
_polygons.Add(_newpolygon)
_gp.AddPolygon(_newpolygon.ToArray)
Next

' Retrieve a rectangle being the bounds of the new GraphicsPath object.

_extent = _gp.GetBounds()

' 'Move' the center of the graphics viewport so that the GraphicsPath
object is centered in the target 'surface'.

e.Graphics.TranslateTransform((Panel1.Width - _extent.Width) / 2,
(Panel1.Height - _extent.Height) / 2)

' Now 'move' the data relative to the viewport and construct a new
GraphicsPath object.

_gp = New GraphicsPath

For Each _polygon As List(Of PointF) In _polygons
For _i As Integer = 0 To _polygon.Count - 1
_polygon(_i) = New PointF(_polygon(_i).X - _extent.X,
_polygon(_i).Y - _extent.Y)
Next
_gp.AddPolygon(_polygon.ToArray)
Next

' The 'origin' of the raw data is the lower left corner rather than the
top left corner.
' The new GraphicsPath object needs to have the Y axis reversed so that
it is the right way up.
' It is imperative that only the data is affected and not the 'canvas'
itself.

_gp.Transform(New Matrix(1, 0, 0, -1, 0, _extent.Height))

' Finally, draw the GraphicsPath object.

Using _pen As New Pen(Color.Black)
e.Graphics.DrawPath(_pen, _gp)
End Using

_gp.Dispose()

End Sub

Private Sub Panel1_Resize(ByVal sender As Object, ByVal e As EventArgs)
Handles Panel1.Resize

Panel1.Invalidate()

End Sub

.....


Reply With Quote
  #2  
Old   
Bob Powell [MVP]
 
Posts: n/a

Default Re: Understanding GDI+ Transfomations (or not) - 01-03-2008 , 10:03 AM






Hi Stephany,
I had a play with this (albeit in C#) is this the sort of thing you want to
do?

Bob.

(code after my sig)

--
--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.

---------------------------------------------------------------------------

public partial class Form1 : Form

{

List<List<PointF>> polys=new List<List<PointF>>();

List<GraphicsPath> paths = new List<GraphicsPath>();

public Form1()

{

InitializeComponent();

this.SetStyle(ControlStyles.ResizeRedraw, true);

List<PointF> poly1 =

new List<PointF>(new PointF[]{

new PointF(10000f,10000f),

new PointF(110000f,10000f),

new PointF(110000f,110000f),

new PointF(10000f,110000f),

new PointF(10000f,10000f)

});

//polys.Add(poly1);


poly1=new List<PointF>(new PointF[]{

new PointF(2727597.42f, 6106293.737f),

new PointF(2727652.434f, 6106195.849f),

new PointF(2727694.003f, 6106123.506f),

new PointF(2727763.29f, 6106001.696f),

new PointF(2727788.363f, 6105957.847f),

new PointF(2727798.628f, 6105940.072f),

new PointF(2727910.42f, 6106001.514f),

new PointF(2727993.563f, 6106049.8f),

new PointF(2727902.583f, 6106207.581f),

new PointF(2727810.943f, 6106366.357f),

new PointF(2727775.272f, 6106428.556f),

new PointF(2727690.896f, 6106574.859f),

new PointF(2727654.082f, 6106638.411f),

new PointF(2727646.77f, 6106590.058f),

new PointF(2727617.795f, 6106416.15f),

new PointF(2727610.378f, 6106371.589f),

new PointF(2727597.42f, 6106293.737f)});

polys.Add(poly1);

poly1 = new List<PointF>(new PointF[]{

new PointF(2727597.42f, 6106293.737f),

new PointF(2727569.482f, 6106122.587f),

new PointF(2727548.613f, 6106002.36f),

new PointF(2727524.538f, 6105854.383f),

new PointF(2727516.172f, 6105802.327f),

new PointF(2727788.363f, 6105957.847f),

new PointF(2727763.29f, 6106001.696f),

new PointF(2727694.003f, 6106123.506f),

new PointF(2727652.434f, 6106195.849f),

new PointF(2727597.42f, 6106293.737f)});

polys.Add(poly1);

foreach (List<PointF> poly in polys)

{

GraphicsPath gp = new GraphicsPath();

gp.AddPolygon(poly.ToArray());

paths.Add(gp);

}

}

protected override void OnPaint(PaintEventArgs e)

{

RectangleF pathbounds = paths[0].GetBounds();

foreach (GraphicsPath pth in this.paths)

{

pathbounds = RectangleF.Union(pathbounds, pth.GetBounds());

}

Matrix transform = new Matrix(1,0,0,-1,0,this.ClientRectangle.Height);
//reverse the Y axis

transform.Scale(0.8f*(float)ClientRectangle.Width/pathbounds.Width,
0.8f*(float)ClientRectangle.Width/pathbounds.Width,MatrixOrder.Prepend);


transform.Translate(-pathbounds.X, -pathbounds.Y, MatrixOrder.Prepend);


e.Graphics.Transform = transform;

Random r=new Random();

foreach (GraphicsPath pth in this.paths)

{

e.Graphics.FillPath(new
SolidBrush(Color.FromArgb(r.Next(255),r.Next(255), r.Next(255))), pth);

}

base.OnPaint(e);

}

}



"Stephany Young" <noone@localhost> wrote

Quote:
I am having trouble, I think, dealing with GDI+ transformations.

I have read all that I can find on the subject, (including Bob Powell's
excellent FAQ and primer), but I appear to be missing some fundamental or
I just don't get it.

What I am attempting to do is illustrated in the VB.NET code shown below,
but can be summarised as follows:

The coordinates for 2 polygons are specified in metres. For those who are
really interested they are actually in respect of the New Zealand Map Grid
projection.

The origin for both polygons is the bottom left corner.

It seems to me that I should be able to define a series of tranformations
that will do the whole job rather than having to execute a number of steps
where I have to re-process the data a number of times.

If anyone can help me to understand this better then I will be very
grateful.

The code ....

Dim m_polygons As List(Of List(Of PointF))

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
Handles Me.Load

m_polygons = New List(Of List(Of PointF))

m_polygons.Add(New List(Of PointF)(New PointF() {New PointF(2727597.42,
6106293.737), New PointF(2727652.434, 6106195.849), New
PointF(2727694.003, 6106123.506), New PointF(2727763.29, 6106001.696), New
PointF(2727788.363, 6105957.847), New PointF(2727798.628, 6105940.072),
New PointF(2727910.42, 6106001.514), New PointF(2727993.563, 6106049.8),
New PointF(2727902.583, 6106207.581), New PointF(2727810.943,
6106366.357), New PointF(2727775.272, 6106428.556), New
PointF(2727690.896, 6106574.859), New PointF(2727654.082, 6106638.411),
New PointF(2727646.77, 6106590.058), New PointF(2727617.795, 6106416.15),
New PointF(2727610.378, 6106371.589), New PointF(2727597.42,
6106293.737)}))

m_polygons.Add(New List(Of PointF)(New PointF() {New PointF(2727597.42,
6106293.737), New PointF(2727569.482, 6106122.587), New
PointF(2727548.613, 6106002.36), New PointF(2727524.538, 6105854.383), New
PointF(2727516.172, 6105802.327), New PointF(2727788.363, 6105957.847),
New PointF(2727763.29, 6106001.696), New PointF(2727694.003, 6106123.506),
New PointF(2727652.434, 6106195.849), New PointF(2727597.42,
6106293.737)}))

End Sub

Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As
PaintEventArgs) Handles Panel1.Paint

' Construct a 'canvas' being the bounds of the target 'surface' with a
5 pixel buffer at each edge.

Dim _canvas As RectangleF = Panel1.Bounds

_canvas.Inflate(-10, -10)

' Construct a GraphicsPath object comprising the shapes to be drawn ,
using the raw data (in metres).

Dim _gp As New GraphicsPath

For Each _polygon As List(Of PointF) In m_polygons
_gp.AddPolygon(_polygon.ToArray)
Next

' Retrieve a rectangle being the bounds of the GraphicsPath object.

Dim _extent As RectangleF = _gp.GetBounds()

' Compute the 'scale factor' being the number of pixels required to
represent 1 metre.
' This must take into account the orientation of both the 'canvas' and
the GraphicsPath object.

Dim _scalefactor As Single = Math.Min(_canvas.Width / _extent.Width,
_canvas.Height / _extent.Height)

' Now scale the raw data using the computed 'scale factor' and
construct a new GraphicsPath object.

Dim _polygons As New List(Of List(Of PointF))

_gp = New GraphicsPath

For Each _polygon As List(Of PointF) In m_polygons
Dim _newpolygon As New List(Of PointF)
For Each _pointf As PointF In _polygon
_newpolygon.Add(New PointF(_pointf.X * _scalefactor, _pointf.Y *
_scalefactor))
Next
_polygons.Add(_newpolygon)
_gp.AddPolygon(_newpolygon.ToArray)
Next

' Retrieve a rectangle being the bounds of the new GraphicsPath object.

_extent = _gp.GetBounds()

' 'Move' the center of the graphics viewport so that the GraphicsPath
object is centered in the target 'surface'.

e.Graphics.TranslateTransform((Panel1.Width - _extent.Width) / 2,
(Panel1.Height - _extent.Height) / 2)

' Now 'move' the data relative to the viewport and construct a new
GraphicsPath object.

_gp = New GraphicsPath

For Each _polygon As List(Of PointF) In _polygons
For _i As Integer = 0 To _polygon.Count - 1
_polygon(_i) = New PointF(_polygon(_i).X - _extent.X,
_polygon(_i).Y - _extent.Y)
Next
_gp.AddPolygon(_polygon.ToArray)
Next

' The 'origin' of the raw data is the lower left corner rather than the
top left corner.
' The new GraphicsPath object needs to have the Y axis reversed so that
it is the right way up.
' It is imperative that only the data is affected and not the 'canvas'
itself.

_gp.Transform(New Matrix(1, 0, 0, -1, 0, _extent.Height))

' Finally, draw the GraphicsPath object.

Using _pen As New Pen(Color.Black)
e.Graphics.DrawPath(_pen, _gp)
End Using

_gp.Dispose()

End Sub

Private Sub Panel1_Resize(ByVal sender As Object, ByVal e As EventArgs)
Handles Panel1.Resize

Panel1.Invalidate()

End Sub

....



Reply With Quote
  #3  
Old   
Stephany Young
 
Posts: n/a

Default Re: Understanding GDI+ Transfomations (or not) - 01-03-2008 , 06:39 PM



Thank you for taking the time to look at that Bob.

Yes, that cetrainly puts me on the right track.

I can see that the secret is to construct the parts of the transformation
correctly and then make sure that they are applied in the correct sequence.

Maybe I should have paid more attention in Maths class at school instead of
daydreaming about boys


"Bob Powell [MVP]" <bob (AT) spamkillerbobpowell (DOT) net> wrote

Quote:
Hi Stephany,
I had a play with this (albeit in C#) is this the sort of thing you want
to do?

Bob.

(code after my sig)

--
--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.

---------------------------------------------------------------------------

public partial class Form1 : Form

{

List<List<PointF>> polys=new List<List<PointF>>();

List<GraphicsPath> paths = new List<GraphicsPath>();

public Form1()

{

InitializeComponent();

this.SetStyle(ControlStyles.ResizeRedraw, true);

List<PointF> poly1 =

new List<PointF>(new PointF[]{

new PointF(10000f,10000f),

new PointF(110000f,10000f),

new PointF(110000f,110000f),

new PointF(10000f,110000f),

new PointF(10000f,10000f)

});

//polys.Add(poly1);


poly1=new List<PointF>(new PointF[]{

new PointF(2727597.42f, 6106293.737f),

new PointF(2727652.434f, 6106195.849f),

new PointF(2727694.003f, 6106123.506f),

new PointF(2727763.29f, 6106001.696f),

new PointF(2727788.363f, 6105957.847f),

new PointF(2727798.628f, 6105940.072f),

new PointF(2727910.42f, 6106001.514f),

new PointF(2727993.563f, 6106049.8f),

new PointF(2727902.583f, 6106207.581f),

new PointF(2727810.943f, 6106366.357f),

new PointF(2727775.272f, 6106428.556f),

new PointF(2727690.896f, 6106574.859f),

new PointF(2727654.082f, 6106638.411f),

new PointF(2727646.77f, 6106590.058f),

new PointF(2727617.795f, 6106416.15f),

new PointF(2727610.378f, 6106371.589f),

new PointF(2727597.42f, 6106293.737f)});

polys.Add(poly1);

poly1 = new List<PointF>(new PointF[]{

new PointF(2727597.42f, 6106293.737f),

new PointF(2727569.482f, 6106122.587f),

new PointF(2727548.613f, 6106002.36f),

new PointF(2727524.538f, 6105854.383f),

new PointF(2727516.172f, 6105802.327f),

new PointF(2727788.363f, 6105957.847f),

new PointF(2727763.29f, 6106001.696f),

new PointF(2727694.003f, 6106123.506f),

new PointF(2727652.434f, 6106195.849f),

new PointF(2727597.42f, 6106293.737f)});

polys.Add(poly1);

foreach (List<PointF> poly in polys)

{

GraphicsPath gp = new GraphicsPath();

gp.AddPolygon(poly.ToArray());

paths.Add(gp);

}

}

protected override void OnPaint(PaintEventArgs e)

{

RectangleF pathbounds = paths[0].GetBounds();

foreach (GraphicsPath pth in this.paths)

{

pathbounds = RectangleF.Union(pathbounds, pth.GetBounds());

}

Matrix transform = new Matrix(1,0,0,-1,0,this.ClientRectangle.Height);
//reverse the Y axis

transform.Scale(0.8f*(float)ClientRectangle.Width/pathbounds.Width,
0.8f*(float)ClientRectangle.Width/pathbounds.Width,MatrixOrder.Prepend);


transform.Translate(-pathbounds.X, -pathbounds.Y, MatrixOrder.Prepend);


e.Graphics.Transform = transform;

Random r=new Random();

foreach (GraphicsPath pth in this.paths)

{

e.Graphics.FillPath(new
SolidBrush(Color.FromArgb(r.Next(255),r.Next(255), r.Next(255))), pth);

}

base.OnPaint(e);

}

}



"Stephany Young" <noone@localhost> wrote in message
news:evohzeBTIHA.6060 (AT) TK2MSFTNGP05 (DOT) phx.gbl...
I am having trouble, I think, dealing with GDI+ transformations.

I have read all that I can find on the subject, (including Bob Powell's
excellent FAQ and primer), but I appear to be missing some fundamental or
I just don't get it.

What I am attempting to do is illustrated in the VB.NET code shown below,
but can be summarised as follows:

The coordinates for 2 polygons are specified in metres. For those who are
really interested they are actually in respect of the New Zealand Map
Grid projection.

The origin for both polygons is the bottom left corner.

It seems to me that I should be able to define a series of tranformations
that will do the whole job rather than having to execute a number of
steps where I have to re-process the data a number of times.

If anyone can help me to understand this better then I will be very
grateful.

The code ....

Dim m_polygons As List(Of List(Of PointF))

Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs)
Handles Me.Load

m_polygons = New List(Of List(Of PointF))

m_polygons.Add(New List(Of PointF)(New PointF() {New
PointF(2727597.42, 6106293.737), New PointF(2727652.434, 6106195.849),
New PointF(2727694.003, 6106123.506), New PointF(2727763.29,
6106001.696), New PointF(2727788.363, 6105957.847), New
PointF(2727798.628, 6105940.072), New PointF(2727910.42, 6106001.514),
New PointF(2727993.563, 6106049.8), New PointF(2727902.583, 6106207.581),
New PointF(2727810.943, 6106366.357), New PointF(2727775.272,
6106428.556), New PointF(2727690.896, 6106574.859), New
PointF(2727654.082, 6106638.411), New PointF(2727646.77, 6106590.058),
New PointF(2727617.795, 6106416.15), New PointF(2727610.378,
6106371.589), New PointF(2727597.42, 6106293.737)}))

m_polygons.Add(New List(Of PointF)(New PointF() {New
PointF(2727597.42, 6106293.737), New PointF(2727569.482, 6106122.587),
New PointF(2727548.613, 6106002.36), New PointF(2727524.538,
6105854.383), New PointF(2727516.172, 6105802.327), New
PointF(2727788.363, 6105957.847), New PointF(2727763.29, 6106001.696),
New PointF(2727694.003, 6106123.506), New PointF(2727652.434,
6106195.849), New PointF(2727597.42, 6106293.737)}))

End Sub

Private Sub Panel1_Paint(ByVal sender As Object, ByVal e As
PaintEventArgs) Handles Panel1.Paint

' Construct a 'canvas' being the bounds of the target 'surface' with a
5 pixel buffer at each edge.

Dim _canvas As RectangleF = Panel1.Bounds

_canvas.Inflate(-10, -10)

' Construct a GraphicsPath object comprising the shapes to be drawn ,
using the raw data (in metres).

Dim _gp As New GraphicsPath

For Each _polygon As List(Of PointF) In m_polygons
_gp.AddPolygon(_polygon.ToArray)
Next

' Retrieve a rectangle being the bounds of the GraphicsPath object.

Dim _extent As RectangleF = _gp.GetBounds()

' Compute the 'scale factor' being the number of pixels required to
represent 1 metre.
' This must take into account the orientation of both the 'canvas' and
the GraphicsPath object.

Dim _scalefactor As Single = Math.Min(_canvas.Width / _extent.Width,
_canvas.Height / _extent.Height)

' Now scale the raw data using the computed 'scale factor' and
construct a new GraphicsPath object.

Dim _polygons As New List(Of List(Of PointF))

_gp = New GraphicsPath

For Each _polygon As List(Of PointF) In m_polygons
Dim _newpolygon As New List(Of PointF)
For Each _pointf As PointF In _polygon
_newpolygon.Add(New PointF(_pointf.X * _scalefactor, _pointf.Y *
_scalefactor))
Next
_polygons.Add(_newpolygon)
_gp.AddPolygon(_newpolygon.ToArray)
Next

' Retrieve a rectangle being the bounds of the new GraphicsPath
object.

_extent = _gp.GetBounds()

' 'Move' the center of the graphics viewport so that the GraphicsPath
object is centered in the target 'surface'.

e.Graphics.TranslateTransform((Panel1.Width - _extent.Width) / 2,
(Panel1.Height - _extent.Height) / 2)

' Now 'move' the data relative to the viewport and construct a new
GraphicsPath object.

_gp = New GraphicsPath

For Each _polygon As List(Of PointF) In _polygons
For _i As Integer = 0 To _polygon.Count - 1
_polygon(_i) = New PointF(_polygon(_i).X - _extent.X,
_polygon(_i).Y - _extent.Y)
Next
_gp.AddPolygon(_polygon.ToArray)
Next

' The 'origin' of the raw data is the lower left corner rather than
the top left corner.
' The new GraphicsPath object needs to have the Y axis reversed so
that it is the right way up.
' It is imperative that only the data is affected and not the 'canvas'
itself.

_gp.Transform(New Matrix(1, 0, 0, -1, 0, _extent.Height))

' Finally, draw the GraphicsPath object.

Using _pen As New Pen(Color.Black)
e.Graphics.DrawPath(_pen, _gp)
End Using

_gp.Dispose()

End Sub

Private Sub Panel1_Resize(ByVal sender As Object, ByVal e As EventArgs)
Handles Panel1.Resize

Panel1.Invalidate()

End Sub

....




Reply With Quote
Reply




Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.