/**
  * compute the dsf index of the building facade object used for a given polygon
  *
  * @param polygon
  * @param height
  * @param roofColor
  * @return
  */
 private Integer computeBuildingFacadeIndex(OsmPolygon osmPolygon) {
   Integer result = null;
   // if the polygon is a simple rectangle, we'll use a facade made for
   // simple shaped buildings
   if (osmPolygon.getPolygon().getEdges().size() == 4) {
     result = dsfObjectsProvider.computeFacadeDsfIndex(true, false, false, osmPolygon);
   }
   // the building has a complex footprint, so we'll use a facade made
   // for this case
   else {
     result = dsfObjectsProvider.computeFacadeDsfIndex(false, false, false, osmPolygon);
   }
   return result;
 }
  /**
   * write a 3D object in the dsf file
   *
   * @param object a xplane dsf object
   * @throws Osm2xpBusinessException
   */
  private void writeObjectToDsf(XplaneDsfObject object) throws Osm2xpBusinessException {

    String objectDsfText = object.asObjDsfText();
    writer.write(objectDsfText, GeomUtils.cleanCoordinatePoint(object.getOsmPolygon().getCenter()));
    // stats
    StatsHelper.addObjectType(dsfObjectsProvider.getObjectsList().get(object.getDsfIndex()), stats);
  }
  /**
   * write a building in the dsf file.
   *
   * @param polygon
   * @param facade
   * @param size
   */
  private void writeBuildingToDsf(OsmPolygon osmPolygon, Integer facade) {
    if (facade != null && osmPolygon.getHeight() != null) {
      StringBuffer sb = new StringBuffer();
      osmPolygon.setPolygon(GeomUtils.setClockwise(osmPolygon.getPolygon()));
      if (osmPolygon.getPolygon().getArea() * 100000000 > 0.1
          && osmPolygon.getPolygon().getVertexNumber() > 3) {

        sb.append("BEGIN_POLYGON " + facade + " " + osmPolygon.getHeight() + " 2");
        sb.append(System.getProperty("line.separator"));
        sb.append("BEGIN_WINDING");
        sb.append(System.getProperty("line.separator"));

        // on supprime le dernier point pour ne pas boucler
        osmPolygon.getPolygon().removePoint(osmPolygon.getPolygon().getLastPoint());
        for (Point2D loc : osmPolygon.getPolygon().getVertices()) {
          sb.append("POLYGON_POINT " + loc.y + " " + loc.x);
          sb.append(System.getProperty("line.separator"));
        }
        sb.append("END_WINDING");
        sb.append(System.getProperty("line.separator"));
        sb.append("END_POLYGON");
        sb.append(System.getProperty("line.separator"));

        // stats TODO not working anymore since v2 facades new features.
        if (dsfObjectsProvider.getPolygonsList().get(facade).toLowerCase().contains("building")
            || dsfObjectsProvider.getPolygonsList().get(facade).toLowerCase().contains("shape")) {
          StatsHelper.addBuildingType("Building", stats);
        } else {
          if (dsfObjectsProvider.getPolygonsList().get(facade).toLowerCase().contains("house")
              || dsfObjectsProvider
                  .getPolygonsList()
                  .get(facade)
                  .toLowerCase()
                  .contains("common")) {
            StatsHelper.addBuildingType("Residential", stats);
          } else {
            StatsHelper.addBuildingType("Facade rule", stats);
          }
        }
        writer.write(
            sb.toString(), GeomUtils.cleanCoordinatePoint(osmPolygon.getPolygon().getFirstPoint()));
      }
    }
  }
 /**
  * @param way
  * @param polygon
  * @return
  */
 private boolean processForest(OsmPolygon osmPolygon) {
   Boolean result = false;
   if (XplaneOptionsHelper.getOptions().isGenerateFor()) {
     Integer[] forestIndexAndDensity =
         dsfObjectsProvider.getRandomForestIndexAndDensity(osmPolygon.getTags());
     if (forestIndexAndDensity != null) {
       writeForestToDsf(osmPolygon, forestIndexAndDensity);
       result = true;
     }
   }
   return result;
 }
  private void processLightObject(OsmPolygon poly) {
    if (XplaneOptionsHelper.getOptions().isGenerateLights()) {
      XplaneDsfObject object = dsfObjectsProvider.getRandomDsfLightObject(poly);
      if (object != null) {
        object.setPolygon(poly);
        try {
          writeObjectToDsf(object);

        } catch (Osm2xpBusinessException e) {
        }
      }
    }
  }
  /**
   * compute the dsf index of the residential facade object used for a given polygon
   *
   * @param polygon
   * @param height
   * @return Integer the facade index
   */
  private Integer computeResidentialFacadeIndex(OsmPolygon osmPolygon) {
    Integer result = null;
    // we check if we can use a sloped roof if the user wants them
    if (XplaneOptionsHelper.getOptions().isGenerateSlopedRoofs() && osmPolygon.isSimplePolygon()) {
      result = dsfObjectsProvider.computeFacadeDsfIndex(true, true, true, osmPolygon);
    }
    // no sloped roof, so we'll use a standard house facade
    else {

      // if the polygon is a simple rectangle, we'll use a facade made for
      // simple shaped buildings
      if (osmPolygon.getPolygon().getEdges().size() == 4) {
        result = dsfObjectsProvider.computeFacadeDsfIndex(true, true, false, osmPolygon);
      }
      // the building has a complex footprint, so we'll use a facade made
      // for this case
      else {
        result = dsfObjectsProvider.computeFacadeDsfIndex(false, true, false, osmPolygon);
      }
    }
    return result;
  }
  /**
   * choose and write a 3D object in the dsf file.
   *
   * @param polygon osm polygon.
   * @return true if a 3D object has been written in the dsf file.
   */
  private boolean process3dObject(OsmPolygon osmPolygon) {
    Boolean result = false;

    if (XplaneOptionsHelper.getOptions().isGenerateObj()) {
      // simplify shape if checked and if necessary
      if (GuiOptionsHelper.getOptions().isSimplifyShapes() && !osmPolygon.isSimplePolygon()) {
        osmPolygon.simplifyPolygon();
      }
      XplaneDsfObject object = dsfObjectsProvider.getRandomDsfObject(osmPolygon);
      if (object != null) {
        object.setPolygon(osmPolygon);
        try {
          writeObjectToDsf(object);
          result = true;
        } catch (Osm2xpBusinessException e) {
          result = false;
        }
      }
    }
    return result;
  }
  /**
   * @param polygon the forest polygon
   * @param forestIndexAndDensity index and density of the forest rule
   */
  private void writeForestToDsf(OsmPolygon osmPolygon, Integer[] forestIndexAndDensity) {
    StringBuffer sb = new StringBuffer();
    sb.append("BEGIN_POLYGON " + forestIndexAndDensity[0] + " " + forestIndexAndDensity[1] + " 2");
    sb.append(System.getProperty("line.separator"));
    sb.append("BEGIN_WINDING");
    sb.append(System.getProperty("line.separator"));
    for (Point2D loc : osmPolygon.getPolygon().getVertices()) {
      sb.append("POLYGON_POINT " + loc.y + " " + loc.x);
      sb.append(System.getProperty("line.separator"));
    }
    sb.append("END_WINDING");
    sb.append(System.getProperty("line.separator"));
    sb.append("END_POLYGON");
    sb.append(System.getProperty("line.separator"));

    // stats
    StatsHelper.addForestType(
        dsfObjectsProvider.getPolygonsList().get(forestIndexAndDensity[0]), stats);

    writer.write(
        sb.toString(), GeomUtils.cleanCoordinatePoint(osmPolygon.getPolygon().getFirstPoint()));
  }
  /**
   * Write streetlight objects in dsf file.
   *
   * @param osmPolygon osm road polygon
   */
  public void writeStreetLightToDsf(OsmPolygon osmPolygon) {
    // init d'un entier pour modulo densité street lights
    Integer densityIndex = 0;
    if (XplaneOptionsHelper.getOptions().getLightsDensity() == 0) {
      densityIndex = 10;
    } else {
      if (XplaneOptionsHelper.getOptions().getLightsDensity() == 1) {
        densityIndex = 5;
      } else {
        if (XplaneOptionsHelper.getOptions().getLightsDensity() == 2) densityIndex = 3;
      }
    }
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < osmPolygon.getPolygon().getVertices().size(); i++) {
      if ((i % densityIndex) == 0) {
        Point2D lightLoc = osmPolygon.getPolygon().getVertex(i);
        lightLoc.x = lightLoc.x + 0.0001;
        lightLoc.y = lightLoc.y + 0.0001;
        if (GeomUtils.compareCoordinates(lightLoc, currentTile)) {
          Random randomGenerator = new Random();
          int orientation = randomGenerator.nextInt(360);
          sb.append(
              "OBJECT "
                  + dsfObjectsProvider.getRandomStreetLightObject()
                  + " "
                  + (lightLoc.y)
                  + " "
                  + (lightLoc.x)
                  + " "
                  + orientation);
          sb.append(System.getProperty("line.separator"));
          // stats
          StatsHelper.addStreetLight(stats);
        }
      }
    }

    writer.write(sb.toString());
  }
 @Override
 public void processNode(Node node) throws Osm2xpBusinessException {
   // process the node if we're on a single pass mode.
   // if not on single pass, only process if the node is on the current
   // lat/long tile
   if (XplaneOptionsHelper.getOptions().isGenerateObj()) {
     if ((!GuiOptionsHelper.getOptions().isSinglePass()
             && GeomUtils.compareCoordinates(currentTile, node))
         || GuiOptionsHelper.getOptions().isSinglePass()) {
       // write a 3D object in the dsf file if this node is in an
       // object
       // rule
       XplaneDsf3DObject object =
           dsfObjectsProvider.getRandomDsfObjectIndexAndAngle(node.getTag(), node.getId());
       if (object != null) {
         List<Node> nodes = new ArrayList<Node>();
         nodes.add(node);
         object.setPolygon(new OsmPolygon(node.getId(), node.getTag(), nodes));
         writeObjectToDsf(object);
       }
     }
   }
 }