package ds.moteur.route.cc;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ds.io.Sauvegardable;
import ds.moteur.geometrie.Angle3D;
import ds.moteur.geometrie.Point;
import ds.moteur.route.Section;
import ds.moteur.route.cc.elements.Arc;
import ds.moteur.route.cc.elements.LigneElementaire;
import ds.moteur.route.cc.elements.Segment;
import ds.moteur.route.cc.elements.TypeElement;
import ds.moteur.voiture.Voiture;
/**Cette classe repr�sente une courbe de conduite. C'est une sorte de rail sur lequel circule les voitures guid�s par l'ordinateur
* et sur lesquels sont projet�s la voiture du joueur pour permettre aux autres voitures de prendre des d�cisions r�actives.
*
* @author Yannick BISIAUX
*
*/
public class CourbeConduite implements Sauvegardable{
/**Section routi�re � laquelle appartient cette CC*/
private Section origine;
/**Point de d�part de la courbe*/
private PointEntree entree;
/**Point d'arriv�e de la courbe*/
private PointSortie sortie;
/**Lignes �l�mentaires composant cette courbe*/
private List<LigneElementaire> elements;
/**Point positions interm�diaires composant cette courbe*/
private List<Point> positions;
/**Index du prochain �l�ment � ajouter*/
private int indexElement = 0;
/**Direction suivie par cette CC*/
private Direction direction;
/**Liste des voitures sur cette CC*/
private List<Voiture> abonnes;
private CourbeConduite(PointEntree entree, PointSortie sortie){
this.entree = entree;
this.sortie = sortie;
this.elements = new ArrayList<LigneElementaire>();
this.positions = new ArrayList<Point>();
this.positions.add(entree);
this.positions.add(sortie);
entree.addCourbeConduite(this);
this.abonnes = new ArrayList<Voiture>();
}
public CourbeConduite(Section origine, PointEntree entree, PointSortie sortie){
this(entree, sortie);
this.origine = origine;
this.direction = Direction.TOUT_DROIT;
}
public CourbeConduite(Section origine, PointEntree entree, PointSortie sortie, Direction direction){
this(origine, entree, sortie);
this.direction = direction;
}
public void addPointIntermediaire(Point point){
this.positions.add(positions.size()-1, point);
}
/**Cr�e une ligne �l�mentaire de type segment entre le dernier point interm�diaire utilis� et le suivant.
*
* @return <b>true</b> si un segment a pu �tre ajout�
*/
public boolean addSegment(){
boolean ok = false;
if (elements.size() <= positions.size()-1){
Segment segment = new Segment(positions.get(indexElement), positions.get(indexElement+1));
segment.calculerLongueur();
this.elements.add(segment);
ok = true;
//System.out.println("Segment ajout� depuis : " + positions.get(indexElement).x + "/" + positions.get(indexElement).y);
indexElement++;
}
return ok;
}
/**Cr�e une ligne �l�mentaire de type arc entre le dernier point interm�diaire utilis� et le suivant.
*
* @param centre
* @param rayon
* @param angleOrigine, cap en radians
* @param ouverture, en radians, positif vers l'Est
* @param skip, nombre de points interm�diaires utilis�s pour dessiner l'arc - entre le point d�but de l'arc et le point de fin
* @return
*/
public boolean addArc(Point centre, double rayon, double angleOrigine, double ouverture, int skip){
boolean ok = false;
if (elements.size() < positions.size() - 1){
Arc arc = new Arc(positions.get(indexElement), positions.get(indexElement+1+skip), centre, rayon, angleOrigine, ouverture);
arc.calculerLongueur();
this.elements.add(arc);
ok = true;
indexElement += (skip+1);
}
return ok;
}
public void addLigneElementaire(LigneElementaire element){
element.calculerLongueur();
this.elements.add(element);
}
public List<LigneElementaire> getElements(){ return this.elements; }
public Direction getDirection(){ return this.direction; }
/**Permet de r�cup�rer le point position et l'angle � partir d'une abscisse curviligne.
*
* @param point
* @param angle
* @param abscisse
* @return
*/
public boolean recupererPosition(Point point, Angle3D angle, double abscisse){
boolean surCourbe = false;
double longueurPartielle = 0;
double distanceInterPts = 0;
for (int i=0; i<elements.size(); i++){
LigneElementaire element = elements.get(i);
distanceInterPts = element.getLongueur();
if (longueurPartielle + distanceInterPts > abscisse){
boolean recupere = element.recupererPosition(point, angle, abscisse - longueurPartielle);
surCourbe = recupere;
break;
}
longueurPartielle += distanceInterPts;
}
return surCourbe;
}
public double getLongueur(){
double longueur = 0;
for (int i=0; i<elements.size(); i++){
LigneElementaire element = elements.get(i);
longueur += element.getLongueur();
}
return longueur;
}
public double[] getDistance(Point point){
double[] distanceAbs = new double[2];
double distance = 1000;
double abscisse = 0;
for(LigneElementaire element : elements){
double ratio = element.projeter(point);
if((ratio>-0.1)&&(ratio<1.1)){
double distanceTemp = element.projeterDistance(point);
if (distanceTemp < distance){
distance = distanceTemp;
abscisse = element.projeterAbsCurv(point);
}
}
}
distanceAbs[0] = distance;
distanceAbs[1] = abscisse;
return distanceAbs;
}
/**Place la courbe de conduite � sa position absolue : position relative + transformation affine de la position de la section.
*
*/
public void rendreAbsoluPI(){
if (origine != null){
for (int i = 1; i<positions.size() - 1; i++){
positions.get(i).transformer(origine.getPositionAbsolue(), origine.getAngle().theta);
}
for (LigneElementaire element : elements){
if (element instanceof Arc){
Arc arc = (Arc)element;
arc.transformer(origine.getPositionAbsolue(), origine.getAngle().theta);
}
}
}
}
public Section getOrigine() { return origine; }
public void setOrigine(Section origine) { this.origine = origine; }
public PointEntree getEntree() { return entree; }
public void setEntree(PointEntree entree) { this.entree = entree; }
public PointSortie getSortie() { return sortie; }
public void setSortie(PointSortie sortie) { this.sortie = sortie; }
public List<Point> getPositionsIntermediaires() { return positions; }
public List<Voiture> getAbonnes(){ return this.abonnes; }
public void load(DataInputStream dis) throws IOException {
//Reconstitution des points interm�diaires
int n1 = dis.readShort();
for(int i=0; i<n1; i++){
Point point = new Point();
point.load(dis);
this.addPointIntermediaire(point);
}
//Reconstitution des lignes �l�mentaires
int n2 = dis.readShort();
for(int i=0; i<n2; i++){
int type = dis.readShort();
if(type == TypeElement.SEGMENT.ordinal()){
this.addSegment();
} else {
Arc arc = new Arc();
arc.load(dis);
int skip = dis.readShort();
this.addArc(arc.getCentre(), arc.getRayon(), arc.getAngleOrigine(), arc.getOuverture(), skip);
}
}
}
public void save(DataOutputStream dos) throws IOException {
//Sauvegarde des points interm�diaires (sauf les extr�mes)
dos.writeShort(positions.size()-2);
for (int i=1; i<positions.size()-1; i++){
Point point = positions.get(i);
point.save(dos);
}
//Sauvegarde des lignes �l�mentaires
dos.writeShort(elements.size());
for (LigneElementaire element : elements){
element.save(dos);
if(element instanceof Arc){
Arc arc = (Arc)element;
int skip = positions.indexOf(arc.getP2()) - positions.indexOf(arc.getP1()) - 1;
dos.writeShort(skip);
}
}
}
}