context: // ********************************************************************************************************
  // Product Name: DotSpatial.Data.dll
  // Description:  The data access libraries for the DotSpatial project.
  // ********************************************************************************************************
  // The contents of this file are subject to the MIT License (MIT)
  // you may not use this file except in compliance with the License. You may obtain a copy of the License at
  // http://dotspatial.codeplex.com/license
  //
  // Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
  // ANY KIND, either expressed or implied. See the License for the specific language governing rights and
  // limitations under the License.
  //
  // The Original Code is from MapWindow.dll version 6.0
  //
  // The Initial Developer of this Original Code is Ted Dunsford. Created 4/16/2009 12:11:19 PM
  //
  // Contributor(s): (Open source contributors should list themselves and their modifications here).
  //
  // ********************************************************************************************************
  
  using System.Collections.Generic;
  using System.Data;
  using DotSpatial.Topology;
  
  namespace DotSpatial.Data
  {
      /// <summary>
      /// Extension Methods for the Features
      /// </summary>
      public static class FeatureExt
      {
          /// <summary>
          /// Calculates the area of the geometric portion of this feature.  This is 0 unless the feature
          /// is a polygon, or multi-polygon.
          /// </summary>
          /// <param name="self">The feature to test</param>
          /// <returns>The double valued area</returns>
          public static double Area(this IFeature self)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).Area;
          }
  
          /// <summary>
          /// Generates a new feature from the buffer of this feature.  The DataRow of
          /// the new feature will be null.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="distance">The double distance</param>
          /// <returns>An IFeature representing the output from the buffer operation</returns>
          public static IFeature Buffer(this IFeature self, double distance)
          {
              IGeometry g = Geometry.FromBasicGeometry(self.BasicGeometry).Buffer(distance);
              return new Feature(g);
          }
  
          /// <summary>
          /// Generates a new feature from the buffer of this feature.  The DataRow of
          /// the new feature will be null.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="distance">The double distance</param>
          /// <param name="endCapStyle">The end cap style to use</param>
          /// <returns>An IFeature representing the output from the buffer operation</returns>
          public static IFeature Buffer(this IFeature self, double distance, BufferStyle endCapStyle)
          {
              IGeometry g = Geometry.FromBasicGeometry(self.BasicGeometry).Buffer(distance, endCapStyle);
              return new Feature(g);
          }
  
          /// <summary>
          /// Generates a new feature from the buffer of this feature.  The DataRow of
          /// the new feature will be null.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="distance">The double distance</param>
          /// <param name="quadrantSegments">The number of segments to use to approximate a quadrant of a circle</param>
          /// <returns>An IFeature representing the output from the buffer operation</returns>
          public static IFeature Buffer(this IFeature self, double distance, int quadrantSegments)
          {
              IGeometry g = Geometry.FromBasicGeometry(self.BasicGeometry).Buffer(distance, quadrantSegments);
              return new Feature(g);
          }
  
          /// <summary>
          /// Generates a new feature from the buffer of this feature.  The DataRow of
          /// the new feature will be null.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="distance">The double distance</param>
          /// <param name="quadrantSegments">The number of segments to use to approximate a quadrant of a circle</param>
          /// <param name="endCapStyle">The end cap style to use</param>
          /// <returns>An IFeature representing the output from the buffer operation</returns>
          public static IFeature Buffer(this IFeature self, double distance, int quadrantSegments, BufferStyle endCapStyle)
          {
              IGeometry g = Geometry.FromBasicGeometry(self.BasicGeometry).Buffer(distance, quadrantSegments, endCapStyle);
              return new Feature(g);
          }
  
          /// <summary>
          /// Generates a buffer, but also adds the newly created feature to the specified output featureset.
          /// This will also compare the field names of the input featureset with the destination featureset.
          /// If a column name exists in both places, it will copy those values to the destination featureset.
          /// </summary>
          /// <param name="self">The feature to calcualate the buffer for.</param>
          /// <param name="distance">The double distance to use for calculating the buffer</param>
          /// <param name="destinationFeatureset">The output featureset to add this feature to and use
          /// as a reference for determining which data columns to copy.</param>
          /// <returns>The IFeature that represents the buffer feature.</returns>
          public static IFeature Buffer(this IFeature self, double distance, IFeatureSet destinationFeatureset)
          {
              IFeature f = Buffer(self, distance);
              destinationFeatureset.Features.Add(f);
              foreach (DataColumn dc in destinationFeatureset.DataTable.Columns)
              {
                  if (self.DataRow[dc.ColumnName] != null)
                  {
                      f.DataRow[dc.ColumnName] = self.DataRow[dc.ColumnName];
                  }
              }
              return f;
          }
  
          /// <summary>
          /// Generates a buffer, but also adds the newly created feature to the specified output featureset.
          /// This will also compare the field names of the input featureset with the destination featureset.
          /// If a column name exists in both places, it will copy those values to the destination featureset.
          /// </summary>
          /// <param name="self">The feature to calcualate the buffer for.</param>
          /// <param name="distance">The double distance to use for calculating the buffer</param>
          /// <param name="endCapStyle">The end cap style to use</param>
          /// <param name="destinationFeatureset">The output featureset to add this feature to and use
          /// as a reference for determining which data columns to copy.</param>
          /// <returns>The IFeature that represents the buffer feature.</returns>
          public static IFeature Buffer(this IFeature self, double distance, BufferStyle endCapStyle, IFeatureSet destinationFeatureset)
          {
              IFeature f = Buffer(self, distance, endCapStyle);
              destinationFeatureset.Features.Add(f);
              foreach (DataColumn dc in destinationFeatureset.DataTable.Columns)
              {
                  if (self.DataRow[dc.ColumnName] != null)
                  {
                      f.DataRow[dc.ColumnName] = self.DataRow[dc.ColumnName];
                  }
              }
              return f;
          }
  
          /// <summary>
          /// Generates a buffer, but also adds the newly created feature to the specified output featureset.
          /// This will also compare the field names of the input featureset with the destination featureset.
          /// If a column name exists in both places, it will copy those values to the destination featureset.
          /// </summary>
          /// <param name="self">The feature to calcualate the buffer for.</param>
          /// <param name="distance">The double distance to use for calculating the buffer</param>
          /// <param name="quadrantSegments">The number of segments to use to approximate a quadrant of a circle</param>
          /// <param name="destinationFeatureset">The output featureset to add this feature to and use
          /// as a reference for determining which data columns to copy.</param>
          /// <returns>The IFeature that represents the buffer feature.</returns>
          public static IFeature Buffer(this IFeature self, double distance, int quadrantSegments, IFeatureSet destinationFeatureset)
          {
              IFeature f = Buffer(self, distance, quadrantSegments);
              destinationFeatureset.Features.Add(f);
              foreach (DataColumn dc in destinationFeatureset.DataTable.Columns)
              {
                  if (self.DataRow[dc.ColumnName] != null)
                  {
                      f.DataRow[dc.ColumnName] = self.DataRow[dc.ColumnName];
                  }
              }
              return f;
          }
  
          /// <summary>
          /// Generates a buffer, but also adds the newly created feature to the specified output featureset.
          /// This will also compare the field names of the input featureset with the destination featureset.
          /// If a column name exists in both places, it will copy those values to the destination featureset.
          /// </summary>
          /// <param name="self">The feature to calcualate the buffer for.</param>
          /// <param name="distance">The double distance to use for calculating the buffer</param>
          /// <param name="quadrantSegments">The number of segments to use to approximate a quadrant of a circle</param>
          /// <param name="endCapStyle">The end cap style to use</param>
          /// <param name="destinationFeatureset">The output featureset to add this feature to and use
          /// as a reference for determining which data columns to copy.</param>
          /// <returns>The IFeature that represents the buffer feature.</returns>
          public static IFeature Buffer(this IFeature self, double distance, int quadrantSegments, BufferStyle endCapStyle, IFeatureSet destinationFeatureset)
          {
              IFeature f = Buffer(self, distance, quadrantSegments, endCapStyle);
              destinationFeatureset.Features.Add(f);
              foreach (DataColumn dc in destinationFeatureset.DataTable.Columns)
              {
                  if (self.DataRow[dc.ColumnName] != null)
                  {
                      f.DataRow[dc.ColumnName] = self.DataRow[dc.ColumnName];
                  }
              }
              return f;
          }
  
          /// <summary>
          /// Returns a feature constructed from the centroid of this feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <returns>An IFeature that is also a point geometry</returns>
          public static IFeature Centroid(this IFeature self)
          {
              return new Feature(Geometry.FromBasicGeometry(self.BasicGeometry).Centroid);
          }
  
          /// <summary>
          /// Gets a boolean that is true if this feature contains the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The other feature to test</param>
          /// <returns>Boolean, true if this feature contains the other feature</returns>
          public static bool Contains(this IFeature self, IFeature other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).Contains(Geometry.FromBasicGeometry(other.BasicGeometry));
          }
  
          /// <summary>
          /// Gets a boolean that is true if this feature contains the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The other feature to test</param>
          /// <returns>Boolean, true if this feature contains the other feature</returns>
          public static bool Contains(this IFeature self, IGeometry other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).Contains(other);
          }
  
          /// <summary>
          /// Calculates a new feature that has a geometry that is the convex hull of this feature.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <returns>A new feature that is the convex hull of this feature.</returns>
          public static IFeature ConvexHull(this IFeature self)
          {
              return new Feature(Geometry.FromBasicGeometry(self.BasicGeometry).ConvexHull());
          }
  
          /// <summary>
          /// Calculates a new feature that has a geometry that is the convex hull of this feature.
          /// This also copies the attributes that are shared between this featureset and the
          /// specified destination featureset, and adds this feature to the destination featureset.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="destinationFeatureset">The destination featureset to add this feature to</param>
          /// <returns>The newly created IFeature</returns>
          public static IFeature ConvexHull(this IFeature self, IFeatureSet destinationFeatureset)
          {
              IFeature f = ConvexHull(self);
              destinationFeatureset.Features.Add(f);
              foreach (DataColumn dc in destinationFeatureset.DataTable.Columns)
              {
                  if (self.DataRow[dc.ColumnName] != null)
                  {
                      f.DataRow[dc.ColumnName] = self.DataRow[dc.ColumnName];
                  }
              }
              return f;
          }
  
          /// <summary>
          /// Gets a boolean that is true if the geometry of this feature is covered by the geometry
          /// of the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The feature to compare this feature to</param>
          /// <returns>Boolean, true if this feature is covered by the specified feature</returns>
          public static bool CoveredBy(this IFeature self, IFeature other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).CoveredBy(Geometry.FromBasicGeometry(other));
          }
  
          /// <summary>
          /// Gets a boolean that is true if the geometry of this feature is covered by the geometry
          /// of the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The feature to compare this feature to</param>
          /// <returns>Boolean, true if this feature is covered by the specified feature</returns>
          public static bool CoveredBy(this IFeature self, IGeometry other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).CoveredBy((other));
          }
  
          /// <summary>
          /// Gets a boolean that is true if the geometry of this feature covers the geometry
          /// of the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The feature to compare this feature to</param>
          /// <returns>Boolean, true if this feature covers the specified feature</returns>
          public static bool Covers(this IFeature self, IFeature other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).Covers(Geometry.FromBasicGeometry(other));
          }
  
          /// <summary>
          /// Gets a boolean that is true if the geometry of this feature covers the geometry
          /// of the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The feature to compare this feature to</param>
          /// <returns>Boolean, true if this feature covers the specified feature</returns>
          public static bool Covers(this IFeature self, IGeometry other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).Covers(other);
          }
  
          /// <summary>
          /// Gets a boolean that is true if the geometry of this feature crosses the geometry
          /// of the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The feature to compare this feature to</param>
          /// <returns>Boolean, true if this feature crosses the specified feature</returns>
          public static bool Crosses(this IFeature self, IFeature other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).Crosses(Geometry.FromBasicGeometry(other));
          }
  
          /// <summary>
          /// Gets a boolean that is true if the geometry of this feature crosses the geometry
          /// of the specified feature
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The feature to compare this feature to</param>
          /// <returns>Boolean, true if this feature crosses the specified feature</returns>
          public static bool Crosses(this IFeature self, IGeometry other)
          {
              return Geometry.FromBasicGeometry(self.BasicGeometry).Crosses(other);
          }
  
          /// <summary>
          /// Creates a new Feature that has a geometry that is the difference between this feature and the specified feature.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The other feature to compare to.</param>
          /// <returns>A new feature that is the geometric difference between this feature and the specified feature.</returns>
          public static IFeature Difference(this IFeature self, IFeature other)
          {
              if (other == null) return self.Copy();
              IGeometry g = Geometry.FromBasicGeometry(self.BasicGeometry).Difference(Geometry.FromBasicGeometry(other.BasicGeometry));
              if (g == null) return null;
              if (g.IsEmpty) return null;
              return new Feature(g);
          }
  
          /// <summary>
          /// Creates a new Feature that has a geometry that is the difference between this feature and the specified feature.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The other feature to compare to.</param>
          /// <returns>A new feature that is the geometric difference between this feature and the specified feature.</returns>
          public static IFeature Difference(this IFeature self, IGeometry other)
          {
              if (other == null) return self.Copy();
              IGeometry g = Geometry.FromBasicGeometry(self.BasicGeometry).Difference(other);
              if (g == null) return null;
              if (g.IsEmpty) return null;
              return new Feature(g);
          }
  
          /// <summary>
          /// Creates a new Feature that has a geometry that is the difference between this feature and the specified feature.
          /// This also copies the attributes that are shared between this featureset and the
          /// specified destination featureset, and adds this feature to the destination featureset.
          /// </summary>
          /// <param name="self">This feature</param>
          /// <param name="other">The other feature to compare to.</param>
          /// <param name="destinationFeatureSet">The featureset to add the new feature to.</param>
          /// <param name="joinType">This clarifies the overall join strategy being used with regards to attribute fields.</param>
          /// <returns>A new feature that is the geometric difference between this feature and the specified feature.</returns>
          public static IFeature Difference(this IFeature self, IFeature other, IFeatureSet destinationFeatureSet, FieldJoinType joinType)
          {
  
gt:             IFeature f = Difference(self, other);