private void calculateVector() {
    /*
     * Notice that this tool assumes that each record in the shapefile is an
     * individual polygon. The feature can contain multiple parts only if it
     * has holes, i.e. islands. A multipart record cannot contain multiple
     * and seperate features. This is because it complicates the calculation
     * of feature area and perimeter.
     */

    amIActive = true;

    // Declare the variable.
    String inputFile = null;
    int progress;
    double featureArea = 0;
    double circleArea = 0;
    double radius = 0;
    int recNum;
    int j, i;
    double[][] vertices = null;
    CoordinateArraySequence coordArray;
    LinearRing ring;
    MinimumBoundingCircle mbc;
    GeometryFactory factory = new GeometryFactory();
    Geometry geom;

    if (args.length <= 0) {
      showFeedback("Plugin parameters have not been set.");
      return;
    }

    inputFile = args[0];
    /*
     * args[1], args[2], and args[3] are ignored by the vector tool
     */

    // check to see that the inputHeader and outputHeader are not null.
    if (inputFile == null) {
      showFeedback("One or more of the input parameters have not been set properly.");
      return;
    }

    try {

      ShapeFile input = new ShapeFile(inputFile);
      double numberOfRecords = input.getNumberOfRecords();

      if (input.getShapeType().getBaseType() != ShapeType.POLYGON) {
        showFeedback("This function can only be applied to polygon type shapefiles.");
        return;
      }

      /* create a new field in the input file's database
      to hold the fractal dimension. Put it at the end
      of the database. */
      DBFField field = new DBFField();
      field = new DBFField();
      field.setName("RC_CIRCLE");
      field.setDataType(DBFField.DBFDataType.NUMERIC);
      field.setFieldLength(10);
      field.setDecimalCount(4);
      input.getAttributeTable().addField(field);

      // initialize the shapefile.
      ShapeType inputType = input.getShapeType();

      for (ShapeFileRecord record : input.records) {
        switch (inputType) {
          case POLYGON:
            whitebox.geospatialfiles.shapefile.Polygon recPolygon =
                (whitebox.geospatialfiles.shapefile.Polygon) (record.getGeometry());
            vertices = recPolygon.getPoints();
            coordArray = new CoordinateArraySequence(vertices.length);
            j = 0;
            for (i = 0; i < vertices.length; i++) {
              coordArray.setOrdinate(j, 0, vertices[i][0]);
              coordArray.setOrdinate(j, 1, vertices[i][1]);
              j++;
            }
            geom = factory.createMultiPoint(coordArray);
            mbc = new MinimumBoundingCircle(geom);
            radius = mbc.getRadius();
            circleArea = Math.PI * radius * radius;
            featureArea = recPolygon.getArea();
            break;
          case POLYGONZ:
            PolygonZ recPolygonZ = (PolygonZ) (record.getGeometry());
            vertices = recPolygonZ.getPoints();
            coordArray = new CoordinateArraySequence(vertices.length);
            j = 0;
            for (i = 0; i < vertices.length; i++) {
              coordArray.setOrdinate(j, 0, vertices[i][0]);
              coordArray.setOrdinate(j, 1, vertices[i][1]);
              j++;
            }
            geom = factory.createMultiPoint(coordArray);
            mbc = new MinimumBoundingCircle(geom);
            radius = mbc.getRadius();
            circleArea = Math.PI * radius * radius;
            featureArea = recPolygonZ.getArea();
            break;
          case POLYGONM:
            PolygonM recPolygonM = (PolygonM) (record.getGeometry());
            vertices = recPolygonM.getPoints();
            coordArray = new CoordinateArraySequence(vertices.length);
            j = 0;
            for (i = 0; i < vertices.length; i++) {
              coordArray.setOrdinate(j, 0, vertices[i][0]);
              coordArray.setOrdinate(j, 1, vertices[i][1]);
              j++;
            }
            geom = factory.createMultiPoint(coordArray);
            mbc = new MinimumBoundingCircle(geom);
            radius = mbc.getRadius();
            circleArea = Math.PI * radius * radius;
            featureArea = recPolygonM.getArea();
            break;
        }

        recNum = record.getRecordNumber() - 1;
        Object[] recData = input.getAttributeTable().getRecord(recNum);
        if (circleArea > 0) {
          recData[recData.length - 1] = new Double(1 - featureArea / circleArea);
        } else {
          recData[recData.length - 1] = new Double(0);
        }
        input.getAttributeTable().updateRecord(recNum, recData);

        if (cancelOp) {
          cancelOperation();
          return;
        }
        progress = (int) (record.getRecordNumber() / numberOfRecords * 100);
        updateProgress(progress);
      }

      // returning the database file will result in it being opened in the Whitebox GUI.
      returnData(input.getDatabaseFile());

    } catch (OutOfMemoryError oe) {
      myHost.showFeedback("An out-of-memory error has occurred during operation.");
    } catch (Exception e) {
      myHost.showFeedback("An error has occurred during operation. See log file for details.");
      myHost.logException("Error in " + getDescriptiveName(), e);
    } finally {
      updateProgress("Progress: ", 0);
      // tells the main application that this process is completed.
      amIActive = false;
      myHost.pluginComplete();
    }
  }
  /**
   * Create device locations in a path near the main zone.
   *
   * @param assignment
   * @param start
   * @return
   * @throws SiteWhereException
   */
  protected List<IDeviceLocation> createDeviceLocations(IDeviceAssignment assignment, Date date)
      throws SiteWhereException {
    long current = date.getTime();
    Polygon zone = GeoUtils.createPolygonForLocations(zoneLocations);
    Point centroid = zone.getCentroid();

    // Calculate length of steps between locations based on bounding circle.
    MinimumBoundingCircle circle = new MinimumBoundingCircle(zone);
    double step = circle.getRadius() / 10;

    double cx = centroid.getX();
    double cy = centroid.getY();
    double deltaX = (Math.sqrt(Math.random()) * step * 2) - step;
    double deltaY = (Math.sqrt(Math.random()) * step * 2) - step;

    // Used to rotate deltas to turn path and stay inside polygon.
    AffineTransformation xform = new AffineTransformation();
    xform.rotate(Math.toRadians(22.5));

    List<IDeviceLocation> results = new ArrayList<IDeviceLocation>();
    GeometryFactory factory = new GeometryFactory();
    for (int x = 0; x < LOCATIONS_PER_ASSIGNMENT; x++) {
      boolean foundNext = false;

      // Add a little randomness to path.
      double waver = ((Math.random() * 20) - 10.0);
      AffineTransformation waverXform = new AffineTransformation();
      waverXform.rotate(Math.toRadians(waver));
      Coordinate waverDelta = new Coordinate(deltaX, deltaY);
      waverXform.transform(waverDelta, waverDelta);
      deltaX = waverDelta.x;
      deltaY = waverDelta.y;

      while (!foundNext) {
        Coordinate start = new Coordinate(cx, cy);
        Coordinate end = new Coordinate(cx + deltaX, cy + deltaY);
        Coordinate[] lineCoords = {start, end};
        LineString line = factory.createLineString(lineCoords);
        if (zone.contains(line)) {
          DeviceLocationCreateRequest request = new DeviceLocationCreateRequest();
          request.setLatitude(end.y);
          request.setLongitude(end.x);
          request.setElevation(0.0);
          request.setEventDate(new Date(current));
          IDeviceLocation created =
              getDeviceManagement().addDeviceLocation(assignment.getToken(), request);
          results.add(created);

          cx = cx + deltaX;
          cy = cy + deltaY;
          foundNext = true;
        } else {
          // Rotate deltas and try again.
          Coordinate delta = new Coordinate(deltaX, deltaY);
          xform.transform(delta, delta);
          deltaX = delta.x;
          deltaY = delta.y;
        }
      }
      current += 30000;
    }
    LOGGER.info(PREFIX_CREATE_EVENTS + " " + results.size() + " locations. ");
    return results;
  }