cdm/src/main/java/ucar/nc2/ft2/simpgeometry/CFPolygon.java
public Polygon setupPolygon(NetcdfDataset dataset, Variable polyvar, int index)
	{
		this.points.clear();
		Array xPts = null;
		Array yPts = null;
		Variable nodeCounts = null;
		Variable partNodeCounts = null;
		Variable interiorRings = null;

		List<CoordinateAxis> axes = dataset.getCoordinateAxes();
		CoordinateAxis x = null; CoordinateAxis y = null;
		
		String[] nodeCoords = polyvar.findAttributeIgnoreCase(CF.NODE_COORDINATES).getStringValue().split(" ");
		
		// Look for x and y
		
		for(CoordinateAxis ax : axes){
			
			if(ax.getFullName().equals(nodeCoords[0])) x = ax;
			if(ax.getFullName().equals(nodeCoords[1])) y = ax;
		}
		
		// Affirm node counts
		String nodeCoStr = polyvar.findAttValueIgnoreCase(CF.NODE_COUNT, "");
		
		if(!nodeCoStr.equals("")) {
			nodeCounts = dataset.findVariable(nodeCoStr);
		}
		
		else return null;
		
		// Affirm part node counts
		String pNodeCoStr = polyvar.findAttValueIgnoreCase(CF.PART_NODE_COUNT, "");
		
		if(!pNodeCoStr.equals("")) {
			partNodeCounts = dataset.findVariable(pNodeCoStr);
		}
		
		// Affirm interior rings
		String interiorRingsStr = polyvar.findAttValueIgnoreCase(CF.PART_NODE_COUNT, "");
				
		if(!interiorRingsStr.equals("")) {
				interiorRings = dataset.findVariable(interiorRingsStr);
		}
		
		SimpleGeometryIndexFinder indexFinder = new SimpleGeometryIndexFinder(nodeCounts);
		
		//Get beginning and ending indicies for this polygon
		int lower = indexFinder.getBeginning(index);
		int upper = indexFinder.getEnd(index);

		
		try {
			
			xPts = x.read( lower + ":" + upper ).reduce();
			yPts = y.read( lower + ":" + upper ).reduce(); 

			IndexIterator itrX = xPts.getIndexIterator();
			IndexIterator itrY = yPts.getIndexIterator();
			
			// No multipolygons just read in the whole thing
			if(partNodeCounts == null) {
				
				this.next = null;
				this.prev = null;
				this.isInteriorRing = false;
				
				// x and y should have the same shape, will add some handling on this
				while(itrX.hasNext()) {
					this.addPoint(itrX.getDoubleNext(), itrY.getDoubleNext());
				}
	
				
				switch(polyvar.getRank()) {
				
				case 2:
					this.setData(polyvar.read(CFSimpleGeometryHelper.getSubsetString(polyvar, index)).reduce());
					break;
					
				case 1:
					this.setData(polyvar.read("" + index));
					break;
					
				default:
					throw new InvalidDataseriesException(InvalidDataseriesException.RANK_MISMATCH);	// currently do not support anything but dataseries and scalar associations
				
				}
			}
			
			// If there are multipolygons then take the upper and lower of it and divy it up
			else {
				
				Polygon tail = this;
				Array pnc = partNodeCounts.read();
				Array ir = null;
				IndexIterator pncItr = pnc.getIndexIterator();
				
				if(interiorRings != null) ir = interiorRings.read();
				
				// In part node count search for the right index to begin looking for "part node counts"
				int pncInd = 0;
				int pncEnd = 0;
				while(pncEnd < lower)
				{
					pncEnd += pncItr.getIntNext();
					pncInd++;
				}
				
				// Now the index is found, use part node count and the index to find each part node count of each individual part
				while(lower < upper) {
					
					int smaller = pnc.getInt(pncInd);
					
					// Set interior ring if needed
					if(interiorRings != null)
					{
						int interiorRingValue = ir.getInt(pncInd);
						
						switch(interiorRingValue) {
						
							case 0:
								this.setInteriorRing(false);
								break;
								
							case 1:
								this.setInteriorRing(true);
								break;
								
							// will handle default case
						}
						
					} else this.isInteriorRing = false;
					
					while(smaller > 0) {
						tail.addPoint(itrX.getDoubleNext(), itrY.getDoubleNext());
						smaller--;
					}
					
					// Set data of each
					switch(polyvar.getRank()) {
					
					case 2:
						tail.setData(polyvar.read(CFSimpleGeometryHelper.getSubsetString(polyvar, index)).reduce());
						break;
						
					case 1:
						tail.setData(polyvar.read("" + index));
						break;
						
					default:
						throw new InvalidDataseriesException(InvalidDataseriesException.RANK_MISMATCH);	// currently do not support anything but dataseries and scalar associations
					
					}

					lower += tail.getPoints().size();
					pncInd++;
					tail.setNext(new CFPolygon());
					tail = tail.getNext();
				}
				
				//Clean up
				tail = tail.getPrev();
				if(tail != null) tail.setNext(null);
			}
		}
		
		catch (IOException | InvalidRangeException | InvalidDataseriesException e) {
			cfpl.error(e.getMessage());
			return null;
		}
		
		return this;
	}
public Polygon setupPolygon(NetcdfDataset dataset, Variable polyvar, int index)
	{
		this.points.clear();
		Array xPts = null;
		Array yPts = null;
		Variable nodeCounts = null;
		Variable partNodeCounts = null;
		Variable interiorRings = null;

		List<CoordinateAxis> axes = dataset.getCoordinateAxes();
		CoordinateAxis x = null; CoordinateAxis y = null;
		
		String[] nodeCoords = polyvar.findAttributeIgnoreCase(CF.NODE_COORDINATES).getStringValue().split(" ");
		
		// Look for x and y
		
		for(CoordinateAxis ax : axes){
			
			if(ax.getFullName().equals(nodeCoords[0])) x = ax;
			if(ax.getFullName().equals(nodeCoords[1])) y = ax;
		}
		
		// Affirm node counts
		String nodeCoStr = polyvar.findAttValueIgnoreCase(CF.NODE_COUNT, "");
		
		if(!nodeCoStr.equals("")) {
			nodeCounts = dataset.findVariable(nodeCoStr);
		}
		
		else return null;
		
		// Affirm part node counts
		String pNodeCoStr = polyvar.findAttValueIgnoreCase(CF.PART_NODE_COUNT, "");
		
		if(!pNodeCoStr.equals("")) {
			partNodeCounts = dataset.findVariable(pNodeCoStr);
		}
		
		// Affirm interior rings
		String interiorRingsStr = polyvar.findAttValueIgnoreCase(CF.PART_NODE_COUNT, "");
				
		if(!interiorRingsStr.equals("")) {
				interiorRings = dataset.findVariable(interiorRingsStr);
		}
		
		SimpleGeometryIndexFinder indexFinder = new SimpleGeometryIndexFinder(nodeCounts);
		
		//Get beginning and ending indicies for this polygon
		int lower = indexFinder.getBeginning(index);
		int upper = indexFinder.getEnd(index);

		
		try {
			
			xPts = x.read( lower + ":" + upper ).reduce();
			yPts = y.read( lower + ":" + upper ).reduce(); 

			IndexIterator itrX = xPts.getIndexIterator();
			IndexIterator itrY = yPts.getIndexIterator();
			
			// No multipolygons just read in the whole thing
			if(partNodeCounts == null) {
				
				this.next = null;
				this.prev = null;
				this.isInteriorRing = false;
				
				// x and y should have the same shape, will add some handling on this
				while(itrX.hasNext()) {
					this.addPoint(itrX.getDoubleNext(), itrY.getDoubleNext());
				}
	
				
				switch(polyvar.getRank()) {
				
				case 2:
					this.setData(polyvar.read(CFSimpleGeometryHelper.getSubsetString(polyvar, index)).reduce());
					break;
					
				case 1:
					this.setData(polyvar.read("" + index));
					break;
					
				default:
					throw new InvalidDataseriesException(InvalidDataseriesException.RANK_MISMATCH);	// currently do not support anything but dataseries and scalar associations
				
				}
			}
			
			// If there are multipolygons then take the upper and lower of it and divy it up
			else {
				
				Polygon tail = this;
				Array pnc = partNodeCounts.read();
				Array ir = null;
				IndexIterator pncItr = pnc.getIndexIterator();
				
				if(interiorRings != null) ir = interiorRings.read();
				
				// In part node count search for the right index to begin looking for "part node counts"
				int pncInd = 0;
				int pncEnd = 0;
				while(pncEnd < lower)
				{
					pncEnd += pncItr.getIntNext();
					pncInd++;
				}
				
				// Now the index is found, use part node count and the index to find each part node count of each individual part
				while(lower < upper) {
					
					int smaller = pnc.getInt(pncInd);
					
					// Set interior ring if needed
					if(interiorRings != null)
					{
						int interiorRingValue = ir.getInt(pncInd);
						
						switch(interiorRingValue) {
						
							case 0:
								this.setInteriorRing(false);
								break;
								
							case 1:
								this.setInteriorRing(true);
								break;
								
							// will handle default case
						}
						
					} else this.isInteriorRing = false;
					
					while(smaller > 0) {
						tail.addPoint(itrX.getDoubleNext(), itrY.getDoubleNext());
						smaller--;
					}
					
					// Set data of each
					switch(polyvar.getRank()) {
					
					case 2:
						tail.setData(polyvar.read(CFSimpleGeometryHelper.getSubsetString(polyvar, index)).reduce());
						break;
						
					case 1:
						tail.setData(polyvar.read("" + index));
						break;
						
					default:
						throw new InvalidDataseriesException(InvalidDataseriesException.RANK_MISMATCH);	// currently do not support anything but dataseries and scalar associations
					
					}

					lower += tail.getPoints().size();
					pncInd++;
					tail.setNext(new CFPolygon());
					tail = tail.getNext();
				}
				
				//Clean up
				tail = tail.getPrev();
				if(tail != null) tail.setNext(null);
			}
		}
		
		catch (IOException | InvalidRangeException | InvalidDataseriesException e) {
			cfpl.error(e.getMessage());
			return null;
		}
		
		return this;
	}
Given a dataset, variable and index, automatically sets up a previously constructed polygon.
If the specified polygon is not found in the dataset, returns null

@param dataset which the variable is a part of
@param polyvar the variable which has a geometry attribute
@param index of the polygon within the variable