Page d'accueil

Espace Pro      
 Mon CV                      
  CV intéractif              
  CV Classique          
  CV imprimable        
  Téléchargement      
 Mes Projets              
  Statistiques              
  C.A.O.                        
  Programmation       
  Contact                     
Espace Perso  
 Liste DVD                  
Accueil programmation | Manipulations, Schémas et Formules | Images de surfaces | Makefile | NURBS.cpp | PLSV.cpp | PLSV.h | Surface.cpp | Surface.h | Vu.cpp | Vu.h | Rn.h | LesFichiers.h

//
// Classes des PLSV Alain PERRONNET Mai 2001
//
#include "LesFichiers.h"
#include "PLSV.h" //attention a l'ordre a cause des constructeurs!
#include "Vu.h"
#include "Surface.cpp"
/*
R TailleArete=0.1; // >0 => Taille souhaitee des aretes du maillage
// =0 => Emploi de la fonction Taille_Ideale() (A FAIRE...)
// <0 => Emploi d'une carte de taille des aretes(A FAIRE...)
// sur un maillage de fond

int NoPoint=-1;
int NoLigne=-1;


R3 PtMIN(0.0, 0.0, 0.0); //Pt MIN par defaut Points de coordonnees extremales
R3 PtMAX(1.5, 1.1, 0.0); //Pt MAX par defaut

XPoint pxy0={0,0};
XPoint pxy;

Drawable fenoupix; //fenetre ou pixmap variable auxiliaire

int TraceTg=0; //Trace (1) ou non (0) des tangentes aux noeuds des courbes NURBS
int TraceNormales=0; //Trace (1) ou non (0) des normales et bi-normales aux noeuds des courbes NURBS
*/
/*
void NommerPoint( Nom & nom )
{
int nbc;

NoPoint++;
strcpy( nom, "P" );
itoa( NoPoint, nbc, nom+1 );
}

void NommerLigne( Nom & nom )
{
int nbc;

NoLigne++;
strcpy( nom, "L" );
itoa( NoLigne, nbc, nom+1 );
}
*/
//==============================================================================

PLSV::PLSV()
{
date = Secondes1970();
//cout << "Date H M S de creation du PLSV = " << setprecision(16) << date <<endl;
}

//==============================================================================

Point::Point() : PLSV()
{
NommerPoint( nom );
#ifdef VERBOSE
cout << "Creation du Point " << nom << endl;
#endif
PSuivant = NULL;
}

Point::Point( Nom NomPt )
{
strcpy( nom, NomPt ); // et non pas Nom=NomPt INTERDIT!!!
PSuivant = NULL;
}

Point::~Point()
{
Nom nom0;
#ifdef VERBOSE
cout << "Entree dans ~Point() pour le point " << this->nom << endl;
#endif
delete [] NoStEF;
delete [] XyzSommet;

if( PSuivant != NULL )
{
nom0 = PSuivant->nom;
#ifdef VERBOSE
cout << "Avant Destruction de Psuivant=" << nom0 << endl;
#endif
delete PSuivant;
#ifdef VERBOSE
cout << "Apres Destruction de Psuivant=" << nom0 << endl;
#endif
}
#ifdef VERBOSE
cout << "Sortie de ~Point() pour le point " << this->nom << endl;
#endif
}

void Point::AfficherMaillage()
{
//Maillage d'un POINT reduit a un SOMMET
cout << "Nom du Point=" << PLSV::nom
<< " X=" << setw(14) << XyzSommet[0].x
<< " Y=" << setw(14) << XyzSommet[0].y
<< " Z=" << setw(14) << XyzSommet[0].z
<< endl;
cout << endl;
}

void Point::TracerMaillage(MemoirePx3d & mpx)
{
Z i, ns1, ns2;
char texte[1+25];
R3 xyz;

//trace du POINT reduit a un SOMMET par +NomPoint
VuChoisirFonte( hauttexte );
VuCouleur( Noir );
strcpy( texte, "+" );
strcat( texte, nom );

//trace de la poignee du Point
VuCouleur( Noir );
mpx.VuSymbole( XyzSommet[0], texte );
}

void Point::Deplacer()
//Deplacer a l'aide de la souris un Point
{
XPoint pxy, pxyaccr0={-1,-1};
int notyev, nbc;
R3 Pt0, Pta;

//copie de mpxPLSV dans mpxModif
fenoupix = mpxModif.mempx; //protection du mempx
mpxModif = mpxPLSV; //mise a jour de fenetre et axonometrie
mpxModif.mempx = fenoupix;
//effacer l'eventuel mpxModif deja trace
mpxModif.VuEffacerMemoirePx();
Pt0 = XyzSommet[0]; //Sauvegarde des coordonnees initiales du point

//Modifier XYZ du Point par un clic sur un bouton de la souris
//==============================================================================
PointADeplacer:
mpxInvite.VuInvite( "Cliquer la NOUVELLE POSITION du Point ou frapper X" );
mpxInvite.VuSourisXYZ( notyev, nbc, pxy, XyzSommet[0] );
switch( notyev )
{
case 0: //ABANDON demande
XyzSommet[0] = Pt0; //Restauration des coordonnees initiales
return;

case -2: //deplacement de la souris. Materialisation de l'accrochage
case -1: //une touche de la souris enfoncee et non relachee
if( (pxyaccr0.x!=-1) && (pxyaccr0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxyaccr0 );
pxyaccr0.x = -1;
pxyaccr0.y = -1; //reinitialisation a vide
}

if( ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, XyzSommet[0] )==0 ) goto PointADeplacer;
//retourne 1 si XyzSommet[0] est le point projete dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible

//fenetre_vu est initialise avec mpxPLSV
mpxPLSV.VuCombinerMemoirePxDansFenetre( GXcopy,
pxy0, mpxPLSV.largeurpx, mpxPLSV.hauteurpx, //source
pxy0 ); //destination
//ajout du mpxAccroche a fenetre_vu
if( mpxPLSV.visee==3 ) mpxPLSV.Vuxyzaxo( XyzSommet[0], Pta ); else Pta=XyzSommet[0];
pxyaccr0.x = mpxPLSV.Vunupxex( Pta.x )- mpxAccroche.largeurpx/2;
pxyaccr0.y = mpxPLSV.Vunupxey( Pta.y )- mpxAccroche.hauteurpx/2;
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxyaccr0 );
//effacer le mpxModif deja trace
mpxModif.VuEffacerMemoirePx();
TracerMaillage(mpxModif); //trace dans mpxModif du nouveau point

//la ligne est ajoutee dans fenetre_vu
mpxModif.VuCombinerMemoirePxDansFenetre( GXand,
pxy0, mpxModif.largeurpx, mpxModif.hauteurpx, //source
pxy0 ); //destination
goto PointADeplacer;

case 1:
if( ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, XyzSommet[0] )==0 )
goto PointADeplacer;
//retourne si 1 si XyzSommet[0] est le point projete dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible
break;

//case 2: //frappe de XYZ au clavier XyzSommet[0] contient le resultat
}

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, XyzSommet[0] );
PtMAX = Max( PtMAX, XyzSommet[0] );

date = Secondes1970(); //nouvelle date du point modifie
}


Pointxyz::Pointxyz() // La definition et maillage du Point Cartesien
{
XPoint pxy, pxyaccr0={-1,-1};
int notyev, nbc, ncvals ;
R3 Pt, Pta;

//saisie a la souris du Point
mpxInvite.VuInvite( "Cliquer le POINT ou frapper X" );

entree:
mpxInvite.VuSourisXYZ( notyev, nbc, pxy, Pt );
switch( notyev )
{
case 0: NbSommet=0; NoPoint--; return; //Pas de Point

case -2: //deplacement de la souris. Materialisation de l'accrochage
case -1: //une touche de la souris enfoncee et non relachee
if( (pxyaccr0.x!=-1) && (pxyaccr0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxyaccr0 );
pxyaccr0.x = -1;
pxyaccr0.y = -1; //reinitialisation a vide
}

if( ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, Pt )==0 ) goto entree;
//retourne si 1 si Pt est le point projete dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible

//ajout du mpxAccroche a fenetre_vu
if( mpxPLSV.visee==3 ) mpxPLSV.Vuxyzaxo( Pt, Pta ); else Pta=Pt;
pxyaccr0.x = mpxPLSV.Vunupxex( Pta.x )- mpxAccroche.largeurpx/2;
pxyaccr0.y = mpxPLSV.Vunupxey( Pta.y )- mpxAccroche.hauteurpx/2;
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxyaccr0 );
goto entree;

case 1:
NbSommet = 1;
XyzSommet = new R3[NbSommet]; // Les coordonnees du sommet=point
if( ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, XyzSommet[0] )==0 ) goto entree;
//retourne si 1 si XyzSommet[0] est le point projete dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible
break;

case 2: //frappe de X Y Z
NbSommet = 1;
XyzSommet = new R3[NbSommet]; // Les coordonnees du sommet=point
XyzSommet[0] = Pt;
break;

default :
goto entree;
}

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, XyzSommet[0] );
PtMAX = Max( PtMAX, XyzSommet[0] );

NbEF = 1; // 1 EF reduit a un sommet de numero 1
NbStEF = 1;
NoStEF = new Z[NbEF*NbStEF];
NoStEF[0]=1;
x = XyzSommet[0].x;
y = XyzSommet[0].y;
z = XyzSommet[0].z;
}

Pointxyz::Pointxyz( Nom NomPt, R abscisse, R ordonnee, R cote )
:Point(NomPt)
{
x=abscisse;
y=ordonnee;
z=cote;

NbSommet = 1;
XyzSommet = new R3[NbSommet]; // Les coordonnees du sommet

XyzSommet[0].x=x; // Le maillage du Point
XyzSommet[0].y=y;
XyzSommet[0].z=z;

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, XyzSommet[0] );
PtMAX = Max( PtMAX, XyzSommet[0] );

NbEF = 1; // 1 EF reduit a un sommet de numero 1
NbStEF = 1;
NoStEF = new Z[NbEF*NbStEF];
NoStEF[0]=1;
}

Pointxyz::~Pointxyz()
{
#ifdef VERBOSE
cout << "Entree Sortie dans ~Pointxyz() du point " << nom << endl;
#endif
}

void Pointxyz::AfficherDefinition()
{
cout << "Nom du Point=" << nom
<< " Abscisse X=" << x
<< " Ordonnee Y= " << y
<< " Cote Z= " << z << endl;
}

PointCyl::PointCyl()
{
cout << "Rayon=? "; // L'affichage du point en coordonnes cylindriques
cin >> rayon;
cout << "Teta en degres=? ";
cin >> teta;
R a = teta * atan(1) / 45; // conversion en radians de l'angle
cout << "Z=? ";
cin >> z;

NbSommet = 1;
XyzSommet = new R3[NbSommet]; // Les coordonnees du sommet

XyzSommet[0].x = rayon * cos(a); // Le maillage du Point
XyzSommet[0].y = rayon * sin(a);
XyzSommet[0].z = z;

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, XyzSommet[0] );
PtMAX = Max( PtMAX, XyzSommet[0] );

NbEF = 1; // 1 EF reduit a un sommet de numero 1
NbStEF = 1;
NoStEF = new Z[NbEF*NbStEF];
NoStEF[0]=1;
}

PointCyl::PointCyl( Nom NomPt, R Rayon, R Teta, R Cote )
:Point(NomPt)
{
rayon=Rayon;
teta=Teta;
z=Cote;

NbSommet = 1;
XyzSommet = new R3[NbSommet]; // Les coordonnees du sommet

R a = Teta * atan(1) / 45.0; // conversion en radians de l'angle
XyzSommet[0].x = rayon * cos(a); // Le maillage du Point
XyzSommet[0].y = rayon * sin(a);
XyzSommet[0].z = z;

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, XyzSommet[0] );
PtMAX = Max( PtMAX, XyzSommet[0] );

NbEF = 1; // 1 EF reduit a un sommet de numero 1
NbStEF = 1;
NoStEF = new Z[NbEF*NbStEF];
NoStEF[0]=1;
}

PointCyl::~PointCyl()
{
#ifdef VERBOSE
cout << "Entree Sortie dans ~PointCyl() du point "<< nom << endl;
#endif
}

void PointCyl::AfficherDefinition()
{
cout << "Nom du Point=" << nom
<< " Rayon R=" << rayon // L'affichage du point
<< " Longitude en degres=" << teta // en coordonnees cylindriques
<< " Cote Z=" << z << endl;
}

//==============================================================================

Points::Points()
{
P1Point=NULL;
}

Points::~Points()
{
if ( Points::P1Point != NULL )
delete P1Point;
}

Point * Points::RetrouverPoint( Nom NomPt, Point * & PtAvant )
// retourne NULL si NomPt pas retrouve
{ // PtAvant pointeur sur le point avant NomPt dans le chainage
// & PtAvant ou (& PtAvant) pour le passage par REFERENCE
Point * PtCourant;

PtAvant=NULL;
PtCourant = P1Point;
while ( PtCourant != NULL )
{
if ( strcmp( PtCourant->nom, NomPt )==0 )
{
return PtCourant;
}
else
{
PtAvant=PtCourant;
PtCourant=PtCourant->PSuivant;
}
}
return NULL;
}

Point * Points::RetrouverPointControle( Nom NomPt, Z nbn, Point *pc[] )
{ // retourne NULL si pas retrouve
Z i;

for( i=0; i<=nbn; i++ )
{
if ( strcmp( pc[i]->nom, NomPt )==0 ) return pc[i];
}
return NULL;
}

Point * Points::CliquerPoint( void )
// retourne le pointeur sur le point le plus proche du clic-souris
// NULL si le point n'est pas retrouve ou trop loin ou abandon demande
// Un accrochage est materialise sur un bouton souris enfonce et non relache
{
int notyev, nbc, nx, ny;
XPoint pxy;
XPoint pxymin;
XPoint pxymin0={-1,-1};
Point *PtCourant, *PtMin;
R3 xyz, axyz;
R d, dmin;
Nom nomPoint;

SaisieT: //saisie a la souris du Point
mpxInvite.VuSourisTexte( notyev, nbc, pxy, nomPoint );
if( notyev == 0 ) { return NULL; } //Abandon demande

if( notyev < 0 ) //souris deplacee ou bouton enfonce non relache
{
xyz.x = mpxPLSV.Vuxob2px( pxy.x ); //construction du point de R2 correspondant
xyz.y = mpxPLSV.Vuyob2px( pxy.y );
xyz.z = 0;
//recherche du Point actuel le plus proche du pixel du clic souris
//==============================================================================
dmin = 1e100;
PtMin = NULL;
PtCourant = P1Point;
while ( PtCourant != NULL ) //recherche du point le plus proche
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
d = Norme2_2( xyz - PtCourant->XyzSommet[0] );
}
else
{ //Visee 3d Un point pxy clique est une droite dans R3
//recherche du point le plus proche de cette droite
// Passage en coordonnees axonometriques du point
mpxPLSV.Vuxyzaxo( PtCourant->XyzSommet[0], axyz );
//distance en XY axonometriques seulement
d = sqrt( pow( xyz.x-axyz.x , 2 )
+ pow( xyz.y-axyz.y , 2 ) );
}
if ( d < dmin ) { dmin = d; PtMin = PtCourant; }
PtCourant = PtCourant->PSuivant;
}

//Verification que PtMin n'est pas trop loin du point clique
if( PtMin != NULL )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
if( abs( mpxPLSV.Vunupxex( PtMin->XyzSommet[0].x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( PtMin->XyzSommet[0].y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}
else
{ //Visee 3d
mpxPLSV.Vuxyzaxo( PtMin->XyzSommet[0], axyz );
if( abs( mpxPLSV.Vunupxex( axyz.x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( axyz.y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}

if( PtMin == NULL ) //Point min trop loin Accrochage a effacer
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
pxymin0.x = -1;
pxymin0.y = -1; //reinitialisation a vide
}
}
}
if( PtMin == NULL ) { goto SaisieT; }

//Un point est suffisamment proche => son accrochage est materialise
//si ce n'est deja fait
if( mpxPLSV.visee == 2 ) //Visee 2d
{
pxymin.x = mpxPLSV.Vunupxex( PtMin->XyzSommet[0].x );
pxymin.y = mpxPLSV.Vunupxey( PtMin->XyzSommet[0].y );
}
else //Visee 3d
{
mpxPLSV.Vuxyzaxo( PtMin->XyzSommet[0], axyz );
pxymin.x = mpxPLSV.Vunupxex( axyz.x );
pxymin.y = mpxPLSV.Vunupxey( axyz.y );
}
pxymin.x -= (int) mpxAccroche.largeurpx/2;
pxymin.y -= (int) mpxAccroche.hauteurpx/2;
if( (pxymin.x!=pxymin0.x) || (pxymin.y!=pxymin0.y) )
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
//ajout du mpxAccroche a fenetre_vu
pxymin0 = pxymin;
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
goto SaisieT;
}
else if( notyev == 1 ) //clic d'un bouton de la souris
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
xyz.x = mpxPLSV.Vuxob2px( pxy.x ); //construction du point de R2 correspondant
xyz.y = mpxPLSV.Vuyob2px( pxy.y );
xyz.z = 0;

//recherche du Point actuel le plus proche du clic souris
dmin = 1e100;
PtMin = NULL;
PtCourant = P1Point;
while ( PtCourant != NULL )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
d = Norme2_2( xyz - PtCourant->XyzSommet[0] );
}
else
{ //Visee 3d Un point pxy clique est une droite dans R3
//recherche du point le plus proche de cette droite
// Passage en coordonnees axonometriques du point
mpxPLSV.Vuxyzaxo( PtCourant->XyzSommet[0], axyz );
//distance en XY axonometriques seulement
d = sqrt( pow( xyz.x-axyz.x , 2 )
+ pow( xyz.y-axyz.y , 2 ) );
}
if ( d < dmin ) { dmin = d; PtMin = PtCourant; }
PtCourant = PtCourant->PSuivant;
}

//Verification que PtMin n'est pas trop loin du point clique
if( PtMin != NULL )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
if( abs( mpxPLSV.Vunupxex( PtMin->XyzSommet[0].x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( PtMin->XyzSommet[0].y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}
else
{ //Visee 3d
mpxPLSV.Vuxyzaxo( PtMin->XyzSommet[0], axyz );
if( abs( mpxPLSV.Vunupxex( axyz.x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( axyz.y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}
}
}
else if ( notyev == 2 )
{
Point *PtAvant;
PtMin = RetrouverPoint( nomPoint, PtAvant ); //par son nom
}
return PtMin;
}


Point * Points::CliquerPointControle( Z nbn, Point *pc[] )
// retourne le pointeur sur le point de controle le plus proche du clic-souris
// NULL si le point n'est pas retrouve ou trop loin ou abandon demande
{
int notyev, nbc, nx, ny;
XPoint pxy;
XPoint pxymin;
XPoint pxymin0={-1,-1};
Point *PtCourant, *PtMin;
R3 xyz, axyz;
R d, dmin;
Nom nomPoint;
Z i;

//saisie a la souris du Point
SaisieT:
mpxInvite.VuSourisTexte( notyev, nbc, pxy, nomPoint );
if( notyev == 0 ) { return NULL; } //Abandon demande

if( notyev < 0 ) //souris deplacee ou bouton enfonce non relache
{
xyz.x = mpxPLSV.Vuxob2px( pxy.x ); //construction du point de R2 correspondant
xyz.y = mpxPLSV.Vuyob2px( pxy.y );
xyz.z = 0;

//recherche du Point actuel le plus proche du clic souris
dmin = 1e100;
PtMin = NULL;
for( i=0; i<=nbn; i++ )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
d = Norme2_2( xyz - pc[i]->XyzSommet[0] );
}
else
{ //Visee 3d Un point pxy clique est une droite dans R3
//recherche du point le plus proche de cette droite
// Passage en coordonnees axonometriques du point
mpxPLSV.Vuxyzaxo( pc[i]->XyzSommet[0], axyz );
//distance en XY axonometriques seulement
d = sqrt( pow( xyz.x-axyz.x , 2 )
+ pow( xyz.y-axyz.y , 2 ) );
}
if ( d < dmin ) { dmin = d; PtMin = pc[i]; }
}

//Verification que PtMin n'est pas trop loin du point clique
if( PtMin != NULL )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
if( abs( mpxPLSV.Vunupxex( PtMin->XyzSommet[0].x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( PtMin->XyzSommet[0].y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}
else
{ //Visee 3d
mpxPLSV.Vuxyzaxo( PtMin->XyzSommet[0], axyz );
if( abs( mpxPLSV.Vunupxex( axyz.x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( axyz.y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}
if( PtMin == NULL ) //Point min trop loin => Accrochage a effacer
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
pxymin0.x = -1;
pxymin0.y = -1; //reinitialisation a vide
}
}
}
if( PtMin == NULL ) { goto SaisieT; }

//Un point est suffisamment proche => son accrochage est materialise
//si ce n'est deja fait
if( mpxPLSV.visee == 2 ) //Visee 2d
{
pxymin.x = mpxPLSV.Vunupxex( PtMin->XyzSommet[0].x );
pxymin.y = mpxPLSV.Vunupxey( PtMin->XyzSommet[0].y );
}
else //Visee 3d
{
mpxPLSV.Vuxyzaxo( PtMin->XyzSommet[0], axyz );
pxymin.x = mpxPLSV.Vunupxex( axyz.x );
pxymin.y = mpxPLSV.Vunupxey( axyz.y );
}
pxymin.x -= (int) mpxAccroche.largeurpx/2;
pxymin.y -= (int) mpxAccroche.hauteurpx/2;
if( (pxymin.x!=pxymin0.x) || (pxymin.y!=pxymin0.y) )
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
//ajout du mpxAccroche a fenetre_vu
pxymin0 = pxymin;
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
goto SaisieT;
}
else if( notyev == 1 ) //clic d'un bouton enfonce et relache de la souris
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
xyz.x = mpxPLSV.Vuxob2px( pxy.x ); //construction du point de R2 correspondant
xyz.y = mpxPLSV.Vuyob2px( pxy.y );
xyz.z = 0;

//recherche du point de controle le plus proche du clic souris
dmin = 1e100;
PtMin = NULL;
for( i=0; i<=nbn; i++ )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
d = Norme2_2( xyz - pc[i]->XyzSommet[0] );
}
else
{ //Visee 3d Un point pxy clique est une droite dans R3
//recherche du point le plus proche de cette droite
// Passage en coordonnees axonometriques du point
mpxPLSV.Vuxyzaxo( pc[i]->XyzSommet[0], axyz );
//distance en XY axonometriques seulement
d = sqrt( pow( xyz.x-axyz.x, 2 )
+ pow( xyz.y-axyz.y, 2 ) );
}
if ( d < dmin ) { dmin = d; PtMin = pc[i]; }
}

//Verification que PtMin n'est pas trop loin du point clique
if( PtMin != NULL )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
if( abs( mpxPLSV.Vunupxex( PtMin->XyzSommet[0].x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( PtMin->XyzSommet[0].y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}
else
{ //Visee 3d
mpxPLSV.Vuxyzaxo( PtMin->XyzSommet[0], axyz );
if( abs( mpxPLSV.Vunupxex( axyz.x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( axyz.y ) - pxy.y ) > 123 )
{PtMin = NULL;}
}
}
}
else if ( notyev == 2 )
{
Point *PtAvant;
PtMin = RetrouverPointControle( nomPoint, nbn, pc ); //par son nom
}

return PtMin;
}


void Points::Ajouter1Point( Point *PPoint )
{
Point * PtAvant;
Point * PtNom;

PtNom = RetrouverPoint( PPoint->nom, PtAvant );
if( PtNom != NULL )
{ // Le point etait deja dans la liste
if (PtAvant==NULL) // Pas de point avant
P1Point=PtNom->PSuivant; // le suivant de PtNom devient le premier
else
PtAvant->PSuivant=PtNom->PSuivant; // Le suivant d'avant est le suivant de PtNom

PtNom->PSuivant=NULL;
delete PtNom;
}
// Le point n'est pas dans la liste
PPoint->PSuivant = P1Point; // Le point devient le premier
P1Point=PPoint; // point de la liste
}

int Points::EntrerPoints() // Entrer des Points avec les donnees utilisateur
{
int type;
Point *PPoint; // Construction d'un point avec demande du Nom

while(1)
{
cout << endl;
cout << "Type du POINT: 0:Quitter 1:X,Y,Z 2:R,Teta,Z =>? ";
cin >> type;

switch( type )
{
case 0:
return 0;

case 1:
PPoint = new Pointxyz(); // construction du POINT et demande du Nom
if ( PPoint->NbSommet == 0 ) return 1;
Points::Ajouter1Point( PPoint ); // ajout du point a l'ensemble des points
PPoint->TracerMaillage(mpxPLSV); // trace du maillage du point
break;

case 2:
PPoint = new PointCyl();
if ( PPoint->NbSommet == 0 ) return 1;
Points::Ajouter1Point( PPoint );
break;

default:
cout << "Type INCONNU de POINT\n";
break;
}
}
}

void Points::AfficherPoints()
{
Point *PCourant;

cout << endl;
cout << "Affichage des POINTS:" << endl;
PCourant = P1Point;
while( PCourant != NULL )
{
PCourant->AfficherDefinition();
PCourant->AfficherMaillage();
PCourant = PCourant->PSuivant;
}
}

R Points::Dist2Pt( Point *P1, Point *P2 )
{
return Norme2( P2->XyzSommet[0] - P1->XyzSommet[0] );
}


void Points::TracerPoints(MemoirePx3d & mpx)
//Tracer tous les points actuels dans fenetre_vu
{
Point * PtCourant;

PtCourant = P1Point;
while ( PtCourant != NULL )
{
PtCourant->TracerMaillage(mpx);
PtCourant=PtCourant->PSuivant;
}
}

//==============================================================================

Ligne::Ligne() : PLSV()
{
NommerLigne( nom );
#ifdef VERBOSE
cout << "Creation de la Ligne " << nom << endl;
#endif
PSuivant = NULL;
}


Ligne::Ligne( Nom NomLg )
{
strcpy( nom, NomLg );
PSuivant = NULL;
}


Ligne::~Ligne()
{
#ifdef VERBOSE
cout << "Entree dans ~Ligne() pour la ligne " << nom << endl;
#endif
if( NoStEF != NULL ) delete [] NoStEF;
if( XyzSommet != NULL ) delete [] XyzSommet;
if( U != NULL ) delete [] U;
if( PC != NULL ) delete [] PC;
if( Poids != NULL ) delete [] Poids;

if ( PSuivant != NULL ) // Destruction de la ligne suivante
delete PSuivant;

#ifdef VERBOSE
cout << "Sortie de ~Ligne() pour la ligne " << nom << endl;
#endif
}


int Ligne::IntervalleNURBS( R u )
//Retrouve i tel que u verifie U[i]<=u<U[i+1] intervalle des noeuds U
//sauf pour u=U[nbn+1] => i=nbn
{
int min, max, milieu;

if( u >= U[1+nbn] ) return nbn; //Cas particulier!

//recherche par dichotomie
min = degre;
max = nbn+1;

Iteration:
milieu = (min+max)/2;

if( u < U[milieu] )
{
max = milieu;
goto Iteration;
}
else if( u >= U[milieu+1] )
{
min = milieu;
goto Iteration;
}
else
{
return milieu;
}
}

int Ligne::DichoIntervalleNURBS( int min, int max, R u )
//Retrouve i tel que u verifie U[i]<=u<U[i+1] intervalle des noeuds U
{ //Appel initial avec min=degre et max=nbn+1
if( (U[min]<=u) && (u<U[min+1]) && (U[min]<U[min+1]) ) return min;

int milieu=(min+max)/2;
if( u<U[milieu] )
return DichoIntervalleNURBS( min, milieu, u );
else
return DichoIntervalleNURBS( milieu, max, u );
}

int Ligne::MultipliciteDuNoeud( R u, int & i ) //La multiplicite du noeud u
{ //-1 si u n'est pas dans l'intervalle des Noeuds
if( u<U[0] || U[nbn+1]<u ) return -1; //u n'est pas dans l'intervalle
if( u==U[nbn+1] ) return int(degre+1); //cas particulier du dernier noeud

i = IntervalleNURBS( u ); //u dans [U(i)<U(i+1)[
if( u!=U[i] ) return 0;

int k=1; //u=U[i] au moins une fois
for (int j=i-1; j>=0; j--)
{
if( u!=U[j] ) return k;
k++;
}
return k;
}


void Ligne::ValeurBaseNSpline( int i, Z NbEtape, R u, R N[] )
//Calcul de la base des polynomes NURBS en u contenu dans [U(i)<U(i+1)[
//NbEtape est le numero de la derniere etape a faire et <=degre
//N contient en sortie N[i-degre],...,N[i-NbEtape-1] non significatifs suivis
//des valeurs significatives N[i-NbEtape,NbEtape],...,N[i,,NbEtape]
//cad si NbEtape=degre N contient en sortie N[i-degre,degre],...,N[i,degre], N[i+1,degre]
//Version simple a partir de la Formule de Cox-de Boor
//ATTENTION: N doit declare avec 1+degre+1 variables!
{
int j,k,ij;
R a,b;

for (j=0; j<=degre+1; j++) //initialisation du degre 0
{ N[j] =0; }
N[degre] = 1.0;

for (j=1; j<=NbEtape; j++)
{
for (k=degre-j; k<=degre; k++) //calcul de N i-degre+k , j
{
ij = i - degre + k;

a = U[ij+j] - U[ij]; //le coefficient de N i-degre+k , j-1
if( a>0 )
a=(u-U[ij]) / a;
else
a=0;

b = U[ij+j+1] - U[ij+1]; //le coefficient de N i-degre+k+1 , j-1
if( b>0 )
b=(U[ij+j+1] - u) / b;
else
b=0;

N[k] = a*N[k] + b*N[k+1];
}
}
}

void Ligne::ValeurBaseNURBS( int i, Z NbEtape, R u, R N[] ) //version optimisee
//Calcul de la base des polynomes NURBS en u contenu dans [U(i)<U(i+1)[
//NbEtape est le numero de la derniere etape a faire et <=degre
//N contient en sortie N[0]=Ni-NbEtape,NbEtape,...,N[NbEtape]=Ni,NbEtape
//cf NURBS Book page 70
{
int j,k;
//R g[1+degre], d[1+degre]; //numerateur gauche et droite de N[i,j]
// Cette instruction donne des resultats corrects avec G++ mais NON a la norme
R g[1+64], d[1+64];//numerateur gauche et droite de N[i,j]
// => degre<=64 ! ce qui n'est pas une contrainte
R s, t; //denominateur=numerateur gauche + droite!

N[0] = 1.0;
for (j=1; j<=NbEtape; j++)
{
g[j] = u - U[i+1-j]; //numerateur gauche j
d[j] = U[i+j] - u; //numerateur droite j
s=0.0;
for (k=0; k<j; k++)
{
t = N[k] / ( d[k+1] + g[j-k] ); //la somme des indices vaut j+1
N[k]= s + d[k+1] * t;
s = g[j-k] * t;
}
N[j]=s;
}
}


void Ligne::Derivee1BaseNURBS( int i, R u, R N[] )
{ //Calcul des N'j,degre(u) pour j=i-degre a i
int j, m;
R a, b;

i = IntervalleNURBS(u); //u contenu dans [U(i)<U(i+1)[

ValeurBaseNSpline( i, degre-1, u, N ); //Calcul des Nj,degre-1(u) pour j=i-degre a i

//application de la formule
//N'j,d(u) = d ( Nj,d-1(u)/(uj+d-uj) - Nj+1,d-1(u)/(uj+d+1-uj+1) )
for (j=0; j<degre; j++)
{
m = i-degre+j;

a = U[m+degre]-U[m];
if(a!=0) a=1./a;

b = U[m+1+degre]-U[m+1];
if(b!=0) b=1./b;

N[j] = degre * ( N[j] * a - N[j+1] * b );
}
N[degre] = degre * ( N[degre]/(U[i+degre]-U[i]) );
}


void Ligne::Derivee2BaseNURBS( int i, R u, R N[] )
{ //Calcul des N''j,degre(u) pour j=i-degre a i
int j, m, k;
R b0, b1, b2;

i = IntervalleNURBS(u); //u contenu dans [U(i)<U(i+1)[

ValeurBaseNSpline( i, degre-2, u, N ); //Calcul des Nj,degre-1(u) pour j=i-degre a i
N[degre+2] = 0;

//application reccurente de la formule
//N''j,d(u) = d ( N'j,d-1(u)/(uj+d-uj) - N'j+1,d-1(u)/(uj+d+1-uj+1) )
k = degre * (degre-1);

for (j=0; j<=degre; j++)
{
m = i-degre+j;

b0 = (U[m+degre-1] - U[m]) * (U[m+degre] - U[m]);
if( b0!=0 ) b0 = k / b0;

b1 = U[m+degre] - U[m];
if( b1!=0 ) b1 = - k / b1;
b2 = U[m+degre+1] - U[m+1];
if( b2!=0 ) b2 = - k / b2;
b1 = b1 + b2;
b2 = U[m+degre] - U[m+1];
if( b2!=0 ) b1 = b1 / b2; else b1=0;

b2 = ( U[m+degre+1] - U[m+1] ) * (U[m+degre+1] - U[m+2]) ;
if( b2!=0 ) b2 = k / b2;

N[j] = b0 * N[j] + b1 * N[j+1] + b2 * N[j+2];
}
}

void Ligne::Derivee3BaseNURBS( int i, R u, R N[] )
{ //Calcul des N''j,degre(u) pour j=i-degre a i
int j, m, k;
R b0, b1, b2, c0, c1, c2, c3;

i = IntervalleNURBS(u); //u contenu dans [U(i)<U(i+1)[

ValeurBaseNSpline( i, degre-3, u, N ); //Calcul des Nj,degre-1(u) pour j=i-degre a i
N[degre+2] = 0;
N[degre+3] = 0;

//application reccurente de la formule
//N'''j,d(u) = d ( N''j,d-1(u)/(uj+d-uj) - N''j+1,d-1(u)/(uj+d+1-uj+1) )
k = degre * (degre-1) * (degre-2);

for (j=0; j<=degre; j++)
{
m = i-degre+j;

b0 = ( U[m+degre-1] - U[m] ) * ( U[m+degre] - U[m] );
if( b0!=0 ) b0 = 1 / b0;

b1 = U[m+degre] - U[m];
if( b1!=0 ) b1 = 1 / b1;
b2 = U[m+degre+1] - U[m+1];
if( b2!=0 ) b2 = 1 / b2;
b1 = b1 + b2;
b2 = U[m+1] - U[m+degre];
if( b2!=0 ) b1 = b1 / b2; else b1=0;

b2 = ( U[m+degre+1] - U[m+1] ) * ( U[m+degre+1] - U[m+2] ) ;
if( b2!=0 ) b2 = 1 / b2;

c0 = U[m+degre-2] - U[m];
if( c0!=0 ) c0 = k * b0 / c0;

c1 = U[m+degre-1] - U[m+1];
if( c1!=0 ) c1 = k * ( b1 - b0 ) / c1;

c2 = U[m+degre] - U[m+2];
if( c2!=0 ) c2 = k * ( b2 - b1 ) / c2;

c3 = U[m+3] - U[m+degre+1];
if( c3!=0 ) c3 = k * b2 / c3;

N[j] = c0 * N[j] + c1 * N[j+1] + c2 * N[j+2] + c3 * N[j+3];
}
//for (j=0; j<=degre+3; j++) cout << "N'''" << j << "(" << u << ")= " << N[j] << endl;
}


void Ligne::PointCourbeNURBS( R u, R3 & P )
//les coordonnees du point P de la courbe NURBS en u
{
//R N[1+degre]; //valeur des fonctions de base utiles en u
R N[1+64]; //valeur des fonctions de base utiles en u
R denominateur, Np;
int i,k,l;

i = IntervalleNURBS(u); //u contenu dans [U(i)<U(i+1)[

ValeurBaseNURBS( i, degre, u, N ); //valeur en u de la base N

P.x = P.y = P.z = 0.0;

if( Poids == NULL )
{ //courbe polynomiale
for (k=0; k<=degre; k++)
{
l=i-degre+k;
P.x += N[k] * PC[l]->XyzSommet[0].x;
P.y += N[k] * PC[l]->XyzSommet[0].y;
P.z += N[k] * PC[l]->XyzSommet[0].z;
}
}
else
{ //courbe NURBS rationnelle
denominateur=0;
for (k=0; k<=degre; k++)
{
l = i-degre+k;
Np = N[k] * Poids[l];
denominateur += Np;
P.x += Np * PC[l]->XyzSommet[0].x; //numerateurs
P.y += Np * PC[l]->XyzSommet[0].y;
P.z += Np * PC[l]->XyzSommet[0].z;
}
P.x /= denominateur;
P.y /= denominateur;
P.z /= denominateur;
}
}


void Ligne::Derivee1CourbeNURBS( R u, R3 & P )
//les composantes de la tangente a la courbe NURBS en u
{
R DN[2+64]; //valeur de la derivee des fonctions de base utiles en u
int i,k;

i = IntervalleNURBS(u); //u contenu dans [U(i)<U(i+1)[

P.x = P.y = P.z = 0.0;

Derivee1BaseNURBS( i, u, DN ); //valeur en u de la base derivee N'

if( Poids == NULL )
{ //courbe polynomiale
for (k=0; k<=degre; k++)
P = P + DN[k] * PC[i-degre+k]->XyzSommet[0];
}
else
{ //courbe rationnelle
R N[2+64]; //valeur des fonctions de base utiles en u
R Omega, OmegaDerivee, Np, NpD;
R3 DP=R3(0,0,0);
int l;

// C(u) = C3Omega(u) / Omega(u) par definition
// (=>C3Omega(u)=C(u) Omega(u)) d'ou
// C'(u) = ( C3Omega'(u) - C(u) Omega'(u) ) / Omega(u)
// C3Omega(u) = 3-eres coordonnees de COmega(u)
// Omega(u) = denominateur de C(u)

ValeurBaseNURBS( i, degre, u, N ); //valeur en u de la base N

Omega = OmegaDerivee = 0;

for (k=0; k<=degre; k++)
{
l = i-degre+k;

Np = N[k] * Poids[l];
Omega += Np; //denominateur de C(u)
P += Np * PC[l]->XyzSommet[0]; //numerateur de C(u)

NpD = DN[k] * Poids[l];
OmegaDerivee += NpD; //derivee du denominateur de C(u)
DP += NpD * PC[l]->XyzSommet[0]; //C3Omega'(u)
}

P = ( DP - OmegaDerivee * (P/Omega) ) / Omega; //C'(u)
}
}


void Ligne::Derivee2CourbeNURBS( R u, R3 & P )
//les composantes de la derivee seconde a la courbe NURBS en u
{
R DDN[3+64]; //valeur de la derivee seconde des fonctions de base utiles en u
int i,k;

i = IntervalleNURBS(u); //u contenu dans [U(i)<U(i+1)[

P.x = P.y = P.z = 0.0;

Derivee2BaseNURBS( i, u, DDN ); //valeur en u de la derivee seconde de la base N''

if( Poids == NULL )
{ //courbe polynomiale
for (k=0; k<=degre; k++)
P = P + DDN[k] * PC[i-degre+k]->XyzSommet[0];
}
else
{ //courbe rationnelle
R N[2+64]; //valeur des fonctions de base utiles en u
R DN[2+64]; //valeur de la derivee des fonctions de base utiles en u
R Omega, OmegaDerivee1, OmegaDerivee2;
R Np, NpD, NpDD;
R3 DP=R3(0,0,0), DDP=R3(0,0,0);
int l;

// C3Omega(u) = 3-eres coordonnees de COmega(u)
// Omega(u) = denominateur de C(u)
// C''(u) = ( C3Omega''(u) Omega(u)*2 - C3Omega'(u) 2 Omega(u) Omega'(u)
// + C3Omega(u) ( 2 Omega'(u)**2 - Omega(u) Omega''(u) ) / Omega(u)**3

ValeurBaseNURBS( i, degre, u, N ); //valeur en u de la base N
Derivee1BaseNURBS( i, u, DN ); //valeur en u de la derivee premiere de la base N'

Omega = OmegaDerivee1 = OmegaDerivee2 = 0;

for (k=0; k<=degre; k++)
{
l = i-degre+k;

Np = N[k] * Poids[l];
Omega += Np; //denominateur de C(u)
P += Np * PC[l]->XyzSommet[0]; //numerateur de C(u)

NpD = DN[k] * Poids[l];
OmegaDerivee1 += NpD; //derivee du denominateur de C(u)
DP += NpD * PC[l]->XyzSommet[0]; //C3Omega'(u)

NpDD = DDN[k] * Poids[l];
OmegaDerivee2 += NpDD; //derivee du denominateur de C(u)
DDP += NpDD * PC[l]->XyzSommet[0]; //C3Omega''(u)
}

P = ( DDP * pow(Omega,2) //C''(u)
- DP * (2*Omega*OmegaDerivee1)
+ P * (2*pow(OmegaDerivee1,2)-Omega*OmegaDerivee2) )
/ pow(Omega,3);
}
}


void Ligne::Derivee3CourbeNURBS( R u, R3 & P )
//les composantes de la derivee seconde a la courbe NURBS en u
{
R DDDN[4+64]; //valeur de la derivee troisieme des fonctions de base utiles en u
int i,k;

i = IntervalleNURBS(u); //u contenu dans [U(i)<U(i+1)[

P.x = P.y = P.z = 0.0;

Derivee3BaseNURBS( i, u, DDDN ); //valeur en u de la derivee troisieme de la base N'''

if( Poids == NULL )
{ //courbe polynomiale
for (k=0; k<=degre; k++)
P = P + DDDN[k] * PC[i-degre+k]->XyzSommet[0];
}
else
{ //courbe rationnelle
R N[1+64]; //valeur des fonctions de base utiles en u
R DN[2+64]; //valeur de la derivee des fonctions de base utiles en u
R DDN[3+64]; //valeur de la derivee des fonctions de base utiles en u
R Omega, OmegaDerivee1, OmegaDerivee2, OmegaDerivee3;
R Np, NpD, NpDD, NpDDD;
R3 DP=R3(0,0,0), DDP=R3(0,0,0), DDDP=R3(0,0,0);
int l;

// C3Omega(u) = 3-eres coordonnees de COmega(u)
// Omega(u) = denominateur de C(u)
// C'''(u) = ( C3Omega'''(u) Omega(u)**3 + C3Omega''(u) ( -3 Omega(u)**2 Omega'(u) )
// + C3Omega'(u) ( -3 Omega(u)**2 Omega''(u) + 6 Omega(u) Omega'(u)**2 )
// + C3Omega(u) ( 6 Omega(u) Omega'(u) Omega''(u) - Omega(u)**2 Omega'''(u)
// - 6 Omega'(u)**3 ) )
// / Omega(u)**4

ValeurBaseNURBS( i, degre, u, N ); //valeur en u de la base N
Derivee1BaseNURBS( i, u, DN ); //valeur en u de la derivee premiere de la base N'
Derivee2BaseNURBS( i, u, DDN ); //valeur en u de la derivee seconde de la base N''

Omega = OmegaDerivee1 = OmegaDerivee2 = OmegaDerivee3 = 0;

for (k=0; k<=degre; k++)
{
l = i-degre+k;

Np = N[k] * Poids[l];
Omega += Np; //denominateur de C(u)
P += Np * PC[l]->XyzSommet[0]; //numerateur de C(u)

NpD = DN[k] * Poids[l];
OmegaDerivee1 += NpD; //derivee1 du denominateur de C(u)
DP += NpD * PC[l]->XyzSommet[0]; //C3Omega'(u)

NpDD = DDN[k] * Poids[l];
OmegaDerivee2 += NpDD; //derivee2 du denominateur de C(u)
DDP += NpDD * PC[l]->XyzSommet[0]; //C3Omega''(u)

NpDDD = DDDN[k] * Poids[l];
OmegaDerivee3 += NpDDD; //derivee3 du denominateur de C(u)
DDDP += NpDDD * PC[l]->XyzSommet[0]; //C3Omega'''(u)
}

P = ( DDDP * pow(Omega,3) //C'''(u)
- DDP * ( 3 * pow(Omega,2) * OmegaDerivee1 )
+ DP * (-3*pow(Omega,2)*OmegaDerivee2 + 6*Omega*pow(OmegaDerivee1,2) )
+ P * ( 6*Omega*OmegaDerivee1*OmegaDerivee2
-pow(Omega,2)*OmegaDerivee3 -6*pow(OmegaDerivee1,3)) )
/ pow(Omega,4);
}
}

void Ligne::CourbureNormaleNURBS( R u, R3 & D, R3 & DD,
R3 & n, R3 & bn, R & Courbure )
//Calcul de la courbure et du vecteur normal au noeud u d'une courbe NURBS
{
R s,ss;

if( degre<=0 )
{ D=DD=n=bn=R3(0,0,0); Courbure=0; return; }

Derivee1CourbeNURBS( u, D ); //C' (u)
s = (D,D); // (C'(u),C'(u))
if( s<=0 || degre<=1 )
{ DD=n=bn=R3(0,0,0); Courbure=0; return; }

Derivee2CourbeNURBS( u, DD ); //C''(u)
//d2h(s)/ds2 = Courbure Normale = ( C"(u) (C'(u),C'(u)) - C'(u) (C'(u),C"(u)) ) / ||C'(u)||4
ss = (D,DD);
n = ( (DD * s) - (D * ss) ) / pow(s,2);

Courbure = Norme2( n ); //la courbure
if( Courbure<=0 ) { bn=R3(0,0,0); return; }
n = n / Courbure; //le vecteur normal

bn = D^n;
ss = Norme2( bn );
if( ss<=0 ) return;
bn = bn / ss; //le vecteur binormal
//cout << "Courbure=" << Courbure << " Normale=" << n << " BiNormale=" << bn << endl;
}

void Ligne::TorsionBiNormaleNURBS( R u, R3 & D, R3 & DD, R3 & DDD, R3 & n, R3 & bn,
R & Courbure, R & Torsion )
//Calcul de la derivee premiere, seconde, courbure et du vecteur normal
//de la torsion et du vecteur binormal au noeud u d'une courbe NURBS
{
R3 DvDD;

CourbureNormaleNURBS( u, D, DD, n, bn, Courbure );
if( degre<=2 )
{ Torsion=0; return; }

Derivee3CourbeNURBS( u, DDD ); //C'''(u)
DvDD = D^DD;
Torsion = - (DvDD,DDD) / (DvDD,DvDD); // - (C'(u)^C''(u),C'''(u)) / ||C'(u)^C''(u)||2
cout << "Torsion=" << Torsion << endl;
}


R Ligne::LongueurNURBS()
//approximation de la longueur de la courbe
{
int j, k;
R longueur, u, h;
R3 Q0, Q1;

Q0=PC[0]->XyzSommet[0]; //le point initial
longueur=0.0;
u=U[0];
for (k=degre; k<=nbn; k++)
{
if(U[k]<U[k+1]) //intervalle non vide des noeuds
{
h=(U[k+1]-U[k])/8;
for (j=1; j<=8; j++) //8 sous intervalles
{
u = u + h;
PointCourbeNURBS( u, Q1 );
longueur += Norme2( Q1 - Q0 ); //longueur de la corde
Q0 = Q1;
}
}
}
//cout << "longueur de la courbe NURBS=" << longueur << endl;
return longueur;
}

void Ligne::InsererNoeudNURBS( Points *LesPoints, R u, Z NbInsertion )
{ //Inserer le noeud u NbInsertion fois et sa multiplicite reste <=degre
R a;
int i,j,m;

if( u<=U[degre] || u>=U[nbn+1] ) return; //ces noeuds extremes sont de multiplicite degre+1

m = MultipliciteDuNoeud( u, i ); //U[i]<=u<U[i+1] sauf u=[nbn+1] => i=nbn

if( m<0 || m>=degre ) return; //u exterieur ou u de multiplicite degre
NbInsertion = Min( NbInsertion, degre-m ); //Nombre final d'insertions a faire
if( NbInsertion<=0 ) return;

R * UU = new R[1+nbn+NbInsertion+degre+1];//la declaration du tableau des nouveaux noeuds
for ( j=0; j<=i; j++ ) //les noeuds avant u
UU[j] = U[j];
for ( j=i+1; j<=i+NbInsertion; j++ ) //les noeuds u
UU[j] = u;
for (j=i+1; j<=nbn+degre+1; j++) //les noeuds apres u
UU[j+NbInsertion] = U[j];

Point ** QC = new Point *[nbn+1+NbInsertion]; //la declaration du tableau des pointeurs
//sur les nouveaux points de controle de la courbe NURBS
R * PoidsQC=NULL;
if( Poids!=NULL ) PoidsQC = new R[nbn+1+NbInsertion]; //les nouveaux poids

//Les points de controle et poids non encore modifies de 0 a i-degre
for (j=0; j<=i-degre; j++)
{
QC[j] = PC[j];
if( Poids!=NULL ) PoidsQC[j] = Poids[j];
}

Nom nomp; //Construction des nouveaux points QC
int k;
for (j=i-degre+1; j<=i+NbInsertion-1; j++)
{
NommerPoint( nomp ); //Nom du nouveau point QC de controle
if(j<=nbn) k=j; else k=i;
QC[j] = new Pointxyz( nomp,
PC[k]->XyzSommet[0].x, //L'abscisse
PC[k]->XyzSommet[0].y, //L'ordonnee
PC[k]->XyzSommet[0].z); //La cote
if( Poids!=NULL ) PoidsQC[j] = Poids[k];
LesPoints->Ajouter1Point( QC[j] ); // ajout du Point a l'ensemble des Points
}

//Initialisation des derniers QC par les derniers PC
for (j=i+NbInsertion; j<=nbn; j++)
{
QC[j] = PC[j];
if( Poids!=NULL ) PoidsQC[j] = Poids[j];
}

//Si Poids passage des QC[3] aux QComega[4] x y z => omegax, omegay, omegaz, omegs
if( Poids!=NULL )
{
k=Max(nbn,i+NbInsertion-1);
for (j=0; j<=k; j++)
QC[j]->XyzSommet[0] = QC[j]->XyzSommet[0] * PoidsQC[j];
}

//NbInsertion du noeud u au dela du noeud i
for (j=1; j<=NbInsertion; j++) //NbInsertion du noeud u
{
for (k=i+j-1; i<k; k--) //decalage des XYZ des derniers QC
{
QC[k]->XyzSommet[0] = QC[k-1]->XyzSommet[0];
if( Poids!=NULL ) PoidsQC[k] = PoidsQC[k-1];
}

for (k=i; i-degre+j<=k; k--) //n1=i-degre+j 1-er point modifie par l'insertion j
{
a = (u-U[k]) / (U[k+degre-j+1]-U[k]);
QC[k]->XyzSommet[0] = (1-a) * QC[k-1]->XyzSommet[0] + a * QC[k]->XyzSommet[0];
if( Poids!=NULL ) PoidsQC[k] = (1-a) * PoidsQC[k-1] + a * PoidsQC[k];
}
}

//Si Poids passage des QComega[4] aux QC[3] omegax, omegay, omegaz, omega => x y z
if( Poids!=NULL )
{
for (j=0; j<=i+NbInsertion-1; j++)
QC[j]->XyzSommet[0] = QC[j]->XyzSommet[0] / PoidsQC[j];
}

//Mise a jour des derniers points et poids de controle
for (j=nbn+NbInsertion; j>=i+NbInsertion; j--)
{
QC[j]=PC[j-NbInsertion];
if( Poids!=NULL ) PoidsQC[j] = Poids[j-NbInsertion];
}

//destruction des anciennes donnees de la courbe NURBS
if( U != NULL ) delete [] U;
if( PC != NULL ) delete [] PC;
if( Poids!= NULL ) delete [] Poids;

//mise a jour des nouvelles donnees de la courbe NURBS
nbn += NbInsertion;
U = UU;
PC = QC;
Poids = PoidsQC;
}


int Ligne::Mailler(Points *LesPoints)
{
Z j, m;
R h, u;

if (TailleArete<=0) return 2;
//cout << "Ligne::Mailler TailleArete=" << TailleArete << endl;
//cout << "Ligne::Mailler LongueurNURBS()=" << LongueurNURBS() << endl;
NbEF = (Z) (LongueurNURBS() / TailleArete + 0.5); //version simpliste!
//cout << "Ligne::Mailler NbEF=" << NbEF << endl;
if ( NbEF < 1 ) NbEF=1;
NbSommet = NbEF+1;
XyzSommet = new R3[NbSommet]; //les coordonnees des sommets

h=(U[nbn+1]-U[0])/NbEF; //le pas dans l'intervalle des U
u=U[0];

XyzSommet[0]=PC[0]->XyzSommet[0]; //le calcul des coordonnees des sommets
for (j=1; j<NbSommet-1; j++)
{
//le j-eme sommet
u += h;
PointCourbeNURBS( u, XyzSommet[j] );

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, XyzSommet[j] );
PtMAX = Max( PtMAX, XyzSommet[j] );
}
//cout << "Ligne::Mailler NbSommet=" << NbSommet << " PtMAX=" << PtMAX << endl;

XyzSommet[NbSommet-1]=PC[nbn]->XyzSommet[0];
//cout << "Ligne NURBS " << nom << " Nombre de Sommets=" << NbSommet << endl;

// Numero initial et final des NbEF de la ligne NURBS
NbStEF = 2;
NoStEF = new Z[NbEF*NbStEF]; // Tableau NoStEF[NbEF][NbStEF]
for (j=0; j<NbEF; j++)
{
m = NbStEF * j;
NoStEF[m] = j+1; // Attention sommet initial de no 1 et non 0
NoStEF[m+1] = j+2; // Sommet final de no Nbsommets=NbEF+1
}
//cout << "Ligne NURBS " << nom << " Nombre d'Aretes =" << NbEF <<endl;
return 0;
}

void Ligne::AfficherMaillage()
{
Z i,m;

//Maillage d'une LIGNE forme de NbStEF ARETES
cout << "Nom de la Ligne=" << PLSV::nom <<endl;

cout << "Nombre de Sommets=" << NbSommet <<endl;
for (i=0; i<NbSommet; i++ )
{
cout << "Sommet " << setw(5) << i+1
<< " X=" << setw(14) << XyzSommet[i].x
<< " Y=" << setw(14) << XyzSommet[i].y
<< " Z=" << setw(14) << XyzSommet[i].z << endl;
}
cout << endl;

cout << "Nombre d'Aretes=" << NbEF <<endl;
for (i=0; i<NbEF; i++ )
{
m = NbStEF * i;
cout << "Arete " << setw(5) << i+1
<< " [S" << NoStEF[m] << "-S" << NoStEF[m+1] << "]" << endl;
}
cout << endl;
}

R3 Ligne::PointMilieuLigne()
{
if( XyzSommet == NULL || NoStEF == NULL )
{ return R3(0,0,0); }
else
{
//le Point "milieu" de la Ligne est le milieu de l'arete NbEF/2
return ( XyzSommet[NoStEF[NbEF]] + XyzSommet[NoStEF[NbEF-1]] ) / 2;
}
}

void Ligne::Elevation1Degre(Points *LesPoints)
{ //le degre des polynomes est augmente de 1 sans modifier la courbe
cout << "Pas d'elevation du degre pour ce type de courbe" << endl;
}

void Ligne::TracerMaillage(MemoirePx3d & mpx)
{
Z i, m, ns1, ns2;
char texte[1+25];
R3 xyz;

//trace du maillage d'une LIGNE par le trace de ses NbStEF aretes
VuChoisirFonte( hauttexte );
VuEpaisseur( 2 );
m = 0;
for (i=0; i<NbEF; i++ )
{
ns1 = NoStEF[m++]-1; //Sommet 1 de l'arete i
ns2 = NoStEF[m++]-1; //Sommet 2 de l'arete i
VuCouleur( Orange );
mpx.VuTrait( XyzSommet[ns1], XyzSommet[ns2] );
VuCouleur( Noir );
mpx.VuSymbole( XyzSommet[ns1], ":" );
}

//le "milieu" de la Ligne supporte la poignee
xyz = PointMilieuLigne();
//trace de la poignee de la ligne
strcpy( texte, "*" );
strcat( texte, nom );
VuCouleur( Noir );
mpx.VuSymbole( xyz, texte );

//le trace du polygone de controle de la ligne NURBS
TracerPolygone(mpx);

//le trace des vecteurs derivees aux noeuds de la ligne NURBS
if( TraceTg + TraceNormales ) TracerDeriveeNURBS(mpx);
}

void Ligne::TracerPolygone(MemoirePx3d & mpx)
{
Z i;

if( degre>1 )
{
//Trace des segments entre 2 Points de controle successifs de la courbe
VuEpaisseur( 2 );
for (i=0; i<nbn; i++ )
{ //Trace du segment PC[i]->PC[i+1]
VuCouleur( Rose );
mpx.VuTrait( PC[i]->XyzSommet[0], PC[i+1]->XyzSommet[0] );
}
}

//Trace des points de controle toujours au dessus des segments
for (i=0; i<=nbn; i++ )
PC[i]->TracerMaillage(mpx);
}

void Ligne::TracerDeriveesNURBS( MemoirePx3d & mpx, R u )
//Trace des vecteurs derivees en la valeur u du parametre de la courbe
{
R courbure, torsion;
R3 Cu, D, DD, DDD, n, bn;

PointCourbeNURBS( u, Cu ); //le point C(u)

if( TraceTg && degre>0 )
{
VuCouleur( Rouge );
Derivee1CourbeNURBS( u, D ); //la tangente C'(u) et Trace du segment Cu -> Cu+Tg
mpx.VuVecteur( Cu, D );
}

if( TraceNormales )
{
TorsionBiNormaleNURBS( u, D, DD, DDD, n, bn, courbure, torsion );
//C'(u), C''(u), C'''(u), normale et binormale, courbure et torsion
VuCouleur( Vert );
mpx.VuVecteur( Cu, DD ); //Trace du segment C(u) -> C(u)+C''(u)
VuCouleur( Turquoise );
mpx.VuVecteur( Cu, n*courbure ); //Trace du segment C(u) -> C(u)+courbure Normale
VuCouleur( Bleu );
mpx.VuVecteur( Cu, DDD ); //Trace du segment C(u) -> C(u)+C'''(u)
VuCouleur( Magenta );
mpx.VuVecteur( Cu, bn*torsion ); //Trace du segment C(u) -> C(u)+torsion BiNormale
}
}


void Ligne::TracerDeriveeNURBS( MemoirePx3d & mpx )
{
Z i;

if( degre>1 )
{
VuEpaisseur( 0 );
//Trace des vecteurs derivees de la courbe
TracerDeriveesNURBS( mpx, U[degre] ); //au noeud initial
for (i=degre; i<=nbn+1; i++ )
{
if( U[i]!=U[i+1] )
TracerDeriveesNURBS( mpx, (U[i]+U[i+1])*0.5 ); //au milieu d'intervalle [U[i],U[i+1][
}
TracerDeriveesNURBS( mpx, U[nbn+1] ); //au noeud final
}
}

void Ligne::DeplacerPC( Points * LesPoints, Point * PPointCourant )
//Deplacer a l'aide de la souris un Point de controle d'une courbe NURBS
{
XPoint pxy, pxyaccr0={-1,-1};
int notyev, nbc;
R3 Pt0, Pt, Pta;

//copie de mpxPLSV dans mpxModif
fenoupix = mpxModif.mempx; //protection du mempx
mpxModif = mpxPLSV; //mise a jour de fenetre et axonometrie
mpxModif.mempx = fenoupix;
//effacer l'eventuel mpxModif deja trace
mpxModif.VuEffacerMemoirePx();

mpxInvite.VuInvite( "Cliquer le POINT de CONTROLE a DEPLACER ou frapper son NOM" );
PPointCourant = LesPoints->Points::CliquerPoint();
if( PPointCourant == NULL ) return; //ABANDON
Pt0 = PPointCourant->XyzSommet[0]; //Sauvegarde des coordonnees initiales du point

//Modifier XYZ du Point de controle => Deplacer le Point avec la souris
//====================================================
PCdeLigneADeplacer:
mpxInvite.VuInvite( "Cliquer la NOUVELLE POSITION du Point ou frapper X" );
mpxInvite.VuSourisXYZ( notyev, nbc, pxy, Pt );
switch( notyev )
{
case 0: //ABANDON demande
PPointCourant->XyzSommet[0] = Pt0; //Restauration des coordonnees initiales
return;

case -2: //deplacement de la souris. Materialisation de l'accrochage
case -1: //une touche de la souris enfoncee et non relachee
if( (pxyaccr0.x!=-1) && (pxyaccr0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxyaccr0 );
pxyaccr0.x = -1;
pxyaccr0.y = -1; //reinitialisation a vide
}

if( ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, Pt )==0 ) goto PCdeLigneADeplacer;
//retourne 1 si Pt est le point projete dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible
PPointCourant->XyzSommet[0] = Pt;

//fenetre_vu est initialise avec mpxPLSV
mpxPLSV.VuCombinerMemoirePxDansFenetre( GXcopy,
pxy0, mpxPLSV.largeurpx, mpxPLSV.hauteurpx, //source
pxy0 ); //destination
//ajout du mpxAccroche a fenetre_vu
if( mpxPLSV.visee==3 ) mpxPLSV.Vuxyzaxo( Pt, Pta ); else Pta=Pt;
pxyaccr0.x = mpxPLSV.Vunupxex( Pta.x )- mpxAccroche.largeurpx/2;
pxyaccr0.y = mpxPLSV.Vunupxey( Pta.y )- mpxAccroche.hauteurpx/2;
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxyaccr0 );
//effacer le mpxModif deja trace
mpxModif.VuEffacerMemoirePx();
Mailler(LesPoints); //reconstruction du maillage de la courbe NURBS
TracerMaillage(mpxModif); //trace dans mpxModif de la nouvelle ligne

//la ligne est ajoutee dans fenetre_vu
mpxModif.VuCombinerMemoirePxDansFenetre( GXand,
pxy0, mpxModif.largeurpx, mpxModif.hauteurpx, //source
pxy0 ); //destination
goto PCdeLigneADeplacer;

case 1:
if( ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, PPointCourant->XyzSommet[0] )==0 )
goto PCdeLigneADeplacer;
//retourne si 1 si XyzSommet[0] est le point projete dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible
break;

case 2: //frappe de XYZ au clavier
PPointCourant->XyzSommet[0] = Pt;
}

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, PPointCourant->XyzSommet[0] );
PtMAX = Max( PtMAX, PPointCourant->XyzSommet[0] );

PPointCourant->date = Secondes1970(); //nouvelle date du point modifie
}


//------------------------------------------------------------------------------

void LigneDroite::LigneDroiteNURBS()
{
degre = 1;
nbn = 1;
PC = new Point *[1+nbn]; //la declaration du tableau des 2 points de controle
PC[0]=PtInitial;
PC[1]=PtFinal;

U = new R[1+nbn+1+degre]; //la declaration du tableau des 4 noeuds
U[0]=U[1]=0;
U[2]=U[3]=Norme2( PtFinal->XyzSommet[0] - PtInitial->XyzSommet[0] );

Poids = NULL; //Pas de poids
}

LigneDroite::LigneDroite(Points *LesPoints)
{
// La definition de la Ligne Droite par saisie a la souris des 2 Points
mpxInvite.VuInvite( "Cliquer le POINT INITIAL de la droite ou frapper son NOM" );
PtInitial = LesPoints->Points::CliquerPoint();
if( PtInitial == NULL ) { NbSommet=0; NoLigne--; return; }

mpxInvite.VuInvite( "Cliquer le POINT FINAL de la droite ou frapper son NOM" );
PtFinal = LesPoints->Points::CliquerPoint();
if( PtFinal == NULL ) { NbSommet=0; NoLigne--; return; }
mpxInvite.VuEffacerMemoirePx();

//Definition de la courbe NURBS equivalente
LigneDroiteNURBS();

// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Ligne::Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}


LigneDroite::LigneDroite(Points *LesPoints, Nom NomLg,
Nom ptinitial, Nom ptfinal)
:Ligne( NomLg )
{
Point *PtAvant;
PtInitial = LesPoints->Points::RetrouverPoint( ptinitial, PtAvant );
PtFinal = LesPoints->Points::RetrouverPoint( ptfinal, PtAvant );

//Definition de la courbe NURBS equivalente
LigneDroiteNURBS();

// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Ligne::Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}

/*
int LigneDroite::Mailler(Points *LesPoints)
{
// Le maillage de la LigneDroite:
// Construction des Coordonnees des Sommets et No des Sommets des Aretes
Z i, m;

R dist = LesPoints->Points::Dist2Pt( PtInitial, PtFinal );
if (dist<=0) return 1;

if ( TailleArete <=0 ) return 2;
NbEF = (Z) (dist / TailleArete + 0.5);
if ( NbEF < 1 ) NbEF=1;
NbSommet = NbEF+1;

XyzSommet = new R3[NbSommet]; // Les coordonnees des NbSommet sommets

XyzSommet[0] =PtInitial->XyzSommet[0]; //dans R3
XyzSommet[NbSommet-1]=PtFinal->XyzSommet[0]; //dans R3

R h;
Z j;
for (i=0; i<3; i++)
{
h=(XyzSommet[NbSommet-1][i]-XyzSommet[0][i])/NbEF;
for (j=1; j<NbSommet-1; j++)
XyzSommet[j][i]=XyzSommet[0][i] + h * j;
}
cout << "Ligne DROITE" << nom << " Nombre de Sommets=" << NbSommet <<endl;

// Numero initial et final des NbEF de la ligne droite
NbStEF = 2;
NoStEF = new Z[NbEF*NbStEF];
m = 0;
for (i=0; i<NbEF; i++)
{
NoStEF[m++] = i+1; // Attention sommet initial de no 1 et non 0
NoStEF[m++] = i+2; // Sommet final de no Nbsommets=NbEF+1
}
cout << "Ligne DROITE" << nom << " Nombre d'Aretes =" << NbEF <<endl;
return 0;
}
*/

void LigneDroite::AfficherDefinition()
{
cout << "Nom de la Ligne DROITE= " << nom
<< " Nom du Point Initial= " << PtInitial->nom
<< " Nom du Point Final= " << PtFinal->nom << endl;
}

void LigneDroite::VerifierMaillage(Points *LesPoints)
{
if( PtInitial->date > this->date || PtFinal->date > this->date ) Mailler(LesPoints);
}


//------------------------------------------------------------------------------

void LigneCercle::LigneCercleNURBS(Points *LesPoints)
{
Nom nomp;
Z i;

degre = 2;
nbn = 8;
PC = new Point *[1+nbn]; //la declaration du tableau des 9 points de controle
R3 tmpSCG, *tmpSCU;

//construction des 8 nouveaux points de controle
NommerPoint( nomp );
tmpSCU = new R3(rayon,0,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[0] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[0] ); // ajout du Point a l'ensemble des Points

NommerPoint( nomp );
tmpSCU = new R3(rayon,rayon,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[1] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[1] ); // ajout du Point a l'ensemble des Points

NommerPoint( nomp );
tmpSCU = new R3(0,rayon,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[2] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[2] ); // ajout du Point a l'ensemble des Points

NommerPoint( nomp );
tmpSCU = new R3(-rayon,rayon,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[3] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[3] ); // ajout du Point a l'ensemble des Points
NommerPoint( nomp );
tmpSCU = new R3(-rayon,0,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[4] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[4] ); // ajout du Point a l'ensemble des Points

NommerPoint( nomp );
tmpSCU = new R3(-rayon,-rayon,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[5] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[5] ); // ajout du Point a l'ensemble des Points

NommerPoint( nomp );
tmpSCU = new R3(0,-rayon,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[6] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[6] ); // ajout du Point a l'ensemble des Points

NommerPoint( nomp );
tmpSCU = new R3(rayon,-rayon,0);
VecteurScuScg( SCU, *tmpSCU, tmpSCG);
free(tmpSCU);
PC[7] = new Pointxyz( nomp,
PtCentre->XyzSommet[0].x + tmpSCG.x,
PtCentre->XyzSommet[0].y + tmpSCG.y,
PtCentre->XyzSommet[0].z + tmpSCG.z);
LesPoints->Ajouter1Point( PC[7] ); // ajout du Point a l'ensemble des Points

PC[nbn] = PC[0];

U = new R[1+nbn+1+degre]; //la declaration du tableau des 12 noeuds
U[0]=U[1]=U[2]=0;
U[3]=U[4]=0.25;
U[5]=U[6]=0.5;
U[7]=U[8]=0.75;
U[9]=U[10]=U[11]=1;

Poids = new R[1+nbn]; //la declaration du tableau des 9 Poids
Poids[0]=Poids[2]=Poids[4]=Poids[6]=Poids[8]=1;
Poids[1]=Poids[3]=Poids[5]=Poids[7]=1./sqrt(2.);

for (i=0; i<=7; i++)
{
//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, PC[i]->XyzSommet[0] );
PtMAX = Max( PtMAX, PC[i]->XyzSommet[0] );
}
}

LigneCercle::LigneCercle(Points *LesPoints)
{
XPoint pxy0={0,0}, pxy, pxyc0, pxyc;
int notyev, nbc, rayc, rayc0=-1 ;
R3 PtDuCercle;

R3 PtCentreSCU;
R3 PtBord, PtBordSCU, PtOpposeSCU, PtQuartCercleSCU;
XPoint pxyt, pxyq;
char messageInvite[128];


//saisie du Point Centre du cercle
mpxInvite. VuInvite( "Cliquer le point CENTRE du cercle ou frapper son NOM" );
PtCentre = LesPoints->Points::CliquerPoint();
if( PtCentre == NULL ) { NbSommet=0; NoLigne--; return; }

if ( mpxPLSV.visee == 2 ) {
//coordonnees pixels du centre du cercle en 2D
pxyc.x = mpxPLSV.Vunupxex( PtCentre->XyzSommet[0].x );
pxyc.y = mpxPLSV.Vunupxey( PtCentre->XyzSommet[0].y );
//cout << "Centre du cercle (2D) : " << PtCentre->XyzSommet[0];
//cout << " => (Pixel) : ("<< pxyc.x << "," << pxyc.y << ")" << endl;
} else if ( mpxPLSV.visee == 3 ) {
mpxPLSV.Vuxyzaxo( PtCentre->XyzSommet[0], PtCentreSCU);
pxyc.x = mpxPLSV.Vunupxex( PtCentreSCU.x );
pxyc.y = mpxPLSV.Vunupxey( PtCentreSCU.y );
//cout << "Centre du cercle (3D) : " << PtCentreSCU ;
//cout << " => (Pixel) : ("<< pxyc.x << "," << pxyc.y << ")" << endl;
}

//saisie a la souris d'un Point du Cercle
rayon = 0;
while (rayon<=0 )
{
mpxInvite.VuInvite( "Cliquer un point SUR le cercle ou frapper X" );
PointSurCercle:
mpxInvite.VuSourisXYZ( notyev, nbc, pxy, PtDuCercle );
if( notyev == 0 )
{ NbSommet=0; NoLigne--; return; } //ABANDON demande
else if( notyev < 0 ) //souris deplacee ou bouton enfonce => Trace du cercle
{
//le rayon du cercle en pixels
rayc = (int) sqrt( pow(R(pxy.x-pxyc.x),2) + pow(R(pxy.y-pxyc.y),2) );
if( rayc0 == rayc ) goto PointSurCercle;
if( rayc0 != -1 ) //le cercle ancien est efface
{
//Restauration de mpxPLSV dans fenetrecran
mpxPLSV.VuCombinerMemoirePxDansFenetre( GXcopy,
pxy0, mpxPLSV.largeurpx, mpxPLSV.hauteurpx,
pxy0 );
rayc0 = -1;
}

//copie de mpxPLSV dans mpxModif pour definir la visee
fenoupix = mpxModif.mempx; //protection du mempx
mpxModif = mpxPLSV; //mise a jour des donnees de fenetre et axonometrie
mpxModif.mempx = fenoupix; //restauration du mempx

//trace du nouveau cercle de centre pxyc et de rayon rayc dans mpxModif
mpxModif.VuEffacerMemoirePx();
rayon = (R) rayc;
VuCouleur( Bleu );
VuEpaisseur( 0 );

if ( mpxPLSV.visee == 2 ) {
mpxModif.VuBordArcEllipse( pxyc, rayc, rayc, 0.0, 360.0 );
} else if ( mpxPLSV.visee == 3 ) {
R3 PtBordSCG, PtOpposeSCG, PtCentreSCG, tmpR3;
R3 PtQuartCercleSCG;

ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, PtBordSCU );
rayon = Norme2( PtBordSCU - PtCentre->XyzSommet[0] );
//PtOpposeSCU = 2*PtCentre->XyzSommet[0] - PtBordSCU;

PtQuartCercleSCG = PtCentre->XyzSommet[0];
//PtQuartCercleSCU = R3 ( rayon/sqrt(2), rayon/sqrt(2), 0) ;
PtQuartCercleSCU = R3 ( 1, 0, 0) ;
VecteurScuScg( SCU, PtQuartCercleSCU, tmpR3 );
PtQuartCercleSCG = PtQuartCercleSCG + tmpR3;
//cout << "Centre : " << PtCentre->XyzSommet[0] << "\n";
//cout << "1/4 Cercle : " << PtQuartCercleSCG << endl;

//VecteurScuScg( SCU, PtBordSCU , PtBordSCG );
//VecteurScuScg( SCU, PtOpposeSCU, PtOpposeSCG );
//VecteurScuScg( SCU, PtCentre->XyzSommet[0], PtCentreSCG );

mpxPLSV.Vuxyzaxo( PtQuartCercleSCG, tmpR3 );
pxyt.x = mpxPLSV.Vunupxex( tmpR3.x );
pxyt.y = mpxPLSV.Vunupxey( tmpR3.y );

//cout << "\nCentre : " << PtCentre->XyzSommet[0] <<" "<< PtCentreSCG
// << "\nBord : " << PtBordSCU << " " << PtBordSCG
// << "\nOppose : " << PtOpposeSCU << " " << PtOpposeSCG << endl;

int rx = (int) fabs( (pxyc.x - pxy.x) );
int ry = (int) fabs( (pxyc.y - pxy.y) );

tmpR3.x = fabs( mpxPLSV.Vuxob2px( rx ) );
tmpR3.y = fabs( mpxPLSV.Vuyob2px( ry ) );
//cout << "(rx,ry) = (" << rx << "," << ry << ")\n";

//sprintf( messageInvite, "Rayon objet : %f", rayon);
//sprintf( messageInvite, "(R3.x,R3.y) : (%f,%f)", tmpR3.x, tmpR3.y);
sprintf( messageInvite, "(pxyt.x,pxyt.y) : (%d,%d)", pxyt.x, pxyt.y);
mpxInvite.VuInvite( messageInvite );
VuCouleur( Bleu );
//mpxModif.MemoirePx::VuTrait( pxyc, pxy );
mpxModif.MemoirePx::VuTrait( pxyc, pxyt );
//mpxModif.VuBordArcEllipse( pxyc, pxyt.x, pxyt.y, 0.0, 360.0 );
//mpxModif.VuBordArcEllipse( pxyc, ry, rx, 0.0, 360.0 );
mpxModif.VuBordArcEllipse( pxyc, rx, ry, 0.0, 360.0 );
}
//combinaison de mpxPLSV dans la fenetre
pxyc0.x = pxyc.x-rayc; pxyc0.y = pxyc.y-rayc; rayc0 = rayc;
mpxModif.VuCombinerMemoirePxDansFenetre( GXand,
pxyc0, 2*rayc0+2, 2*rayc0+2,
pxyc0 );
goto PointSurCercle;
}
else if( notyev == 1 )
{
if( rayc0 != -1 ) //le cercle ancien est efface
{
//Restauration de mpxPLSV dans fenetrecran
mpxPLSV.VuCombinerMemoirePxDansFenetre( GXcopy,
pxy0, mpxPLSV.largeurpx, mpxPLSV.hauteurpx,
pxy0 );

//mpxModif.VuCombinerMemoirePxDansFenetre( GXxor,
// pxyc0, 2*rayc0+2, 2*rayc0+2,
// pxyc0 );
rayc0 = -1;
}

//transformation des coordonnees pixels en coordonnees 2d
PtDuCercle.x = mpxPLSV.Vuxob2px( pxy.x );
PtDuCercle.y = mpxPLSV.Vuyob2px( pxy.y );
PtDuCercle.z = 0;
if ( mpxPLSV.visee == 3 ) {
ProjectionClicSourisSCU( mpxPLSV, SCU, pxy, PtDuCercle );
}
//le rayon du cercle
rayon = Norme2( PtDuCercle - PtCentre->XyzSommet[0] );
//cout << "Point clique : " << PtDuCercle ;
//cout << " => (Pixel) : ("<< pxy.x << "," << pxy.y << ")" << endl;
//cout << "Rayon du cercle (Pixel/Objet) : " << rayc << "/" << rayon <<endl;
}
else if( notyev == 2 )
{
//le rayon du cercle
//cout << "Saisie clavier ..." << endl;
rayon = Norme2( PtDuCercle - PtCentre->XyzSommet[0] );
}
}
mpxInvite.VuEffacerMemoirePx();

//Definition de la courbe NURBS equivalente
//cout << "RAYON=" << rayon << endl;
LigneCercleNURBS(LesPoints);

// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}

LigneCercle::LigneCercle(Points *LesPoints, Nom NomLg,
Nom ptcentre, R Rayon) :Ligne( NomLg )
{
Point *PtAvant;

PtCentre = LesPoints->Points::RetrouverPoint( ptcentre, PtAvant );
rayon = Rayon;

//Definition de la courbe NURBS equivalente
LigneCercleNURBS(LesPoints);

// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}

/*
int LigneCercle::Mailler(Points *LesPoints)
{
Z j,m;

if (rayon<=0) return 1;
if (TailleArete<=0) return 2;
if (degre>0) //maillage en tant que ligne NURBS
{ Mailler(LesPoints); return 0; }

//Le dessous est inactif!
NbStEF = 2;
NbEF = (Z) (atan(1) * 8 * rayon / TailleArete + 0.5);
if ( NbEF < 1 ) NbEF=1;
NbSommet = NbEF+1;
XyzSommet = new R3[NbSommet]; // Les coordonnees des sommets

R Angle = atan(1) * 8 / NbEF; // Angle du secteur en radians

XyzSommet[0].x=PtCentre->XyzSommet[0].x + rayon;
XyzSommet[0].y=PtCentre->XyzSommet[0].y;
XyzSommet[0].z=0;
for (j=1; j<NbSommet-1; j++)
{
//le j-eme sommet
XyzSommet[j].x=PtCentre->XyzSommet[0].x + rayon * cos(j*Angle);
XyzSommet[j].y=PtCentre->XyzSommet[0].y + rayon * sin(j*Angle);
XyzSommet[j].z=0;

//Mise a jour eventuelle des Points EXTREMES
PtMIN = Min( PtMIN, XyzSommet[j] );
PtMAX = Max( PtMAX, XyzSommet[j] );
}
XyzSommet[NbSommet-1].x=PtCentre->XyzSommet[0].x + rayon;
XyzSommet[NbSommet-1].y=PtCentre->XyzSommet[0].y;
XyzSommet[NbSommet-1].z=0;
cout << "Ligne CERCLE" << nom << " Nombre de Sommets=" << NbSommet <<endl;

// Numero initial et final des NbEF de la ligne CERCLE
NoStEF = new Z[NbEF*NbStEF]; // Tableau NoStEF[NbEF][NbStEF]
for (j=0; j<NbEF; j++)
{
m = NbStEF * j;
NoStEF[m] = j+1; // Attention sommet initial de no 1 et non 0
NoStEF[m+1] = j+2; // Sommet final de no Nbsommets=NbEF+1
}
cout << "Ligne CERCLE" << nom << " Nombre d'Aretes =" << NbEF <<endl;
return 0;
}
*/

void LigneCercle::AfficherDefinition()
{
cout << "Nom de la Ligne CERCLE= " << nom
<< " Nom du Point CENTRE= " << PtCentre->nom
<< " Rayon du CERCLE= " << rayon << endl;
}

void LigneCercle::VerifierMaillage(Points *LesPoints)
{
if( PtCentre->date > this->date ) Mailler(LesPoints);
}


//------------------------------------------------------------------------------

LigneBEZIER::LigneBEZIER(Points *LesPoints)
{ //saisie interactive des donnees de la courbe BEZIER
int i, nbc, ncvals;
Nom NomPt;
Point * PtAvant;
char texte[48];
char carlu;

mpxInvite.VuInvite( "Frapper le DEGRE de la courbe de BEZIER" );
do {
mpxInvite.lireZ( ncvals, degre );
if(ncvals==-1) {nbn=0; return;}
} while( degre<=0 );

nbn = degre;

PC = new Point *[1+nbn]; //la declaration du tableau des points de controle
strcpy( texte, "Cliquer le POINT de CONTROLE[" );
for (i=0; i<=nbn; i++)
{
itoa( i, nbc, (texte+29) ); //texte de l'invite
strcat( texte, "] ou frapper son NOM" );
mpxInvite.VuInvite( texte ); //trace de l'invite
PC[i] = LesPoints->Points::CliquerPoint();//en attente de clic d'un point
if( PC[i] == NULL ) { nbn=0; return; }
mpxInvite.VuEffacerMemoirePx();
}

U = new R[1+nbn+1+degre]; //la declaration du tableau des noeuds
// creation automatique des noeuds
for (i=0; i<=degre; i++ ) //noeud initial de multiplicite 1+degre
{ U[i] = 0; }

for (i=nbn+1; i<=nbn+1+degre; i++) //noeud final de multiplicite 1+degre
{ U[i] = 1; }

mpxInvite.VuInvite( "Frapper la valeur des Poids (o/N)" ); //Les Poids?
carlu = mpxInvite.lire1Caractere();
if( carlu == '@' || int(carlu)== 27 ) {nbn=0; return;} //ABANDON
if( carlu == 'o' || carlu == 'O' || carlu == '0' )
{
//saisie interactive des valeurs des Poids => courbe de BEZIER
Poids = new R[1+nbn]; //la declaration du tableau des Poids
strcpy( texte, "Frapper le Poids[" );
for (i=0; i<=nbn; i++)
{
itoa( i, nbc, (texte+17) ); //texte de l'invite
strcat( texte, "]" );
mpxInvite.VuInvite( texte );
mpxInvite.lireR( ncvals, Poids[i] );
if(ncvals==-1) {nbn=0; return;} //ABANDON demande
}
}
else
{ // pas de creation des Poids => courbe polynomiale
Poids = NULL;
}

mpxInvite.VuEffacerMemoirePx();
// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}


LigneBEZIER::LigneBEZIER(Points *LesPoints, int clavier)
{ //saisie par cin au clavier des donnees de la courbe BEZIER
int i;
Nom NomPt;
Point * PtAvant;

cout << "Mode entree Clavier=" << clavier << endl; //pour utiliser clavier

do { // La definition de la Ligne BEZIER
cout << "DEGRE des polynomes de la courbe de BEZIER=? ";
cin >> degre;
} while ( degre<=0 );

nbn = degre;
U = new R[1+nbn+1+degre]; //la declaration du tableau des noeuds
for (i=0; i<=nbn; i++)
U[i] = 0;
for (i=nbn+1; i<=nbn+1+degre; i++) //dernier noeud de multiplicite 1+degre
U[i] = 1;

PC = new Point *[1+nbn]; //la declaration du tableau des points de controle
for (i=0; i<=nbn; i++)
{
do {
cout << "Nom du Point[" << i << "]=? ";
cin >> NomPt;
PC[i] = LesPoints->Points::RetrouverPoint( NomPt, PtAvant );
} while ( PC[i] == NULL );
}

// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}


LigneBEZIER::LigneBEZIER(Points *LesPoints, Nom NomLg,
int degrepol, Nom P[], R poids[]) :Ligne( NomLg )
{
Z i;
Point *PtAvant;

degre = nbn = degrepol; //degre des polynomes = nombre de points total - 1

U = new R[1+nbn+1+degre]; //la declaration du tableau des noeuds
for ( i=0; i<=nbn; i++ )
U[i] = 0;
for (i=nbn+1; i<=nbn+1+degre; i++) //dernier noeud de multiplicite 1+degre
U[i] = 1;

PC = new Point *[1+nbn]; //la declaration du tableau des pointeurs
//sur les points de controle de la courbe BEZIER
for ( i=0; i<=nbn; i++ )
{PC[i] = LesPoints->Points::RetrouverPoint( P[i], PtAvant );}

Poids = new R[1+nbn]; //la declaration du tableau des Poids
for ( i=0; i<=nbn; i++ )
Poids[i] = poids[i];

if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; } //la generation du maillage
}


void LigneBEZIER::AfficherDefinition()
{
int i;

cout << "Nom de la Ligne de BEZIER= " << nom
<< " Degre des Polynomes= " << degre
<< " Nombre de Points= " << nbn+1 << endl;

for (i=0; i<=nbn; i++)
{
cout << "U[" << i << "]= " << U[i] << endl;
}

for (i=0; i<=nbn; i++)
{
cout << "Point de Controle[" << i << "]= " << *PC[i]->nom << " \0";
}
}

void LigneBEZIER::VerifierMaillage(Points *LesPoints)
{
int i;
for (i=0; i<=nbn; i++)
{
if( PC[i]->date > this->date )
{
Mailler(LesPoints);
return;
}
}
}

void LigneBEZIER::Elevation1Degre(Points *LesPoints)
{ //le degre des polynomes est augmente de 1 sans modifier la courbe
R a, a1;
int i;
Nom nomp;

R * UU = new R[2*(degre+2)]; //la declaration du tableau des nouveaux noeuds
for ( i=0; i<=1+degre; i++ )
UU[i] = 0;
for (i=degre+2; i<=degre+3+degre; i++) //dernier noeud de multiplicite 2+degre
UU[i] = 1;

Point ** QC = new Point *[degre+2]; //la declaration du tableau des pointeurs
//sur les nouveaux points de controle de la courbe BEZIER
R * PoidsQC=NULL;
if( Poids!=NULL ) PoidsQC = new R[degre+2];

for (i=1; i<=degre; i++)
{
NommerPoint( nomp ); //Nom du nouveau point QC de controle

a = R(i)/R(degre+1); //Les coefficients de passage des anciens aux nouveaux
a1 = 1-a;
if( Poids!=NULL ) //xyz => omega x, omega y, omega z, omega
{ a *= Poids[i-1]; a1 *= Poids[i]; }

QC[i] = new Pointxyz( nomp, //Declaration du nouveau point QC de controle
a1 * (PC[i]->XyzSommet[0].x) + a * (PC[i-1]->XyzSommet[0].x), //L'abscisse
a1 * (PC[i]->XyzSommet[0].y) + a * (PC[i-1]->XyzSommet[0].y), //L'ordonnee
a1 * (PC[i]->XyzSommet[0].z) + a * (PC[i-1]->XyzSommet[0].z)); //La cote
if( Poids!=NULL )
{
PoidsQC[i] = a1 + a;
QC[i]->XyzSommet[0] = QC[i]->XyzSommet[0] / PoidsQC[i]; // retour a x y z
}

LesPoints->Ajouter1Point( QC[i] ); // ajout du Point a l'ensemble des Points
}

QC[0] = PC[0]; //le nouveau premier est en fait l'ancien (pointeur=)
QC[degre+1] = PC[degre]; //le nouveau dernier est en fait l'ancien
if( Poids!=NULL )
{
PoidsQC[0] = Poids[0];
PoidsQC[degre+1] = Poids[degre];
}

//destruction des anciennes donnees de la courbe de Bezier
if( U != NULL ) delete [] U;
if( PC != NULL ) delete [] PC;
if( Poids!= NULL ) delete [] Poids;

//mise a jour des nouvelles donnees de la courbe de Bezier
degre++;
nbn++;
U = UU;
PC = QC;
Poids = PoidsQC;
}

//------------------------------------------------------------------------------

LigneNURBS::LigneNURBS(Points *LesPoints)
{ //saisie interactive des donnees de la courbe NURBS
int i, nbc, ncvals;
Nom NomPt;
Point * PtAvant;
char texte[48];
char carlu;

mpxInvite.VuInvite( "Frapper le DEGRE de la courbe NURBS" );
do {
mpxInvite.lireZ( ncvals, degre );
if(ncvals==-1) {nbn=0; return;}
} while( degre<=0 );

mpxInvite.VuInvite( "Frapper le NOMBRE de POINTS de la courbe NURBS" );
do {
mpxInvite.lireZ( ncvals, nbn );
if(ncvals==-1) {nbn=0; return;}
} while( nbn<=0 );
nbn--;

PC = new Point *[1+nbn]; //la declaration du tableau des points de controle
strcpy( texte, "Cliquer le POINT de CONTROLE[" );
for (i=0; i<=nbn; i++)
{
itoa( i, nbc, (texte+29) ); //texte de l'invite
strcat( texte, "] ou frapper son NOM" );
mpxInvite.VuInvite( texte ); //trace de l'invite
PC[i] = LesPoints->Points::CliquerPoint();//en attente de clic d'un point
if( PC[i] == NULL ) { nbn=0; return; }
mpxInvite.VuEffacerMemoirePx();
}

U = new R[1+nbn+1+degre]; //la declaration du tableau des noeuds
mpxInvite.VuInvite( "Frapper la valeur des NOEUDS (o/N)" );
carlu = mpxInvite.lire1Caractere();
mpxInvite.VuEffacerMemoirePx();
if( carlu == '@' || int(carlu)== 27 ) {nbn=0; return;} //ABANDON
if( carlu == 'o' || carlu == 'O' || carlu == '0' )
{ //saisie interactive des valeurs des noeuds
strcpy( texte, "Frapper la valeur du noeud U[" );
for (i=degre; i<=nbn+1; i++)
{
itoa( i, nbc, (texte+29) ); //texte de l'invite
strcat( texte, "]" );
mpxInvite.VuInvite( texte ); //trace de l'invite
do {
mpxInvite.lireR( ncvals, U[i] );
if(ncvals==-1) {nbn=0; return;} //ABANDON demande
if(i==0) break;
} while (U[i]<U[i-1]);
mpxInvite.VuEffacerMemoirePx();
}
}
else
{ // creation automatique des noeuds simples en fonction
// des distances entre les points de controle
U[degre] = 0;
for (i=degre+1; i<=nbn+1; i++)
{ U[i] = U[i-1] + Norme2( PC[i-degre ]->XyzSommet[0]
- PC[i-degre-1]->XyzSommet[0] ); }
}

for (i=0; i<=degre; i++ ) //noeud initial de multiplicite 1+degre
{ U[i] = U[degre]; }

for (i=nbn+2; i<=nbn+1+degre; i++) //noeud final de multiplicite 1+degre
{ U[i]=U[nbn+1]; }

mpxInvite.VuInvite( "Frapper la valeur des Poids (o/N)" ); //Les Poids?
carlu = mpxInvite.lire1Caractere();
if( carlu == '@' || int(carlu)== 27 ) {nbn=0; return;} //ABANDON
if( carlu == 'o' || carlu == 'O' || carlu == '0' )
{
//saisie interactive des valeurs des Poids => courbe NURBS
Poids = new R[1+nbn]; //la declaration du tableau des Poids
strcpy( texte, "Frapper le Poids[" );
for (i=0; i<=nbn; i++)
{
itoa( i, nbc, (texte+17) ); //texte de l'invite
strcat( texte, "]" );
mpxInvite.VuInvite( texte );
mpxInvite.lireR( ncvals, Poids[i] );
if(ncvals==-1) {nbn=0; return;} //ABANDON demande
}
}
else
{ // pas de creation des Poids => courbe polynomiale
Poids = NULL;
}

mpxInvite.VuEffacerMemoirePx();
// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}


LigneNURBS::LigneNURBS(Points *LesPoints, int clavier)
{ //saisie par cin au clavier des donnees de la courbe NURBS
int i;
Nom NomPt;
Point * PtAvant;

cout << "Mode entree Clavier=" << clavier << endl; //pour utiliser clavier

do { // La definition de la Ligne NURBS
cout << "DEGRE des polynomes de la courbe NURBS=? ";
cin >> degre;
} while ( degre<=0 );

do {
cout << "Nombre de NOEUDS=? ";
cin >> nbn;
} while ( nbn<0 );

U = new R[1+nbn+1+degre]; //la declaration du tableau des noeuds
for (i=0; i<=nbn+1; i++)
{
do {
cout << "Valeur du noeud U[" << i << "]=? ";
cin >> U[i];
if(i==0) break;
} while (U[i]<U[i-1]);
}
for (i=nbn+2; i<=nbn+1+degre; i++) //dernier noeud de multiplicite 1+degre
U[i]=U[nbn+1];

PC = new Point *[1+nbn]; //la declaration du tableau des points de controle
for (i=0; i<=nbn; i++)
{
do {
cout << "Nom du Point[" << i << "]=? ";
cin >> NomPt;
PC[i] = LesPoints->Points::RetrouverPoint( NomPt, PtAvant );
} while ( PC[i] == NULL );
}

// Le maillage de la Ligne: Coordonnees des Sommets et No des Sommets des Aretes
if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; }
}


LigneNURBS::LigneNURBS(Points *LesPoints, Nom NomLg,
int degrepol, int nbtpoints,
R u[], Nom P[], R poids[]) :Ligne( NomLg )
{
Z i;
Point *PtAvant;

degre = degrepol; //le degre des polynome
nbn = nbtpoints-1; //le nombre de points total - 1

U = new R[1+nbn+1+degre]; //la declaration du tableau des noeuds
for ( i=0; i<=nbn+1; i++ )
U[i] = u[i];
for (i=nbn+2; i<=nbn+1+degre; i++) //dernier noeud de multiplicite 1+degre
U[i]=U[nbn+1];

PC = new Point *[1+nbn]; //la declaration du tableau des pointeurs
//sur les points de controle de la courbe NURBS
for ( i=0; i<=nbn; i++ )
{PC[i] = LesPoints->Points::RetrouverPoint( P[i], PtAvant );}

Poids = new R[1+nbn]; //la declaration du tableau des Poids
for ( i=0; i<=nbn; i++ )
{Poids[i] = poids[i];}

if( Mailler(LesPoints) != 0 ) { NbSommet=0; NoLigne--; return; } //la generation du maillage
}

 

void LigneNURBS::AfficherDefinition()
{
int i;

cout << "Nom de la Ligne NURBS= " << nom
<< " Degre des Polynomes= " << degre
<< " Nombre de Points= " << nbn+1 << endl;

for (i=0; i<=nbn; i++)
{
cout << "U[" << i << "]= " << U[i] << endl;
}

for (i=0; i<=nbn; i++)
{
cout << "Point de Controle[" << i << "]= " << *PC[i]->nom << " \0";
}
}

void LigneNURBS::VerifierMaillage(Points *LesPoints)
{
for (Z i=0; i<=nbn; i++)
{
if( PC[i]->date > this->date )
{
Mailler(LesPoints);
return;
}
}
}

//------------------------------------------------------------------------------

//Fin de la classe Ligne

//==============================================================================


Lignes::Lignes()
{
P1Ligne=NULL;
}

Lignes::~Lignes()
{
#ifdef VERBOSE
cout << "Entrée dans ~Lignes()" << endl;
#endif
if ( Lignes::P1Ligne != NULL )
delete P1Ligne;
#ifdef VERBOSE
cout << "Sortie de ~Lignes" << endl;
#endif
}

Ligne * Lignes::RetrouverLigne( Nom NomLg, Ligne * & LgAvant ) // retourne NULL si pas retrouve
{
Ligne * LgCourant;

LgAvant=NULL;
LgCourant = P1Ligne;
while ( LgCourant != NULL )
{
if ( strcmp( LgCourant->nom, NomLg )==0 )
{
return LgCourant;
}
else
{
LgAvant=LgCourant;
LgCourant=LgCourant->PSuivant;
}
}
return NULL;
}

Ligne * Lignes::CliquerLigne( void )
// retourne le pointeur sur la ligne la plus proche du clic-souris
// NULL si la ligne n'est pas retrouvee ou abandon demande
{
int notyev, nbc;
XPoint pxy, pxymin0={-1,-1}, pxymin;
Ligne *LgCourant, *LgMin;
R3 xyz, xyzm, axyz;
R d, dmin;
Nom nomLigne;

//saisie a la souris de la poignee de la Ligne
SaisieT:
mpxInvite.VuSourisTexte( notyev, nbc, pxy, nomLigne );
if( notyev == 0 ) { return NULL; } //Abandon demande

if( notyev < 0 ) //souris deplacee ou bouton enfonce non relache
{
xyz.x = mpxPLSV.Vuxob2px( pxy.x ); //construction du point de R2 correspondant
xyz.y = mpxPLSV.Vuyob2px( pxy.y );
xyz.z = 0;

//recherche de la Ligne actuelle la plus proche du clic souris
//==============================================================================
dmin = 1e100;
LgMin = NULL;
LgCourant = P1Ligne;
while ( LgCourant != NULL )
{
xyzm = LgCourant->PointMilieuLigne(); //la poignee de la ligne
if( mpxPLSV.visee == 2 ) //Visee 2d
{
d = Norme2_2( xyz - LgCourant->PointMilieuLigne() );
}
else
{ //Visee 3d Un point pxy clique est une droite dans R3
//recherche du point le plus proche de cette droite
// Passage en coordonnees axonometriques du point
mpxPLSV.Vuxyzaxo( xyzm, axyz );
//distance en XY axonometriques seulement
d = sqrt( pow( xyz.x-axyz.x, 2 )
+ pow( xyz.y-axyz.y, 2 ) );
}
if ( d < dmin ) { dmin = d; LgMin = LgCourant; }
LgCourant = LgCourant->PSuivant;
}

//Verification que LgMin n'est pas trop loin du point clique
if( LgMin != NULL )
{
xyzm = LgMin->PointMilieuLigne(); //la poignee de la ligne
if( mpxPLSV.visee == 2 ) //Visee 2d
{
pxymin.x = mpxPLSV.Vunupxex( xyzm.x );
pxymin.y = mpxPLSV.Vunupxey( xyzm.y );
if( abs( pxymin.x - pxy.x ) > 123
|| abs( pxymin.y - pxy.y ) > 123 ) {LgMin = NULL;}
}
else
{ //Visee 3d
mpxPLSV.Vuxyzaxo( xyzm, axyz );
pxymin.x = mpxPLSV.Vunupxex( axyz.x );
pxymin.y = mpxPLSV.Vunupxey( axyz.y );
if( abs( pxymin.x - pxy.x ) > 123
|| abs( pxymin.y - pxy.y ) > 123 )
{LgMin = NULL;}
}
if( LgMin == NULL ) //Ligne min trop loin => Accrochage a effacer
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
pxymin0.x = -1;
pxymin0.y = -1; //reinitialisation a vide
}
}
}
if( LgMin == NULL ) { goto SaisieT; }

//Une Ligne est suffisamment proche => son accrochage est materialise
//si ce n'est deja fait
pxymin.x -= (int) mpxAccroche.largeurpx/2;
pxymin.y -= (int) mpxAccroche.hauteurpx/2;
if( (pxymin.x!=pxymin0.x) || (pxymin.y!=pxymin0.y) )
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
//ajout du mpxAccroche a fenetre_vu
pxymin0 = pxymin;
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
goto SaisieT;
}
else if( notyev == 1 ) //clic enfonce et relache d'un bouton de la souris
{
if( (pxymin0.x!=-1) && (pxymin0.y!=-1) )
{
//suppression du mpxAccroche de fenetre_vu
//GXxor 2 fois de suite redonne la fenetre_vu initiale
mpxAccroche.VuCombinerMemoirePxDansFenetre( GXxor,
pxy0, mpxAccroche.largeurpx, mpxAccroche.hauteurpx,
pxymin0 );
}
xyz.x = mpxPLSV.Vuxob2px( pxy.x ); //Construction du point de R2 correspondant
xyz.y = mpxPLSV.Vuyob2px( pxy.y );
xyz.z = 0;

//recherche de la Ligne actuelle la plus proche du clic souris
dmin = 1e100;
LgMin = NULL;
LgCourant = P1Ligne;
while ( LgCourant != NULL )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
d = Norme2_2( xyz - LgCourant->PointMilieuLigne() );
}
else
{ //Visee 3d Un point pxy clique est une droite dans R3
//recherche du point le plus proche de cette droite
// Passage en coordonnees axonometriques du point
mpxPLSV.Vuxyzaxo( LgCourant->PointMilieuLigne(), axyz );
//distance en XY axonometriques seulement
d = sqrt( pow( xyz.x-axyz.x , 2 )
+ pow( xyz.y-axyz.y , 2 ) );
}
if ( d < dmin ) { dmin = d; LgMin = LgCourant; }
LgCourant = LgCourant->PSuivant;
}

//verification que LgMin n'est pas trop loin du point clique
if( LgMin != NULL )
{
if( mpxPLSV.visee == 2 ) //Visee 2d
{
if( abs( mpxPLSV.Vunupxex( LgMin->PointMilieuLigne().x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( LgMin->PointMilieuLigne().y ) - pxy.y ) > 123 )
{LgMin = NULL;}
}
else
{ //Visee 3d
mpxPLSV.Vuxyzaxo( LgMin->PointMilieuLigne(), axyz );
if( abs( mpxPLSV.Vunupxex( axyz.x ) - pxy.x ) > 123
|| abs( mpxPLSV.Vunupxey( axyz.y ) - pxy.y ) > 123 )
{LgMin = NULL;}
}
}
}
else if ( notyev == 2 )
{
Ligne *LgAvant;
LgMin = RetrouverLigne( nomLigne, LgAvant ); //par son nom
}

return LgMin;
}


void Lignes::Ajouter1Ligne( Ligne *PLigne )
{
Ligne * LgAvant;
Ligne * LgNom;

LgNom=RetrouverLigne( PLigne->nom, LgAvant );
if( LgNom != NULL )
{ // La ligne etait deja dans la liste => Destruction
if (LgAvant==NULL) // Pas de ligne avant
P1Ligne=LgNom->PSuivant; // La suivante de LgNom devient la premiere
else
LgAvant->PSuivant=LgNom->PSuivant;// Le suivant d'avant est le suivant de LgNom

LgNom->PSuivant=NULL;
delete [] LgNom->NoStEF; // La ligne LgNom est detruite
delete [] LgNom->XyzSommet;
}
// La ligne n'est pas dans la liste
PLigne->PSuivant = P1Ligne; // La ligne devient la premiere
P1Ligne=PLigne; // ligne de la liste
}

int Lignes::EntrerLignes( Points *LesPoints ) // Entrer des Lignes avec les donnees utilisateur
{
int type;
Ligne *PLigne; // Construction d'une ligne avec demande du Nom

while(1)
{
cout << endl;
cout << "Type de la LIGNE: 0:Quitter 1:Droite 2:Cercle =>? ";
cin >> type;

switch( type )
{
case 0:
return 0;

case 1:
PLigne = new LigneDroite( LesPoints );
Lignes::Ajouter1Ligne( PLigne );
break;

case 2:
PLigne = new LigneCercle( LesPoints );
Lignes::Ajouter1Ligne( PLigne );
break;

default:
cout << "Type INCONNU de LIGNE\n";
break;
}
}
}

void Lignes::AfficherLignes()
{
Ligne *PCourant;

cout << endl;
cout << "Affichage des LIGNES:" << endl;
PCourant = P1Ligne;
while( PCourant != NULL )
{
PCourant->AfficherDefinition();
PCourant->AfficherMaillage();
PCourant = PCourant->PSuivant;
}
}

void Lignes::TracerLignes( MemoirePx3d & mpx, Points *LesPoints )
{
Ligne *PCourant;

PCourant = P1Ligne;
while( PCourant != NULL )
{
PCourant->VerifierMaillage( LesPoints );
PCourant->TracerMaillage(mpx);
PCourant = PCourant->PSuivant;
}
}

//==============================================================================
//Fonstions utilitaires
//==============================================================================
int ProjectionDansXYSCU( MemoirePx3d & mpx, R3 SCU[], R3 P, R3 & Pscu )
//Projection du point P (dans SCG) selon la direction PtVu->OEIL sur le plan XY du SCU
//Pscu le point (dans SCG) projete de P dans le plan XY du SCU
//retourne 1 si Point projete existe et 0 sinon
{
R3 Pn;
R z1, z2;

ScgScu( SCU, P, Pscu ); //XYZ SCU de P

//Verification que Pscu->Oeil-PtVu intersecte le plan XY du SCU
Pn = P + (mpx.axoeil - mpx.axoptv);
ScgScu( SCU, Pn, Pn ); //XYZ SCU de P + OEIL-PtVu
//S'il n'y a pas d'intersection alors les cotes Z de Pscu et Pn sont identiques

z1 = Abs( Pscu.z ); //La cote Z des 2 points est elle identique?
z2 = Abs( Pn.z );
if ( z1 <= epzero )
{
if ( z2 <= epzero ) return 0; //Z identiques
}
else
{
if( z2 > epzero )
if( Abs(Pscu.z - Pn.z) <= z1*epsxyz ) return 0; //Z identiques
}
//Ici z1 z2 sont juges differents
//Intersection de la droite PscuPn avec XY du SCU
z1 = Pscu.z / ( Pscu.z - Pn.z ); //coefficient de la droite pour Z=0
Pn = Pn - Pscu; //dans le repere du SCU
Pscu = Pscu + z1 * Pn;

//retour dans le repere SCG
ScuScg( SCU, Pscu, Pscu ); //XYZ SCU de P

return 1; //Point d'intersection calcule
}


void PlusProcheXYSCU( MemoirePx3d & mpx, R3 SCU[], R3 Pt, R3 & PtCoin )
{ //retourne pour le point Pt appartenant au plan XY du SCU
//le point PtCoin du coin le plus proche du plan XY du SCU
//Pt de coordonnees SCG
//PtCoin de coordonnees SCG

R3 P;

if( mpx.visee==3 ) //Visee en 3d
{ //Passage de Pt dans le repere du SCU
ScgScu( SCU, Pt, P);

//Le point P est projete au plus proche coin de la grille du plan XY du SCU
PtCoin.x = int( P.x / PasGrilleSCU.x + 0.5 ) * PasGrilleSCU.x;
PtCoin.y = int( P.y / PasGrilleSCU.y + 0.5 ) * PasGrilleSCU.y;
PtCoin.z = 0;

//Passage de PtCoin dans le repere SCG
ScuScg( SCU, PtCoin, PtCoin );
}
else //Visee en 2d
{
//Le point P est projete au plus proche coin de la grille du plan XY du SCU
PtCoin.x = int( (Pt.x - SCU[0].x) / PasGrilleSCU.x + 0.5 ) * PasGrilleSCU.x;
PtCoin.y = int( (Pt.y - SCU[0].y) / PasGrilleSCU.y + 0.5 ) * PasGrilleSCU.y;
PtCoin.z = 0;
}
}


int ProjectionClicSourisSCU( MemoirePx3d & mpx, R3 SCU[], XPoint pxy, R3 & PgSCU )
{ //retourne si 1 si PgSCU est le point projete PgSCU dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible
R3 P;
int i;

//transformation des coordonnees pixels en coordonnees 2d
//en 2d du plan XY et en 3d du plan XY d'axonometrie
P.x = mpx.Vuxob2px( pxy.x );
P.y = mpx.Vuyob2px( pxy.y );
P.z = 0;

//si 3d Pt est en coordonnees axonometriques et il retourne dans le repere absolu
if( mpx.visee==3 ) //visee 3d
{
mpx.Vuaxoxyz( P, P ); //P passe de l'axonometrie au SCG
//Projection du point P (dans SCG) selon la direction PtVu->OEIL sur le plan XY du SCU
i = ProjectionDansXYSCU( mpx, SCU, P, P );
if( i==0 ) {P=R3(0,0,0); return 0;}
}

//si accrochage au SCU demande alors calcul du point du plan XY du SCU le plus proche
if( AccrocherGrilleSCU != 0 ) PlusProcheXYSCU( mpx, SCU, P, P );

PgSCU = P; return 1;
}


//==============================================================================

U
Pscu = Pscu + z1 * Pn;

 

//retour dans le repere SCG
ScuScg( SCU, Pscu, Pscu ); //XYZ SCU de P

return 1; //Point d'intersection calcule
}


void PlusProcheXYSCU( MemoirePx3d & mpx, R3 SCU[], R3 Pt, R3 & PtCoin )
{ //retourne pour le point Pt appartenant au plan XY du SCU
//le point PtCoin du coin le plus proche du plan XY du SCU
//Pt de coordonnees SCG
//PtCoin de coordonnees SCG

R3 P;

if( mpx.visee==3 ) //Visee en 3d
{ //Passage de Pt dans le repere du SCU
ScgScu( SCU, Pt, P);

//Le point P est projete au plus proche coin de la grille du plan XY du SCU
PtCoin.x = int( P.x / PasGrilleSCU.x + 0.5 ) * PasGrilleSCU.x;
PtCoin.y = int( P.y / PasGrilleSCU.y + 0.5 ) * PasGrilleSCU.y;
PtCoin.z = 0;

//Passage de PtCoin dans le repere SCG
ScuScg( SCU, PtCoin, PtCoin );
}
else //Visee en 2d
{
//Le point P est projete au plus proche coin de la grille du plan XY du SCU
PtCoin.x = int( (Pt.x - SCU[0].x) / PasGrilleSCU.x + 0.5 ) * PasGrilleSCU.x;
PtCoin.y = int( (Pt.y - SCU[0].y) / PasGrilleSCU.y + 0.5 ) * PasGrilleSCU.y;
PtCoin.z = 0;
}
}


int ProjectionClicSourisSCU( MemoirePx3d & mpx, R3 SCU[], XPoint pxy, R3 & PgSCU )
{ //retourne si 1 si PgSCU est le point projete PgSCU dans le plan XY du SCU du pt pxy
// 0 si pas de projection possible
R3 P;
int i;

//transformation des coordonnees pixels en coordonnees 2d
//en 2d du plan XY et en 3d du plan XY d'axonometrie
P.x = mpx.Vuxob2px( pxy.x );
P.y = mpx.Vuyob2px( pxy.y );
P.z = 0;

//si 3d Pt est en coordonnees axonometriques et il retourne dans le repere absolu
if( mpx.visee==3 ) //visee 3d
{
mpx.Vuaxoxyz( P, P ); //P passe de l'axonometrie au SCG
//Projection du point P (dans SCG) selon la direction PtVu->OEIL sur le plan XY du SCU
i = ProjectionDansXYSCU( mpx, SCU, P, P );
if( i==0 ) {P=R3(0,0,0); return 0;}
}

//si accrochage au SCU demande alors calcul du point du plan XY du SCU le plus proche
if( AccrocherGrilleSCU != 0 ) PlusProcheXYSCU( mpx, SCU, P, P );

PgSCU = P; return 1;
}


//==============================================================================