ThinkGeo.com    |     Blog    |     Wiki    |     Support

How to get a point on a polygon (surface)?

I have polygon and need to find a point that is contained inside the polygon. I cannot use the centroid as I have some C shaped polygons where the centroid is not inside the polygon.

In other libraries there is something like “GetPointOnSurface” for polygons. How do I accomplish this using ThinkGeo?
Thanks.

Regards,
Peter

Hi Peter,

If you have the point and the polygon, you can just adjust whether the point is contained by the polygon like this:

        PointShape point;
        PolygonShape polygon;

        bool isContains = polygon.Contains(point);

Please let me know whether I understand your requirement correct. If you have a lot of polygons, you can build a simple function and loop all polygons for this.

If your polygons is in the same layer, here I just put an inmemory feature layer as example, you can do it like this:

        InMemoryFeatureLayer layer;
        layer.Open();
        layer.QueryTools.GetFeaturesContaining(yourPointShape, ReturningColumnsType.AllColumns);

Regards,

Ethan

Hi Ethan,

thank you for your fast answer.
Unfortunately I do not have the point yet.

I really need to find/create a new point that is inside of a given polygon. The centroid won’t do it, because the polygons can have holes or be e.g. C shaped.

Regards,
Peter

Hi Peter,

I think I understand your requirement, you have a polygon and want to calculate a random interior point of it, does that correct?

We don’t have an exsiting api for that, but I think you can write custom function for it.

I tried to find one algorithm about that but failed, I will takes more time to help you on it tomorrow, any news I will update here. And if you have known algorithm please paste here, I can parse that into our code.

Regards,

Ethan

Hi Ethan,

you’re right. That is absolutely what I’m trying to do.

The automatic label positioning in your styles does not satisfy my customer. Therefore I’m trying to do my own label positioning.

The only way to currently achieve this is to use a functionality of NTS. But I would really love to get rid of the conversion overhead.

private static PointShape GetPointOnSurface(BaseShape shape)
{
      // convert ThinkGeo shape to NTS geometry
      byte[] shapeWKB = shape.GetWellKnownBinary();
      WKBReader reader = new WKBReader();
      GeoAPI.Geometries.IGeometry geometry = (GeoAPI.Geometries.IGeometry)reader.Read(shapeWKB);
    
      // retrieve the new point through NTS
      ICoordinate x = geometry.PointOnSurface.Coordinate;

      // return new ThinkGeo point 
      return new PointShape(x.X, x.Y);
}

The results on the other hand are much better than your label positioning. I’ll try to post a comparison after this post.

Regards,
Peter

Hi Peter,

I double check all logic and it looks our API don’t support a feature the same as PointOnSurface.

About performance I think any other algorithm will have the same problem. In fact we also use NTS when did spatial query, generally I think you don’t need to worry about the conversion overhead, but if you make sure it reduce the performance, you can did a pre-build process.

For example you can build a function named BuildPointOnSurface, then just loop all features once, calculate the label position, save the result to feature.ColumnValues, when you want to label it, you just need read the position value from column values but don’t need to calculate it again.

Wish that’s helpful.

Regards,

Ethan

Hi Ethan,

thank you very much for the hint about using the ColumnValues to store the result. I will certainly do this, so the positions do not have to be calculated at every map change.

How do you in your libraries convert between the ThinkGeo objects to the NTS objects?

Regards,
Peter

Hi Peter,

Just like your code did, but just like you mentioned, we won’t call SpatialQuery all the time, but in your logic we need to calculate the position each time the map pan or zoom, so I am glad to hear that’s helpful.

Regards,

Ethan

1 Like