moduleNSWTopomoduleLabelsclassConvexHulls<GeoJSON::MultiLineStringdefinitialize(feature,buffer,&block)coordinates=casefeaturewhenGeoJSON::Polygonthenfeature.ringswhenGeoJSON::MultiPolygonthenfeature.ringselsefeatureend.explode.flat_mapdo|feature|casefeaturewhenGeoJSON::Point# a point feature barrierx,y=*feature[[Vector[x-buffer,y-buffer],Vector[x+buffer,y-buffer],Vector[x+buffer,y+buffer],Vector[x-buffer,y+buffer]]]whenGeoJSON::LineString# a linestring label to be broken down into segment hullsoffsets=feature.each_cons(2).mapdo|p0,p1|(p1-p0).perp.normalised*bufferendcorners=offsets.thendo|offsets|feature.closed??[offsets.last,*offsets,offsets.first]:[offsets.first,*offsets,offsets.last]end.each_cons(2).mapdo|o01,o12|nextifo12.cross(o01)==0(o01+o12).normalised*buffer*(o12.cross(o01)<=>0)end.each_cons(2)feature.each_cons(2).zip(corners,offsets).mapdo|(p0,p1),(c0,c1),offset|ifc0then[p0+offset,p0+c0,p0-offset]else[p0+offset,p0-offset]end+ifc1then[p1-offset,p1+c1,p1+offset]else[p1-offset,p1+offset]endendendendsupercoordinates,&blockenddelegate:length=>:@coordinatesdefeach(&block)enum=Enumerator.newdo|yielder|@coordinates.eachdo|coordinates|yielder<<ConvexHull.new(self,coordinates)endendblock_given??enum.each(&block):enumenddefself.overlap?(ring0,ring1,buffer)# implements Gilbert–Johnson–Keerthisimplex=[ring0.first-ring1.first]perp=simplex[0].perploopdoreturntrueunlesscasewhensimplex.one?thensimplex[0].normwhensimplex.inject(&:-).dot(simplex[1])>0thensimplex[1].normwhensimplex.inject(&:-).dot(simplex[0])<0thensimplex[0].normelsesimplex.inject(&:cross).abs/simplex.inject(&:-).normend>buffermax=ring0.max_by{|point|perp.crosspoint}min=ring1.min_by{|point|perp.crosspoint}support=max-minreturnfalseunless(simplex[0]-support).cross(perp)>0rays=simplex.map{|point|point-support}casesimplex.lengthwhen1casewhenrays[0].dot(support)>0simplex,perp=[support],support.perpwhenrays[0].cross(support)<0simplex,perp=[support,*simplex],rays[0]elsesimplex,perp=[*simplex,support],-rays[0]endwhen2casewhenrays[0].cross(support)>0&&rays[0].dot(support)<0simplex,perp=[simplex[0],support],-rays[0]whenrays[1].cross(support)<0&&rays[1].dot(support)<0simplex,perp=[support,simplex[1]],rays[1]whenrays[0].cross(support)<=0&&rays[1].cross(support)>=0returntrueelsesimplex,perp=[support],support.perpendendendendendendend