polyshape not closing a circle
8 views (last 30 days)
Show older comments
I am trying to produce circles (range rings) and plot on a geoglobe the union of the range ring circles around various geographic points (latitude, longitude pairs). To use the union function, I have to generate polyshapes. I am able to generate the polyshapes, perform the union and plot them successfully. Well, almost…
I generate the latitudes and longitudes (I’ve done it several different ways, most easily with scircle1), and even the best performing ways fail to close the polygon circle! That is, if I generate 100 lat/lon pair, with the first and last point the same (which scircle1 does), and pass them as input to polyshape, the polygon still plots with a gap (at what looks like between the last point and the first point), and there are only 99 resulting vertices. I cannot add to the vertices, since they are read-only as part of a polyshape.
The union part does combine the polyshapes properly, but because the polyshapes have that gap, there is a gap present in the union polyshape as well.
First time poster, so I apologize if any of this is unconventional or done incorrectly.
Here is sample code:
gui = uifigure;
g = geoglobe(gui,"Basemap","satellite", 'NextPlot','add');
wgs84 = wgs84Ellipsoid("nm");
lat0 = 42.3601;
lon0 = -71.0589;
r = 10;
[lat,lon] = scircle1(lat0,lon0,r,[],wgs84);
nr_pts = length(lat);
alt = 10000*ones(nr_pts,1);
alt2 = 10000*ones(nr_pts-1,1); % Account for the one less point
geoplot3(g,lat,lon,alt,"LineWidth",5) % Plot the result from scircle1
circle_poly = polyshape({lat},{lon}); % Create the polyshape
%
% It only generates 99 points
%
% I have tried variations of "Simplify" and "KeepCollinearPoints" with no
% apparent effect
%
c_lat = circle_poly.Vertices(:,1);
c_lon = circle_poly.Vertices(:,2);
geoplot3(g,c_lat,c_lon,alt2,"Color","y","LineWidth",1) % Plot the vertices of the polyshape
%
% I have not included the union code, since it appears the problem is with
% the creation of the polyshape.
%
Accepted Answer
Matt J
on 8 Mar 2025
Edited: Matt J
on 8 Mar 2025
An added complication is that the resulting union may have multiple regions, so I cannot just duplicate the first vertex to the last.
You can use the regions() command to break up the polyshape into single-region polyshapes:
wgs84 = wgs84Ellipsoid("nm");
lat0 = 42.3601;
lon0 = -71.0589;
r = 10;
[lat,lon] = scircle1(lat0,lon0,r,[],wgs84);
lat=lat(1:10:end); %coarsen so that we can see the completion of the polygons
lon=lon(1:10:end);
shp = polyshape({lat,lat},{lon,lon+0.6}); % multi-region polyshape
latlon=closeGaps(shp);
h=geoplot(latlon{:}); % Plot the vertices of the polyshape
[h.Color]=deal('b','g');
[h.LineWidth]=deal(1);
function latlon=closeGaps(shp)
shp=regions(shp);
n=numel(shp);
latlon = cell(2,n);
for i=1:n
latlon{1,i}=shp(i).Vertices([1:end,1],1);
latlon{2,i}=shp(i).Vertices([1:end,1],2);
end
end
3 Comments
Matt J
on 10 Mar 2025
Edited: Matt J
on 10 Mar 2025
The function allBoundaries() below will extract the boundaries of all regions and holes. You can then adapt the answer easily:
p=nsidedpoly(5); %Example
p=subtract(p,polybuffer(p,-0.5));
p=union([p,translate(p,[2,0])]);
C=allBoundaries(p);
plot(p,Edgecolor='none'); hold on; axis equal
for i=1:numel(C)
plot(C{i}(:,1), C{i}(:,2),'.-','MarkerSize',12,'LineWidth',2)
end; hold off
function boundaries = allBoundaries(ps)
arguments
ps polyshape
end
% Get the boundary coordinates
[vx, vy] = boundary(ps);
% Identify NaN separators
nanIdx = isnan(vx);
% Compute segment lengths
segmentLengths = diff([0; find(nanIdx); numel(vx)+1])-1;
% Remove NaNs and split using mat2cell
vx(nanIdx) = [];
vy(nanIdx) = [];
boundaries = mat2cell([vx, vy], segmentLengths, 2);
boundaries=cellfun(@(z) [z;z(1,:)], boundaries,'uni',0);
end
More Answers (2)
Voss
on 6 Mar 2025
Here's an example with 'Simplify', true (the default), where polyshape removes duplicate vertices:
polyshape([0 0 1 2],[0 0 2 1]).Vertices
And with 'Simplify', false, polyshape does not remove duplicate vertices:
polyshape([0 0 1 2],[0 0 2 1],'Simplify',false).Vertices
except apparently if the first and last vertices are the same, then the last vertex is removed, even with 'Simplify', false:
polyshape([0 0 1 2 0],[0 0 2 1 0],'Simplify',false).Vertices
So you may not be able to prevent polyshape removing the last vertex. But what you can do is duplicate the last vertex when you plot the vertices. Then there's no gap. (Obviously this wouldn't have any effect on the union of polyshapes you construct.)
% changes made to plotting code to run online
gui = figure;
wgs84 = wgs84Ellipsoid("nm");
lat0 = 42.3601;
lon0 = -71.0589;
r = 10;
[lat,lon] = scircle1(lat0,lon0,r,[],wgs84);
nr_pts = length(lat);
geoplot(lat,lon,"LineWidth",5) % Plot the result from scircle1
hold on
circle_poly = polyshape({lat},{lon}); % Create the polyshape
c_lat = circle_poly.Vertices([1:end 1],1); % duplicate the first vertex
c_lon = circle_poly.Vertices([1:end 1],2);
geoplot(c_lat,c_lon,"Color","y","LineWidth",1) % Plot the vertices of the polyshape
Image Analyst
on 6 Mar 2025
You might try other ways of drawing the circle. Some might need the image processing toolbox, but try looking at viscircles, poly2mask, and drawpolygon (demo attached).
2 Comments
Image Analyst
on 8 Mar 2025
I don't know. I don't have the mapping toolbox so I don't work with that kind of object.
See Also
Categories
Find more on Elementary Polygons in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!