public void addVPFLayer(File file) {
   VPFDatabase db = VPFUtils.readDatabase(file);
   VPFLayer layer = new VPFLayer(db);
   insertBeforePlacenames(this.getWwd(), layer);
   this.getLayerPanel().update(this.getWwd());
   this.openVPFCoveragePanel(db, layer);
 }
  protected void buildEdgePrimitives(
      VPFCoverage coverage, VPFTile tile, VPFPrimitiveData primitiveData) {
    VPFBufferedRecordData edgeTable =
        this.createPrimitiveTable(coverage, tile, VPFConstants.EDGE_PRIMITIVE_TABLE);
    if (edgeTable == null || edgeTable.getNumRecords() == 0) return;

    VPFBufferedRecordData mbrTable =
        this.createPrimitiveTable(coverage, tile, VPFConstants.EDGE_BOUNDING_RECTANGLE_TABLE);
    if (mbrTable == null) return;

    int numEdges = edgeTable.getNumRecords();
    VPFPrimitiveData.EdgeInfo[] edgeInfo = new VPFPrimitiveData.EdgeInfo[numEdges];
    VecBufferSequence coords =
        (VecBufferSequence) edgeTable.getRecordData("coordinates").getBackingData();

    for (VPFRecord row : edgeTable) {
      int id = row.getId();
      VPFRecord mbrRow = mbrTable.getRecord(id);

      edgeInfo[VPFBufferedRecordData.indexFromId(id)] =
          new VPFPrimitiveData.EdgeInfo(
              getNumber(row.getValue("edge_type")),
              getId(row.getValue("start_node")),
              getNumber(row.getValue("end_node")),
              getId(row.getValue("left_face")),
              getId(row.getValue("right_face")),
              getId(row.getValue("left_edge")),
              getId(row.getValue("right_edge")),
              isEdgeOnTileBoundary(row),
              VPFUtils.getExtent(mbrRow));
    }

    primitiveData.setPrimitiveInfo(VPFConstants.EDGE_PRIMITIVE_TABLE, edgeInfo);
    primitiveData.setPrimitiveCoords(VPFConstants.EDGE_PRIMITIVE_TABLE, coords);
  }
  protected VPFBufferedRecordData createPrimitiveTable(
      VPFCoverage coverage, VPFTile tile, String tableName) {
    String path = getPrimitiveTablePath(coverage, tile, tableName);

    File file = new File(path);
    if (!file.exists()) return null;

    return VPFUtils.readTable(file);
  }
  protected void buildFacePrimitives(
      VPFCoverage coverage, VPFTile tile, VPFPrimitiveData primitiveData) {
    VPFBufferedRecordData faceTable =
        this.createPrimitiveTable(coverage, tile, VPFConstants.FACE_PRIMITIVE_TABLE);
    if (faceTable == null) return;

    VPFBufferedRecordData mbrTable =
        this.createPrimitiveTable(coverage, tile, VPFConstants.FACE_BOUNDING_RECTANGLE_TABLE);
    if (mbrTable == null) return;

    VPFBufferedRecordData ringTable =
        this.createPrimitiveTable(coverage, tile, VPFConstants.RING_TABLE);
    if (ringTable == null) return;

    VPFPrimitiveData.PrimitiveInfo[] edgeInfo =
        primitiveData.getPrimitiveInfo(VPFConstants.EDGE_PRIMITIVE_TABLE);

    int numFaces = faceTable.getNumRecords();
    VPFPrimitiveData.FaceInfo[] faceInfo = new VPFPrimitiveData.FaceInfo[numFaces];

    for (VPFRecord faceRow : faceTable) {
      int faceId = faceRow.getId();
      VPFRecord mbrRow = mbrTable.getRecord(faceId);

      // Face ID 1 is reserved for the "universe face", which does not have any associated geometry.
      if (faceId == 1) continue;

      // The first ring primitive associated with the face primitive defines the outer ring. The
      // face primitive must
      // at least contain coordinates for an outer ring.

      int ringId = ((Number) faceRow.getValue("ring_ptr")).intValue();
      VPFRecord ringRow = ringTable.getRecord(ringId);
      VPFPrimitiveData.Ring outerRing = this.buildRing(ringRow, edgeInfo);

      // The ring table maintains an order relationship for its rows. The first record of a new face
      // id will always
      // be defined as the outer ring. Any repeating records with an identical face value will
      // define inner rings.

      ArrayList<VPFPrimitiveData.Ring> innerRingList = new ArrayList<VPFPrimitiveData.Ring>();

      for (ringId = ringId + 1; ringId <= ringTable.getNumRecords(); ringId++) {
        ringRow = ringTable.getRecord(ringId);

        // Break on the first ring primitive row which isn't associated with the face. Because the
        // ring rows
        // maintain an ordering with respect to face id, there will be no other ring rows
        // corresponding to this
        // face.
        if (faceId != getId(ringRow.getValue("face_id"))) break;

        VPFPrimitiveData.Ring innerRing = this.buildRing(ringRow, edgeInfo);
        if (innerRing != null) innerRingList.add(innerRing);
      }

      VPFPrimitiveData.Ring[] innerRings = new VPFPrimitiveData.Ring[innerRingList.size()];
      innerRingList.toArray(innerRings);

      faceInfo[VPFBufferedRecordData.indexFromId(faceId)] =
          new VPFPrimitiveData.FaceInfo(outerRing, innerRings, VPFUtils.getExtent(mbrRow));
    }

    primitiveData.setPrimitiveInfo(VPFConstants.FACE_PRIMITIVE_TABLE, faceInfo);
  }