context: using System;
  using GeoAPI.Geometries;
  using GisSharpBlog.NetTopologySuite.Geometries;
  
  namespace GisSharpBlog.NetTopologySuite.Utilities
  {
      /// <summary>
      /// Computes various kinds of common geometric shapes.
      /// Allows various ways of specifying the location and extent of the shapes,
      /// as well as number of line segments used to form them.
      /// </summary>
      public class GeometricShapeFactory
      {
          private GeometryFactory geomFact;
          private Dimensions dim = new Dimensions();
          private int nPts = 100;
  
          /// <summary>
          /// Create a shape factory which will create shapes using the default GeometryFactory.
          /// </summary>
          public GeometricShapeFactory() : this(new GeometryFactory()) { }
  
          /// <summary>
          /// Create a shape factory which will create shapes using the given GeometryFactory.
          /// </summary>
          /// <param name="geomFact">The factory to use.</param>
          public GeometricShapeFactory(GeometryFactory geomFact)
          {
              this.geomFact = geomFact;
          }
  
          /// <summary>
          /// Gets/Sets the location of the shape by specifying the base coordinate
          /// (which in most cases is the
          /// lower left point of the envelope containing the shape).
          /// </summary>
          public ICoordinate Base  
          {
              get
              {
                  return dim.Base;
              }
              set
              {
                  dim.Base = value;
              }
          }
  
          /// <summary>
          /// Gets/Sets the location of the shape by specifying the centre of
          /// the shape's bounding box.
          /// </summary>
          public ICoordinate Centre
          {
              get
              {
                  return dim.Centre;
              }
              set
              {
                  dim.Centre = value;
              }
          }
  
          /// <summary>
          /// Gets/Sets the total number of points in the created Geometry.
          /// </summary>
          public int NumPoints
          {
              get
              {
                  return nPts;
              }
              set
              {
                  nPts = value;
              }
          }
  
          /// <summary>
          /// Gets/Sets the size of the extent of the shape in both x and y directions.        
          /// </summary>                
          public double Size
          {
              get
              {
                  return dim.Size;
              }
              set
              {
                  dim.Size = value;
              }
          }
  
          /// <summary>
          /// Gets/Sets the width of the shape.
          /// </summary>
          public double Width
          {
              get
              {
                  return dim.Width;
              }
              set
              {
                  dim.Width = value;
              }
          }
  
          /// <summary>
          /// Gets/Sets the height of the shape.
          /// </summary>
          public double Height
          {
              get
              {
                  return dim.Height;
              }
              set
              {
                  dim.Height = value;
              }
          }
  
          /// <summary>
          /// Creates a rectangular <c>Polygon</c>.
          /// </summary>
          /// <returns>A rectangular polygon.</returns>
          public IPolygon CreateRectangle()
          {
              int i;
              int ipt = 0;
              int nSide = nPts / 4;
              if (nSide < 1) nSide = 1;
              double XsegLen = dim.Envelope.Width / nSide;
              double YsegLen = dim.Envelope.Height / nSide;
  
              ICoordinate[] pts = new ICoordinate[4 * nSide + 1];
              IEnvelope env = dim.Envelope;            
  
              for (i = 0; i < nSide; i++) 
              {
                  double x = env.MinX + i * XsegLen;
                  double y = env.MinY;
                  pts[ipt++] = new Coordinate(x, y);
              }
              for (i = 0; i < nSide; i++) 
              {
                  double x = env.MaxX;
                  double y = env.MinY + i * YsegLen;
                  pts[ipt++] = new Coordinate(x, y);
              }
              for (i = 0; i < nSide; i++) 
              {
                  double x = env.MaxX - i * XsegLen;
                  double y = env.MaxY;
                  pts[ipt++] = new Coordinate(x, y);
              }
              for (i = 0; i < nSide; i++) 
              {
                  double x = env.MinX;
                  double y = env.MaxY - i * YsegLen;
                  pts[ipt++] = new Coordinate(x, y);
              }
              pts[ipt++] = new Coordinate(pts[0]);
  
              ILinearRing ring = geomFact.CreateLinearRing(pts);
              IPolygon poly = geomFact.CreatePolygon(ring, null);
              return poly;
          }
  
          /// <summary>
          /// Creates a circular <c>Polygon</c>.
          /// </summary>
          /// <returns>A circular polygon.</returns>
          public IPolygon CreateCircle()
          {
              IEnvelope env = dim.Envelope;
              double xRadius = env.Width / 2.0;
              double yRadius = env.Height / 2.0;
  
              double centreX = env.MinX + xRadius;
              double centreY = env.MinY + yRadius;
  
              ICoordinate[] pts = new ICoordinate[nPts + 1];
              int iPt = 0;
              for (int i = 0; i < nPts; i++) 
              {
                  double ang = i * (2 * Math.PI / nPts);
                  double x = xRadius * Math.Cos(ang) + centreX;
                  double y = yRadius * Math.Sin(ang) + centreY;
                  ICoordinate pt = new Coordinate(x, y);
                  pts[iPt++] = pt;
              }
              pts[iPt] = pts[0];
  
              ILinearRing ring = geomFact.CreateLinearRing(pts);
              IPolygon poly = geomFact.CreatePolygon(ring, null);
              return poly;
          }
  
          /// <summary>
          /// Creates a elliptical arc, as a LineString.
          /// </summary>
          /// <param name="startAng"></param>
          /// <param name="endAng"></param>
          /// <returns></returns>
          public ILineString CreateArc(double startAng, double endAng)
          {
              IEnvelope env = dim.Envelope;
              double xRadius = env.Width / 2.0;
              double yRadius = env.Height / 2.0;
  
              double centreX = env.MinX + xRadius;
              double centreY = env.MinY + yRadius;
  
              double angSize = (endAng - startAng);
              if (angSize <= 0.0 || angSize > 2 * Math.PI)
                  angSize = 2 * Math.PI;
              double angInc = angSize / nPts;
  
              ICoordinate[] pts = new ICoordinate[nPts];
              int iPt = 0;
              for (int i = 0; i < nPts; i++) 
              {
                  double ang = startAng + i * angInc;
                  double x = xRadius * Math.Cos(ang) + centreX;
                  double y = yRadius * Math.Sin(ang) + centreY;
                  ICoordinate pt = new Coordinate(x, y);
                  geomFact.PrecisionModel.MakePrecise( pt);
                  pts[iPt++] = pt;
              }
              ILineString line = geomFact.CreateLineString(pts);
              return line;
          }
  
          /// <summary>
          /// 
          /// </summary>
          private class Dimensions
          {
              private ICoordinate basecoord;
  
              /// <summary>
              /// 
              /// </summary>
              public ICoordinate Base
              {
                  get { return basecoord; }
                  set { basecoord = value; }
              }
  
              private ICoordinate centre;
  
              /// <summary>
              /// 
              /// </summary>
              public ICoordinate Centre
              {
                  get { return centre; }
                  set { centre = value; }
              }
  
              private double width;
  
              /// <summary>
              /// 
              /// </summary>
              public double Width
              {
                  get { return width; }
                  set { width = value; }
              }
  
              private double height;
  
              /// <summary>
              /// 
              /// </summary>
              public double Height
              {
                  get { return height; }
  
gt:                 set { height = value; }