EIMBase.cpp 80 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610
  1. /*******************************************************************\
  2. Fichier : EIMBase.cpp
  3. Date : 29/04/98
  4. Version : 1.024
  5. Auteur : P-J Touboul
  6. Description : Fonctions de d�tection et mesures de parois
  7. |*******************************************************************|
  8. Bugs:
  9. Il serait plus propre dans la fonction EIM, d'appliquer le masque
  10. sur le vecteur (proc�dure Mask mise en commentaire).
  11. Notes:
  12. |*******************************************************************|
  13. Historique :
  14. 29/04/98 1.024 : Modification du sens de la mesure en fonction de la position relative
  15. des points du segment utilisateur
  16. M�morisation de la distance de la mesure
  17. 02/04/98 1.022 : Utilisation d'une valeur minimale permettant de consid�rer qu'il
  18. y a une variation de densit� (STEP)
  19. Bug quand il y a avait UN SEUL lissage effectu�
  20. 11/03/98 1.020 : Nouvel algorithme possible pour la mesure de diam�tre (sym�trie)
  21. 31/01/98 1.010 : Mesures 'sub-pixels' permettant de gagner jusqu'� un pixel
  22. en pr�cision (1/2 pixel avant + 1/2 pixel apr�s). Les points
  23. au milieu des pentes ont donc defs coordonn�es d�cimales
  24. Correction d'un probl�me sur la d�tection de plateaux
  25. 22/01/98 1.001 : Correction sur le calcul des points m�dians
  26. Ajout de la position des points m�dians
  27. 17/03/97 1.000 : Premi�re version
  28. \*******************************************************************/
  29. /*----------------------------------------------------------\
  30. Includes
  31. \----------------------------------------------------------*/
  32. #include "EIMBase.h"
  33. #include "MeanEstimate.h"
  34. #include "CEIMResult.h"
  35. #include "EIMResult.h"
  36. #include "Ressource.h"
  37. #include "point.h"
  38. #include "ToolsMath.h"
  39. #include <limits>
  40. #include <string.h>
  41. #include <QImage>
  42. //#define TEST_FOR_FANTOME
  43. /*----------------------------------------------------------\
  44. Defines
  45. \----------------------------------------------------------*/
  46. #define STEP 0
  47. /*----------------------------------------------------------\
  48. Variables locales
  49. \----------------------------------------------------------*/
  50. //static char Version[] = "$VER: " __FILE__ " 1.024 (" __DATE__ ")";
  51. /*----------------------------------------------------------\
  52. | Delta |
  53. \----------------------------------------------------------*/
  54. char CEIMBase::Delta (unsigned char b1, unsigned char b2)
  55. {
  56. int i;
  57. // En utilisant STEP, on consid�re par exemple que 15/16/17 repr�sentent
  58. // la m�me valeur et que ce n'est donc pas une croissance
  59. i = b1 - b2;
  60. if (i > STEP) return ( 1);
  61. else if (i < -STEP) return (-1);
  62. else return ( 0);
  63. } // end of Delta
  64. /*----------------------------------------------------------\
  65. | CEIM::CEIM |
  66. |-----------------------------------------------------------|
  67. | DESCRIPTION : |
  68. | Constructeur de la classe |
  69. |-----------------------------------------------------------|
  70. | PARAMETRES : |
  71. | scale : �chelle � utiliser pour les mesures |
  72. \----------------------------------------------------------*/
  73. CEIMBase::CEIMBase (void)
  74. {
  75. //debugOutput = NULL;
  76. m_pMeasures = NULL;
  77. m_bDelta1 = 30; // variation minimale pour la premi�re pente
  78. m_bDelta2 = 10; // variation minimale entre le sommet des deux pentes // A voir Release
  79. m_bSeuil1 = 140;
  80. m_algoDiameter = algoProfile; // algorithme par d�faut
  81. m_arVariance.clear();
  82. m_arVarianceAA.clear();
  83. m_arVarianceII.clear();
  84. m_arVarianceINT.clear();
  85. Release(); // apr�s m_pMeasures = NULL;
  86. m_coeff_a = -1.0;
  87. m_coeff_b = -1.0;
  88. m_coeff_c = -1.0;
  89. m_bDisplay = false;
  90. m_parallelismeDiametre = false; // Exp�rimental
  91. m_image = NULL;
  92. m_versionTomtecAout08 = true;
  93. } // fin de CEIM
  94. CEIMBase::~CEIMBase(void)
  95. {
  96. Release();
  97. } // fin de ~CEIM
  98. void CEIMBase::SetEimAssisted(bool valide)
  99. {
  100. m_Assist = valide;
  101. }
  102. bool CEIMBase::GetEimAssisted()
  103. {
  104. return m_Assist;
  105. }
  106. // Calcul automatique de l'EIM
  107. // Ancienne version : n'est plus utilis�e
  108. int CEIMBase::CalculEimAutomatique(int mode, bool bActionDiametre, Point *ptClick0, Point *ptClick1, Point *ptLastClick, unsigned char *bClicks, QImage *img,bool *fBackToNone)
  109. {
  110. m_image = img;
  111. return CalculEimAutomatique( mode, bActionDiametre, ptClick0, ptClick1, ptLastClick, bClicks, fBackToNone );
  112. }
  113. int CEIMBase::CalculEimAutomatique(int mode, bool bActionDiametre, Point *ptClick0, Point *ptClick1, Point *ptLastClick, unsigned char *bClicks, bool *fBackToNone)
  114. {
  115. int retour = 0;
  116. if (m_Assist)
  117. {
  118. if (mode == 0)
  119. {
  120. Measure(*ptClick0, *ptLastClick, bActionDiametre);
  121. }
  122. double dDirection = Direction();
  123. if (dDirection == 0)
  124. {
  125. //CMessage::Warn(MyLoadString(IDS_EIM_FAILED));
  126. *fBackToNone = false;
  127. return 0;
  128. }
  129. else
  130. {
  131. Point CorrectPoint = *ptLastClick;
  132. CorrectPoint.y = ptClick0->y + ((long) (dDirection*(CorrectPoint.x - ptClick0->x)));
  133. *ptClick1 = CorrectPoint;
  134. *bClicks = 1;
  135. retour = 1; // Pour lancer un Invalidate
  136. if (mode == 1)
  137. {
  138. Measure(*ptClick0, CorrectPoint, bActionDiametre);
  139. }
  140. *ptLastClick = CorrectPoint;
  141. }
  142. }
  143. return retour;
  144. }
  145. bool CEIMBase::PointInBuffer(const Point& pt)
  146. {
  147. assert( m_image );
  148. int dx = m_image->width();
  149. int dy = m_image->height();
  150. return ( pt.x >= 0 && pt.y >= 0 && pt.x < dx && pt.y < dy );
  151. }
  152. unsigned char CEIMBase::GetIntensity(const Point& pt)
  153. {
  154. assert( m_image );
  155. return qGray(m_image->pixel( pt.x, pt.y ));
  156. }
  157. /*----------------------------------------------------------\
  158. | Release |
  159. |-----------------------------------------------------------|
  160. | DESCRIPTION : |
  161. | Lib�re les ressources allou�es pour une mesure |
  162. \----------------------------------------------------------*/
  163. void CEIMBase::Release (void)
  164. {
  165. m_dblEIMMin =
  166. m_dblEIMMean =
  167. m_dblEIMMax =
  168. m_dblINTMin =
  169. m_dblINTMean =
  170. m_dblINTMax =
  171. m_dblDiaAAMin =
  172. m_dblDiaAAMean =
  173. m_dblDiaAAMax =
  174. m_dblDiaIIMin =
  175. m_dblDiaIIMean =
  176. m_dblDiaIIMax =
  177. m_dblQI =
  178. m_dblQIMean =
  179. m_dblIA =
  180. m_dblEIMdMean =
  181. m_dblINTdMean =
  182. m_dblMEDdMean =
  183. m_dblIAd =
  184. m_dblVariance =
  185. m_dblDistance = 0.0;
  186. m_dwPoints = // nombre de points sur lesquels une mesure a �t� effectu�e
  187. m_dwValidPoints = // nombre de points sur lesquels le profil a �t� reconnu
  188. m_uErrorID = 0; // ID de la cha�ne d�crivant l'erreur
  189. if (m_pMeasures)
  190. {
  191. delete [] m_pMeasures;
  192. m_pMeasures = NULL;
  193. }
  194. m_StartPoint.x = -1;
  195. m_StartPoint.y = -1;
  196. m_EndPoint.x = -1;
  197. m_EndPoint.x = -1;
  198. memset( m_bBuffer, 0, THICKNESS );
  199. memset( m_cOffsets, 0, THICKNESS );
  200. } // fin de Release
  201. /*----------------------------------------------------------\
  202. | Measure |
  203. |-----------------------------------------------------------|
  204. | DESCRIPTION : |
  205. | Mesure d'une �paisseur de paroi ou d'un diam�tre |
  206. |-----------------------------------------------------------|
  207. | PARAMETRES : |
  208. | gfx : image en niveau de gris d'o� lire les |
  209. | donn�es |
  210. | pGraphMean : graphe dans lequel ajout� les mesures si |
  211. | non nul |
  212. | pt1 : premier point du segment d�terminant la |
  213. | ligne de la paroi |
  214. | pt2 : deuxi�me point du segment |
  215. | fDiameter : mesure d'un diam�re ou d'une paroi |
  216. |-----------------------------------------------------------|
  217. | RETOURNE : |
  218. | VRAI si au moins une mesure a �t� effectu�e |
  219. \----------------------------------------------------------*/
  220. bool CEIMBase::Measure(
  221. QImage *h_image,
  222. const Point &point1,
  223. const Point &point2,
  224. bool fDiameter,
  225. CEIMResult *m_res)
  226. {
  227. m_image = h_image;
  228. return Measure( point1, point2, fDiameter, m_res );
  229. }
  230. bool CEIMBase::Measure (
  231. const Point &point1,
  232. const Point &point2,
  233. bool fDiameter,
  234. CEIMResult *m_res
  235. )
  236. {
  237. Point point3, point4;
  238. // En fonction de la position du premier point, on d�termine le c�t� d'analyse
  239. m_fDiameter = fDiameter;
  240. Release ();
  241. if (point1.x > point2.x)
  242. {
  243. m_bNearWall = true;
  244. m_vUser = CVector(point2, point1);
  245. if (!fDiameter)
  246. {
  247. m_StartPoint = point2;
  248. m_EndPoint = point1;
  249. }
  250. }
  251. else
  252. {
  253. m_bNearWall = false;
  254. m_vUser = CVector(point1, point2); // pour imposer le calcul de gauche � droite pour
  255. // le diam�tre et la distensibilit� m�me si le trac�
  256. // se fait de droite � gauche.
  257. if (!fDiameter)
  258. {
  259. m_StartPoint = point1;
  260. m_EndPoint = point2;
  261. }
  262. }
  263. m_minx_curve = std::numeric_limits< int >::max();
  264. m_max_curve = 0;
  265. /*
  266. if ((m_Assist) && (!fDiameter))
  267. {
  268. // CJ 2007 : Allongement auto de la distance � 10 mm
  269. dpoint pta, ptb, s1, s2, ptc;
  270. const long x1 = 0;
  271. pta.x = point1.x;
  272. pta.y = point1.y;
  273. ptb.x = point2.x;
  274. ptb.y = point2.y;
  275. if (point1.x < point2.x)
  276. {
  277. if (InterCercleDroite(pta, 10.0 / g_pCurrentScale->DistanceX(1L), pta, ptb, &s1, &s2))
  278. {
  279. ptc = leplusproche(ptb, s1, s2);
  280. point3.x = (int) pta.x;
  281. point3.y = (int) pta.y;
  282. point4.x = (int) ptc.x;
  283. point4.y = (int) ptc.y;
  284. }
  285. #ifndef NEW_EIM
  286. m_vUser = CVector (point3, point4);
  287. #else
  288. if (point3.x <= point4.x)
  289. {
  290. m_vUser = CVector (point3, point4);
  291. m_StartPoint = point3;
  292. m_EndPoint = point4;
  293. }
  294. else
  295. {
  296. m_vUser = CVector (point4, point3);
  297. m_StartPoint = point4;
  298. m_EndPoint = point3;
  299. }
  300. if (point4.x > point3.x)
  301. {
  302. m_max_curve = point4.x;
  303. }
  304. else
  305. {
  306. m_max_curve = point3.x;
  307. }
  308. if (point3.x < point4.x)
  309. {
  310. m_minx_curve = point3.x;
  311. }
  312. else
  313. {
  314. m_minx_curve = point4.x;
  315. }
  316. #endif
  317. }
  318. }
  319. */
  320. if (m_vUser.Nul ())
  321. {
  322. m_uErrorID = IDS_EIM_INVALID;
  323. return (false);
  324. }
  325. else
  326. {
  327. // CWaitCursor wait;
  328. m_dwPoints = m_vUser.Length () + 1;
  329. m_pMeasures = new CEIMInfo [m_dwPoints];
  330. memset (m_pMeasures, 0, sizeof (CEIMInfo) * m_dwPoints);
  331. // pour un algo plut�t bas� sur la proximit� de la droite par
  332. // rapport � la paroi potentielle la plus proche voir fichier EIM/AvecSeuil.cpp
  333. // comme le point de d�part de vecteur � toujours une abscisse inf�rieure au point d'arriv�e
  334. // la direction � donner � Orthogonal est 0. Voir algo de Orthogonal pour comprendre
  335. if (!m_bNearWall)
  336. {
  337. m_indexParoi = 0;
  338. m_Max_Alignement = 8;
  339. }
  340. else
  341. {
  342. m_indexParoi = 1;
  343. m_Max_Alignement = 20;
  344. }
  345. if (fDiameter)
  346. {
  347. Diameter();
  348. }
  349. else
  350. {
  351. #ifdef NEW_EIM
  352. if (!m_Assist)
  353. #else
  354. // if ((m_Assist) && (!fDiameter))
  355. {
  356. }
  357. // else
  358. #endif
  359. {
  360. m_vUser = CVector (point1, point2);
  361. }
  362. Paroi();
  363. }
  364. }
  365. Update (m_res);
  366. return (Valid ());
  367. } // fin de Measure
  368. /*----------------------------------------------------------\
  369. | ParallelismeEIM |
  370. |-----------------------------------------------------------|
  371. | DESCRIPTION : |
  372. | Fonction de calcul du parall�lisme du trait utilisateur |
  373. | Par rapport � la paroi
  374. | Pour le calcul de l'EIM |
  375. \----------------------------------------------------------*/
  376. void CEIMBase::ParallelismeEIM()
  377. {
  378. long dwPos, dwMin;
  379. long dwPos2;
  380. CEIMInfo *pInfo = &m_pMeasures[0];
  381. dpoint tpoints[MAX_POINTS_EIM_AUTO];
  382. int tContinueGauche[MAX_POINTS_EIM_AUTO];
  383. int tContinueDroite[MAX_POINTS_EIM_AUTO];
  384. int tContinue[MAX_POINTS_EIM_AUTO];
  385. int tContinue2[MAX_POINTS_EIM_AUTO];
  386. dpoint pta, ptb, ptc, ptd, pte, ptf, s1, s2;
  387. double dist_etalon, dist_etalon2, dist;
  388. int cptValid, cptNonValid;
  389. dpoint tabPointsValides[128];
  390. dpoint pts;
  391. bool bDebut = false;
  392. for (int i = 0; i < MAX_POINTS_EIM_AUTO; i++)
  393. {
  394. tContinueGauche[i] = 0;
  395. tContinueDroite[i] = 0;
  396. tContinue[i] = 0;
  397. tContinue2[i] = 0;
  398. }
  399. // 2�me passe : On enl�ve les outliers : En allant de gauche � droite
  400. dwMin = long (-1);
  401. pInfo = &m_pMeasures[0];
  402. cptValid = 0;
  403. cptNonValid = 0;
  404. // double dist2, dist3;
  405. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  406. {
  407. if (pInfo->m_fValid == true)
  408. {
  409. pts.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  410. pts.y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  411. if ((pts.x != 0) && (pts.y != 0))
  412. {
  413. // V�rification de l'alignement
  414. if (cptValid >= m_Max_Alignement)
  415. {
  416. // Estimation droite � partir de tabPointsValides
  417. double ka, kb;
  418. RegressionLineaire(m_Max_Alignement, tabPointsValides, &ka, &kb);
  419. // Calcul de la distance orthogonale entre la droite et pts
  420. dpoint ptk, ptl, ptr;
  421. ptk.x = pts.x;
  422. ptk.y = ka * pts.x + kb;
  423. ptl.x = pts.x + 10;
  424. ptl.y = ka * ptl.x + kb;
  425. dist = distanceOrthPtDroite(pts, ptk, ptl, &ptr);
  426. if (dist < 3) // Si la distance est < � n pixels
  427. {
  428. cptNonValid = 0; // On remet le compteur � 0
  429. // Ce point est OK, on le garde
  430. // Remise � jour du tableau des points
  431. for (int i = 0; i < m_Max_Alignement-1; i++)
  432. {
  433. tabPointsValides[i].x = tabPointsValides[i+1].x;
  434. tabPointsValides[i].y = tabPointsValides[i+1].y;
  435. }
  436. tabPointsValides[m_Max_Alignement-1].x = pts.x;
  437. tabPointsValides[m_Max_Alignement-1].y = pts.y;
  438. tContinueGauche[dwPos] = 1;
  439. }
  440. else
  441. {
  442. cptNonValid++; // Nb de points non valides � la suite
  443. }
  444. // Si un nombre de points non valides suffisant a �t� d�tect� � la suite
  445. if (cptNonValid >= m_Max_Alignement - 1)
  446. {
  447. // On remet � 0 le tableau des valeurs
  448. for (int i = 0; i < m_Max_Alignement-1; i++)
  449. {
  450. tabPointsValides[i].x = 0;
  451. tabPointsValides[i].y = 0;
  452. }
  453. cptValid = 0; // On redemande un remplissage
  454. cptNonValid = 0;
  455. }
  456. }
  457. else
  458. {
  459. tabPointsValides[0].x = pInfo->m_Paroi[m_indexParoi].m_slope[2].m_ptDraw.x;
  460. tabPointsValides[0].y = pInfo->m_Paroi[m_indexParoi].m_slope[2].m_ptDraw.y;
  461. cptValid++;
  462. }
  463. }
  464. }
  465. pInfo++;
  466. }
  467. // Puis de droite � gauche
  468. pInfo = &m_pMeasures[m_dwPoints-1];
  469. cptValid = 0;
  470. cptNonValid = 0;
  471. bDebut = false;
  472. for (dwPos = m_dwPoints-1; dwPos > 0; dwPos--)
  473. {
  474. if (pInfo->m_fValid == true)
  475. {
  476. pts.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  477. pts.y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  478. if ((pts.x != 0) && (pts.y != 0))
  479. {
  480. // V�rification de l'alignement
  481. if (cptValid >= m_Max_Alignement)
  482. {
  483. // Estimation droite � partir de tabPointsValides
  484. double ka, kb;
  485. RegressionLineaire(m_Max_Alignement, tabPointsValides, &ka, &kb);
  486. // Calcul de la distance orthogonale entre la droite et pts
  487. dpoint ptk, ptl, ptr;
  488. ptk.x = pts.x;
  489. ptk.y = ka * pts.x + kb;
  490. ptl.x = pts.x + 10;
  491. ptl.y = ka * ptl.x + kb;
  492. dist = distanceOrthPtDroite(pts, ptk, ptl, &ptr);
  493. if (dist < 3) // Si la distance est < � x pixels
  494. {
  495. cptNonValid = 0; // On remet le compteur � 0
  496. // Ce point est OK, on le garde
  497. // Remise � jour du tableau des points
  498. for (int i = 0; i < m_Max_Alignement-1; i++)
  499. {
  500. tabPointsValides[i].x = tabPointsValides[i+1].x;
  501. tabPointsValides[i].y = tabPointsValides[i+1].y;
  502. }
  503. tabPointsValides[m_Max_Alignement-1].x = pts.x;
  504. tabPointsValides[m_Max_Alignement-1].y = pts.y;
  505. tContinueDroite[dwPos] = 1;
  506. }
  507. else
  508. {
  509. cptNonValid++; // Nb de points non valides � la suite
  510. }
  511. // Si un nombre de points non valides suffisant a �t� d�tect� � la suite
  512. if (cptNonValid >= m_Max_Alignement - 1)
  513. {
  514. // On remet � 0 le tableau des valeurs
  515. for (int i = 0; i < m_Max_Alignement-1; i++)
  516. {
  517. tabPointsValides[i].x = 0;
  518. tabPointsValides[i].y = 0;
  519. }
  520. cptNonValid = 0;
  521. cptValid = 0; // On redemande un remplissage
  522. }
  523. }
  524. else
  525. {
  526. tabPointsValides[cptValid].x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  527. tabPointsValides[cptValid].y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  528. cptValid++;
  529. }
  530. }
  531. }
  532. pInfo--;
  533. }
  534. pInfo = &m_pMeasures[0];
  535. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  536. {
  537. if (pInfo->m_fValid == true)
  538. {
  539. if ((tContinueGauche[dwPos] == 1) || (tContinueDroite[dwPos] == 1))
  540. {
  541. tContinue[dwPos] = 1;
  542. }
  543. }
  544. tContinue2[dwPos] = tContinue[dwPos];
  545. pInfo++;
  546. }
  547. bool bNonContinue = false;
  548. int cptNonContinue = 0;
  549. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  550. {
  551. if (tContinue2[dwPos] == 1)
  552. {
  553. cptNonContinue = 0;
  554. }
  555. else if (tContinue2[dwPos] == 0)
  556. {
  557. cptNonContinue++;
  558. bNonContinue = true;
  559. }
  560. // 1- On faits rejoindre les segments si l'�cart est faible (sur front montant)
  561. if ((tContinue2[dwPos] == 1) && bNonContinue)
  562. {
  563. bNonContinue = false;
  564. if (cptNonContinue < 3*m_Max_Alignement)
  565. {
  566. // Dans ce cas on peut rejoindre les 2 segments
  567. for (dwPos2 = dwPos - 3*m_Max_Alignement; dwPos2 < dwPos; dwPos2++)
  568. {
  569. if (dwPos2 >= 0)
  570. {
  571. tContinue2[dwPos2] = 1;
  572. }
  573. }
  574. }
  575. }
  576. }
  577. int indexSegments = 0;
  578. bNonContinue = true;
  579. int maxSegment = 0;
  580. int longueurSegment = 0;
  581. int indexMaxSegment = 1;
  582. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  583. {
  584. if (tContinue2[dwPos] == 0)
  585. {
  586. bNonContinue = true;
  587. }
  588. if ((tContinue2[dwPos] == 1) && bNonContinue)
  589. {
  590. indexSegments++;
  591. bNonContinue = false;
  592. longueurSegment = 0;
  593. }
  594. // 2 - On num�rote chacun des segments
  595. if (tContinue2[dwPos] == 1)
  596. {
  597. tContinue2[dwPos] = indexSegments;
  598. longueurSegment++;
  599. if (longueurSegment > maxSegment)
  600. {
  601. maxSegment = longueurSegment;
  602. indexMaxSegment = indexSegments;
  603. }
  604. }
  605. }
  606. // 3 - Si plus de 1 segment on regarde celui qui est le plus grand
  607. if (indexSegments > 1)
  608. {
  609. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  610. {
  611. if (tContinue2[dwPos] != indexMaxSegment)
  612. {
  613. // 4- On efface les traits continus des segments qui ne sont pas le plus long
  614. tContinue[dwPos] = 0;
  615. }
  616. }
  617. }
  618. dwMin = long (-1);
  619. pInfo = &m_pMeasures[0];
  620. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  621. {
  622. pInfo->m_fValid = (tContinue[dwPos] == 1);
  623. pInfo++;
  624. }
  625. dwMin = long (-1);
  626. pInfo = &m_pMeasures[0];
  627. dist_etalon = 0;
  628. dist_etalon2 = 0;
  629. m_nbpoints_curve = 0;
  630. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  631. {
  632. if (pInfo->m_fValid == true)
  633. {
  634. // Au premier point on m�morise la valeur de la distance qui va servir d'�talon pour les autres points
  635. pta.x = m_vUser[dwPos].x;
  636. pta.y = m_vUser[dwPos].y;
  637. ptb.x = pInfo->m_Paroi[0].m_slope[2].m_ptMiddle.x;
  638. ptb.y = pInfo->m_Paroi[0].m_slope[2].m_ptMiddle.y;
  639. pte.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  640. pte.y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  641. ptf.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  642. ptf.y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  643. if (m_nbpoints_curve == 0)
  644. {
  645. dist_etalon = distance(pta, ptb);
  646. dist_etalon2 = distance(pta, pte);
  647. tpoints[0].x = m_vUser[dwPos].x;
  648. tpoints[0].y = m_vUser[dwPos].y;
  649. m_nbpoints_curve++;
  650. }
  651. else
  652. {
  653. bool outOfImage;
  654. outOfImage = false;
  655. // Intersection entre le cercle centr� sur ptb de rayon dist_etalon, et la droite pta, ptb
  656. if (InterCercleDroite(ptb, dist_etalon, pta, ptb, &s1, &s2))
  657. {
  658. // Renvoie le point le plus proche de pta
  659. // Qui va �tre le nouveau point
  660. ptc = leplusproche(pta, s1, s2);
  661. dist = distance(ptc, pta);
  662. // Contre les bugs aux extr�mit�s des images
  663. if (dist <= (2 * dist_etalon))
  664. //if ((ptc.x <= m_rectCadre.GetRight()) && (ptc.x >= m_rectCadre.GetLeft()))
  665. {
  666. tpoints[m_nbpoints_curve].x = ptc.x;
  667. tpoints[m_nbpoints_curve].y = ptc.y;
  668. }
  669. else
  670. {
  671. outOfImage = true;
  672. }
  673. }
  674. else
  675. {
  676. tpoints[m_nbpoints_curve].x = m_vUser[dwPos].x;
  677. tpoints[m_nbpoints_curve].y = m_vUser[dwPos].y;
  678. }
  679. if (!outOfImage)
  680. {
  681. m_nbpoints_curve++;
  682. }
  683. }
  684. }
  685. pInfo++;
  686. }
  687. moindres_carres_parabole(m_nbpoints_curve, tpoints, &m_coeff_a, &m_coeff_b, &m_coeff_c);
  688. CVector vPerp;
  689. Point point1, point2, point3;
  690. // On recalcul l'EIM, en utilisant cette fois les perpendiculaires � la courbe obtenue
  691. dwMin = long (-1);
  692. int i;
  693. i = 0;
  694. pInfo = &m_pMeasures[0];
  695. bool bDistDeb;
  696. bDistDeb = false;
  697. double ka, kb;
  698. bDebut = false;
  699. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  700. {
  701. if (pInfo->m_fValid == true)
  702. {
  703. pta.x = tpoints[i].x;
  704. pta.y = tpoints[i].y;
  705. // La tangente (d�riv�e) de y = ax2 + b x + c est y = 2ax + b
  706. // Le coefficient directeur de la perpendiculaire � la tangente est -1/b
  707. // Pour la perpendiculaire qui passe par pta.x, pta.y, y = ka x + kb
  708. if (m_coeff_b != 0)
  709. {
  710. ka = (double) -1.0 / (2 * m_coeff_a);
  711. }
  712. else
  713. {
  714. ka = 0.0;
  715. }
  716. kb = pta.y - ka * pta.x;
  717. ptb.y = tpoints[i].y + 2 * dist_etalon;
  718. if (ka != 0)
  719. {
  720. ptb.x = (ptb.y - kb) / ka;
  721. }
  722. else
  723. {
  724. ptb.x = tpoints[i].x;
  725. }
  726. // Intersection entre le cercle centr� sur pta de rayon dist_etalon, et la droite pta, ptb
  727. bool bInter = InterCercleDroite(pta, 2 * dist_etalon2, pta, ptb, &s1, &s2);
  728. if (bInter)
  729. {
  730. if (m_bNearWall)
  731. {
  732. if (s1.y <= s2.y)
  733. {
  734. ptc.x = s1.x;
  735. ptc.y = s1.y;
  736. ptd.x = s2.x;
  737. ptd.y = s2.y;
  738. }
  739. else
  740. {
  741. ptc.x = s2.x;
  742. ptc.y = s2.y;
  743. ptd.x = s1.x;
  744. ptd.y = s1.y;
  745. }
  746. }
  747. else
  748. {
  749. if (s1.y > s2.y)
  750. {
  751. ptc.x = s1.x;
  752. ptc.y = s1.y;
  753. ptd.x = s2.x;
  754. ptd.y = s2.y;
  755. }
  756. else
  757. {
  758. ptc.x = s2.x;
  759. ptc.y = s2.y;
  760. ptd.x = s1.x;
  761. ptd.y = s1.y;
  762. }
  763. }
  764. }
  765. else
  766. {
  767. ptc.x = ptb.x;
  768. ptc.y = ptb.y;
  769. ptd.x = ptb.x;
  770. ptd.y = ptb.y;
  771. }
  772. point1.x = (int) pta.x;
  773. point1.y = (int) pta.y;
  774. point2.x = (int) ptc.x;
  775. point2.y = (int) ptc.y;
  776. point3.x = (int) ptd.x;
  777. point3.y = (int) ptd.y;
  778. m_pt1perp[i].x = point1.x;
  779. m_pt1perp[i].y = point1.y;
  780. m_pt2perp[i].x = point2.x;
  781. m_pt2perp[i].y = point2.y;
  782. i++;
  783. }
  784. pInfo++;
  785. }
  786. /* Enlev�
  787. // Calculs aux extr�mit�s
  788. // Au d�but
  789. dpoint pt0, pt1;
  790. pt0.x = debx;
  791. // y = ax2 + b x + c
  792. pt0.y = (m_coeff_a * pt0.x * pt0.x) + (m_coeff_b * pt0.x) + m_coeff_c;
  793. // La tangente (d�riv�e) de y = ax2 + b x + c est y = 2ax + b
  794. // Le coefficient directeur de la perpendiculaire � la tangente est -1/b
  795. double ka, kb;
  796. // Pour la perpendiculaire qui passe par pta.x, pta.y, y = ka x + kb
  797. if (m_coeff_b != 0)
  798. {
  799. ka = (double) -1.0 / (2 * m_coeff_a);
  800. }
  801. else
  802. {
  803. ka = 0.0;
  804. }
  805. kb = pt0.y - ka * pt0.x;
  806. double kb2 = m_coeff_b;
  807. pt1.y = pt0.y + 2 * dist_etalon;
  808. if (ka != 0)
  809. {
  810. pt1.x = (pt1.y - kb) / ka;
  811. }
  812. else
  813. {
  814. pt1.x = pt0.x;
  815. }
  816. // Intersection entre le cercle centr� sur pt0 de rayon dist_etalon, et la droite xd,yd, ptcel
  817. if (InterCercleDroite(pt0, dist_Debut, pt0, pt1, &s1, &s2))
  818. {
  819. dist2 = distance(s1, ptdeb);
  820. dist3 = distance(s2, ptdeb);
  821. if (dist2 < dist3)
  822. {
  823. m_ptDebut.x = (int) s1.x;
  824. m_ptDebut.y = (int) s1.y;
  825. }
  826. else
  827. {
  828. m_ptDebut.x = (int) s2.x;
  829. m_ptDebut.y = (int) s2.y;
  830. }
  831. }
  832. // A la fin
  833. pt0.x = finx;
  834. // y = ax2 + b x + c
  835. pt0.y = (m_coeff_a * pt0.x * pt0.x) + (m_coeff_b * pt0.x) + m_coeff_c;
  836. // La tangente (d�riv�e) de y = ax2 + b x + c est y = 2ax + b
  837. // Le coefficient directeur de la perpendiculaire � la tangente est -1/b
  838. // Pour la perpendiculaire qui passe par pta.x, pta.y, y = ka x + kb
  839. if (m_coeff_b != 0)
  840. {
  841. ka = (double) -1.0 / (2 * m_coeff_a);
  842. }
  843. else
  844. {
  845. ka = 0.0;
  846. }
  847. kb = pt0.y - ka * pt0.x;
  848. kb2 = m_coeff_b;
  849. pt1.y = pt0.y + 2 * dist_etalon;
  850. if (ka != 0)
  851. {
  852. pt1.x = (pt1.y - kb) / ka;
  853. }
  854. else
  855. {
  856. pt1.x = pt0.x;
  857. }
  858. // Intersection entre le cercle centr� sur pt0 de rayon dist_etalon, et la droite xd,yd, ptcel
  859. if (InterCercleDroite(pt0, dist_Fin, pt0, pt1, &s1, &s2))
  860. {
  861. dist2 = distance(s1, ptfin);
  862. dist3 = distance(s2, ptfin);
  863. if (dist2 < dist3)
  864. {
  865. m_ptFin.x = (int) s1.x;
  866. m_ptFin.y = (int) s1.y;
  867. }
  868. else
  869. {
  870. m_ptFin.x = (int) s2.x;
  871. m_ptFin.y = (int) s2.y;
  872. }
  873. }
  874. */
  875. }
  876. /*----------------------------------------------------------\
  877. | Paroi |
  878. |-----------------------------------------------------------|
  879. | DESCRIPTION : |
  880. | Calcul de l'�paisseur d'une paroi dans une zone donn�e |
  881. \----------------------------------------------------------*/
  882. void CEIMBase::Paroi()
  883. {
  884. long dwPos, dwMin, dwFirst;
  885. int debx, finx;
  886. CEIMInfo *pInfo = &m_pMeasures[0];
  887. #ifdef NEW_EIM
  888. double dist_Debut, dist_Fin;
  889. dpoint pts;
  890. #endif
  891. bool bDebut = false;
  892. dpoint ptdeb, ptfin;
  893. ptdeb.x = ptfin.x = 0;
  894. ptdeb.y = ptfin.y = 0;
  895. m_nbpoints_curve = 0;
  896. m_coeff_a = -1.0;
  897. m_coeff_b = -1.0;
  898. m_coeff_c = -1.0;
  899. assert(!m_fDiameter && m_pMeasures && GfxImageValid());
  900. dwMin = long (-1);
  901. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  902. {
  903. // Ligne perpendiculaire � la paroi sur laquelle effectuer la mesure
  904. pInfo->m_Paroi[0].m_vMeasure = m_vUser.Orthogonal(m_vUser[dwPos], 0);
  905. if (AddVector(pInfo->m_Paroi[0]))
  906. {
  907. ComputeEIM(pInfo);
  908. // recherche des premi�res position valides, afin de r�duire l'�tendue de l'histogramme
  909. dwFirst = pInfo->m_Paroi[0].m_slope[0].m_dwPos[0];
  910. if (dwFirst < dwMin)
  911. {
  912. dwMin = dwFirst;
  913. }
  914. if (bDebut == false)
  915. {
  916. bDebut = true;
  917. debx = m_vUser[dwPos].x;
  918. #ifndef NEW_EIM
  919. ptdeb.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  920. ptdeb.y = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y;
  921. #endif
  922. }
  923. #ifndef NEW_EIM
  924. ptfin.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  925. ptfin.y = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y;
  926. #endif
  927. finx = m_vUser[dwPos].x;
  928. }
  929. else
  930. {
  931. pInfo->m_fValid = false;
  932. }
  933. pInfo->m_diagnostic = m_diag;
  934. pInfo++;
  935. }
  936. #ifdef NEW_EIM
  937. // Modif CJ2007
  938. if (m_Assist)
  939. {
  940. ParallelismeEIM();
  941. CVector vPerp;
  942. // On recalcul l'EIM, en utilisant cette fois les perpendiculaires � la courbe obtenue
  943. dwMin = long (-1);
  944. int i;
  945. i = 0;
  946. pInfo = &m_pMeasures[0];
  947. bool bDistDeb;
  948. bDistDeb = false;
  949. bDebut = false;
  950. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  951. {
  952. if (pInfo->m_fValid == true)
  953. {
  954. if ((m_pt1perp[i].y >= 0) && (m_pt2perp[i].y >= 0) && (m_pt1perp[i].x >= 0) && (m_pt2perp[i].x >= 0)
  955. && (m_pt1perp[i].y < 576) && (m_pt2perp[i].y < 576) && (m_pt1perp[i].x < 768) && (m_pt2perp[i].x < 768))
  956. {
  957. pInfo->m_Paroi[0].m_vMeasure = CVector(m_pt1perp[i], m_pt2perp[i]);
  958. if (AddVector(pInfo->m_Paroi[0]))
  959. {
  960. ComputeEIM(pInfo);
  961. // Recherche des premi�res position valides, afin de r�duire l'�tendue de l'histogramme
  962. dwFirst = pInfo->m_Paroi[0].m_slope[0].m_dwPos[0];
  963. if (dwFirst < dwMin)
  964. {
  965. dwMin = dwFirst;
  966. }
  967. if (bDebut == false)
  968. {
  969. bDebut = true;
  970. ptdeb.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  971. ptdeb.y = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y;
  972. }
  973. ptfin.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  974. ptfin.y = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y;
  975. dpoint ptt, ptr;
  976. ptt.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  977. ptt.y = (m_coeff_a * ptt.x * ptt.x) + (m_coeff_b * ptt.x) + m_coeff_c;
  978. ptr.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  979. ptr.y = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y;
  980. if (!bDistDeb)
  981. {
  982. bDistDeb = true;
  983. dist_Debut = distance(ptt, ptr);
  984. }
  985. dist_Fin = distance(ptt, ptr);
  986. }
  987. else
  988. {
  989. pInfo->m_fValid = false;
  990. }
  991. pts.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  992. }
  993. i++;
  994. }
  995. pInfo++;
  996. }
  997. }
  998. #endif
  999. if (ptdeb.x < ptfin.x)
  1000. {
  1001. m_ptDebut.x = (long) ptdeb.x;
  1002. m_ptFin.x = (long) ptfin.x;
  1003. }
  1004. else
  1005. {
  1006. m_ptDebut.x = (long) ptfin.x;
  1007. m_ptFin.x = (long) ptdeb.x;
  1008. }
  1009. // Ajustement des vecteurs de mesures et des positions
  1010. pInfo = &m_pMeasures[0];
  1011. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  1012. {
  1013. pInfo->m_Paroi[0].m_slope[0].m_dwPos[0] -= dwMin;
  1014. pInfo->m_Paroi[0].m_slope[0].m_dwPos[1] -= dwMin;
  1015. pInfo->m_Paroi[0].m_slope[0].m_dwMiddle -= dwMin;
  1016. pInfo->m_Paroi[0].m_slope[1].m_dwPos[0] -= dwMin;
  1017. pInfo->m_Paroi[0].m_slope[1].m_dwPos[1] -= dwMin;
  1018. pInfo->m_Paroi[0].m_slope[1].m_dwMiddle -= dwMin;
  1019. pInfo->m_Paroi[0].m_slope[2].m_dwPos[0] -= dwMin;
  1020. pInfo->m_Paroi[0].m_slope[2].m_dwPos[1] -= dwMin;
  1021. pInfo->m_Paroi[0].m_slope[2].m_dwMiddle -= dwMin;
  1022. pInfo->m_Paroi[0].m_vMeasure = CVector(pInfo->m_Paroi[0].m_vMeasure[dwMin], pInfo->m_Paroi[0].m_vMeasure.EndPoint());
  1023. pInfo++;
  1024. }
  1025. } // end of Paroi
  1026. /*-----------------------------------------------------------\
  1027. | ParallelismeDistensibilite |
  1028. |-----------------------------------------------------------|
  1029. | DESCRIPTION : |
  1030. | Fonction de calcul du parall�lisme du trait utilisateur |
  1031. | Par rapport � la paroi |
  1032. | Pour le calcul du diam�tre pour la distensibilit� |
  1033. \----------------------------------------------------------*/
  1034. void CEIMBase::ParallelismeDistensibilite()
  1035. {
  1036. int nbOk;
  1037. long dwPos;
  1038. dpoint pta, ptb, ptc, s1, s2;
  1039. double distMoy, sommeDist;
  1040. dpoint tpoints[MAX_POINTS_EIM_AUTO];
  1041. double ka, kb;
  1042. Point vp1, vp2;
  1043. bool bInter;
  1044. CEIMInfo *pInfo;
  1045. ka = 0;
  1046. kb = 0;
  1047. // 1)- On va estimer la distance du milieu de la veine sur les points valides
  1048. nbOk = 0;
  1049. distMoy = 0;
  1050. sommeDist = 0;
  1051. pInfo = &m_pMeasures [0];
  1052. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  1053. {
  1054. pInfo->m_Paroi[0].m_vMeasure = m_vUser.Orthogonal(m_vUser[dwPos], 0);
  1055. // pour l'histogramme, le deuxi�me vecteur est requis m�me si la mesure a �chou�
  1056. pInfo->m_Paroi[1].m_vMeasure = m_vUser.Orthogonal(m_vUser[dwPos], 1);
  1057. if (AddVector(pInfo->m_Paroi [0])
  1058. && ((m_algoDiameter == algoProfile) ?
  1059. AddVector(pInfo->m_Paroi [1]) : // recherche d'un profil sur la paroi sup�rieure
  1060. FindOpposite(pInfo->m_Paroi[0], pInfo->m_Paroi[1]) // recherche sur la paroi sup�rieure du sym�trique de la paroi inf�rieure
  1061. )
  1062. )
  1063. {
  1064. ComputeEIM(pInfo);
  1065. distMoy = (pInfo->m_dblDia / 2.0);
  1066. sommeDist += distMoy;
  1067. nbOk++;
  1068. }
  1069. pInfo++;
  1070. }
  1071. if (nbOk > 0)
  1072. {
  1073. distMoy = sommeDist / nbOk;
  1074. // 2)- On va d�terminer les points au centre
  1075. pInfo = &m_pMeasures [0];
  1076. m_nbpoints_curve = 0;
  1077. nbOk = 0;
  1078. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  1079. {
  1080. pInfo->m_Paroi[0].m_vMeasure = m_vUser.Orthogonal(m_vUser[dwPos], 0);
  1081. // On regarde que la paroi du bas pour le parall�lisme
  1082. if (AddVector(pInfo->m_Paroi [0]))
  1083. {
  1084. ComputeEIM(pInfo);
  1085. // Au premier point on m�morise la valeur de la distance qui va servir d'�talon pour les autres points
  1086. pta.x = m_vUser[dwPos].x;
  1087. pta.y = m_vUser[dwPos].y;
  1088. ptb.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  1089. ptb.y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  1090. // Intersection cercle centr� sur ptb
  1091. bInter = InterCercleDroite(ptb, distMoy, pta, ptb, &s1, &s2);
  1092. // On prend celui qui est le plus pr�s de pta
  1093. ptc = leplusproche(pta, s1, s2);
  1094. // On stocke le point trouv� pour faire l'approximation
  1095. tpoints[nbOk].x = ptc.x;
  1096. tpoints[nbOk].y = ptc.y;
  1097. nbOk++;
  1098. }
  1099. pInfo++;
  1100. }
  1101. if (nbOk > 4) // Plusieurs points sinon �rron�s
  1102. {
  1103. // Alors on approxime les points par une droite
  1104. RegressionLineaire(nbOk, tpoints, &ka, &kb);
  1105. // On met � jour m_vUser en fonction de la droite approxim�e : il va �tre utilis� par la suite
  1106. vp1.x = m_vUser[0].x;
  1107. vp1.y = (int) ((double) ka * vp1.x + kb);
  1108. vp2.x = m_vUser[dwPos].x;
  1109. vp2.y = (int) ((double) ka * vp2.x + kb);
  1110. // On d�termine les nouvelles valeurs de m_vUser
  1111. // Et c'est celui l� qui va �tre utilis� dans la fonction de base
  1112. m_vUser = CVector (vp1, vp2);
  1113. m_StartPoint.x = vp1.x;
  1114. m_StartPoint.y = vp1.y;
  1115. m_EndPoint.x = vp2.x;
  1116. m_EndPoint.y = vp2.y;
  1117. }
  1118. else
  1119. {
  1120. m_StartPoint.x = m_vUser[0].x;
  1121. m_StartPoint.y = m_vUser[0].y;
  1122. m_EndPoint.x = m_vUser[1].x;
  1123. m_EndPoint.y = m_vUser[1].y;
  1124. }
  1125. // Les calculs de base vont se faire avec le nouvel m_vUser calcul�
  1126. }
  1127. }
  1128. /*----------------------------------------------------------\
  1129. | Diameter |
  1130. |-----------------------------------------------------------|
  1131. | DESCRIPTION : |
  1132. | Mesure du diam�tre d'un vaisseau |
  1133. |-----------------------------------------------------------|
  1134. | PARAMETRES : |
  1135. | pScale : �chelle � utiliser pour les mesures |
  1136. | gfx : image en niveau de gris d'o� lire les donn�es |
  1137. | pt1 : premier point du segment d�terminant la ligne |
  1138. | de la paroi. |
  1139. | pt2 : deuxi�me point du segment |
  1140. \----------------------------------------------------------*/
  1141. void CEIMBase::Diameter()
  1142. {
  1143. CEIMInfo *pInfo;
  1144. long dwMin [2], dwPos, dwFirst;
  1145. assert (m_fDiameter && m_pMeasures && GfxImageValid());
  1146. if (m_parallelismeDiametre)
  1147. {
  1148. ParallelismeDistensibilite();
  1149. }
  1150. dwMin[0] = long(-1);
  1151. dwMin[1] = long(-1);
  1152. bool bDistDeb, bDebut;
  1153. bDistDeb = false;
  1154. bDebut = false;
  1155. pInfo = &m_pMeasures[0];
  1156. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  1157. {
  1158. pInfo->m_Paroi[0].m_vMeasure = m_vUser.Orthogonal(m_vUser[dwPos], 0);
  1159. // Pour l'histogramme, le deuxi�me vecteur est requis m�me si la mesure a �chou�
  1160. pInfo->m_Paroi[1].m_vMeasure = m_vUser.Orthogonal(m_vUser[dwPos], 1);
  1161. if ( AddVector(pInfo->m_Paroi [0])
  1162. && ( (m_algoDiameter == algoProfile) ?
  1163. AddVector(pInfo->m_Paroi [1]) : // recherche d'un profil sur la paroi sup�rieure
  1164. FindOpposite (pInfo->m_Paroi[0], pInfo->m_Paroi[1]) // recherche sur la paroi sup�rieure du sym�trique de la paroi inf�rieure
  1165. )
  1166. )
  1167. {
  1168. ComputeEIM (pInfo);
  1169. // recherche des premi�res position valides, afin de r�duire l'�tendue de l'histogramme
  1170. for (int j = 0; j < 2; j++)
  1171. {
  1172. dwFirst = pInfo->m_Paroi[j].m_slope[0].m_dwPos[0];
  1173. if (dwFirst < dwMin [j])
  1174. dwMin[j] = dwFirst;
  1175. }
  1176. }
  1177. else
  1178. {
  1179. // recalcul syst�matique, car cette fonction est appel� lors de la modification des seuils
  1180. pInfo->m_fValid = false;
  1181. }
  1182. pInfo++;
  1183. }
  1184. // ajustement des vecteurs de mesures et des positions
  1185. pInfo = &m_pMeasures [0];
  1186. for (dwPos = 0; dwPos < m_dwPoints; dwPos++)
  1187. {
  1188. for (int i = 0; i < 2; i++)
  1189. {
  1190. pInfo->m_Paroi[i].m_slope[0].m_dwPos[0] -= dwMin[i];
  1191. pInfo->m_Paroi[i].m_slope[0].m_dwPos[1] -= dwMin[i];
  1192. pInfo->m_Paroi[i].m_slope[0].m_dwMiddle -= dwMin[i];
  1193. pInfo->m_Paroi[i].m_slope[1].m_dwPos[0] -= dwMin[i];
  1194. pInfo->m_Paroi[i].m_slope[1].m_dwPos[1] -= dwMin[i];
  1195. pInfo->m_Paroi[i].m_slope[1].m_dwMiddle -= dwMin[i];
  1196. pInfo->m_Paroi[i].m_vMeasure = CVector (pInfo->m_Paroi[i].m_vMeasure[dwMin[i]], pInfo->m_Paroi[i].m_vMeasure.EndPoint());
  1197. }
  1198. pInfo++;
  1199. }
  1200. } // end of Diameter
  1201. /*----------------------------------------------------------\
  1202. | CEIM::AddVector |
  1203. |-----------------------------------------------------------|
  1204. | DESCRIPTION : |
  1205. | Calcul de l'�paisseur d'une paroi dans une zone donn�e |
  1206. |-----------------------------------------------------------|
  1207. | PARAMETRES : |
  1208. | paroi : CEIMInfo � remplir avec les mesures |
  1209. \----------------------------------------------------------*/
  1210. bool CEIMBase::AddVector(sParoi &paroi)
  1211. {
  1212. long dwPoint, dwLast = THICKNESS - 1; // le dernier point sur lequel effectuer une mesure (au pire)
  1213. // on s'assure que le vecteur ne d�passe pas la zone d'affichage
  1214. // paroi.m_vMeasure.Mask (*m_pGfx); dwLast = min( dwMax, m_vMeasure.Length())
  1215. assert (PointInBuffer (paroi.m_vMeasure [0]));
  1216. // afin de traiter la variation d'intensit� en m�me temps, on r�cup�re le premier
  1217. // point ind�pendamment des autres
  1218. // ASSERT ((paroi.m_vMeasure [0].x != 301) && (paroi.m_vMeasure [0].x != 336));
  1219. m_bBuffer [0] = GetIntensity (paroi.m_vMeasure [0]);
  1220. for (dwPoint = 1; dwPoint <= dwLast; dwPoint++)
  1221. {
  1222. const Point &pt = paroi.m_vMeasure [dwPoint];
  1223. if (PointInBuffer (pt))
  1224. {
  1225. // remplissage de la m�moire tampon
  1226. m_bBuffer [dwPoint] = GetIntensity (pt);
  1227. // calcul de la variation de densit�
  1228. m_cOffsets [dwPoint] = Delta (m_bBuffer [dwPoint], m_bBuffer [dwPoint - 1]);
  1229. }
  1230. else // peu �l�gant, mais efficace
  1231. {
  1232. dwLast = dwPoint - 1; // interrompra �galement la prochaine boucle (de d�tection de profil)
  1233. }
  1234. }
  1235. // On mesure l'E.I.M. sur la ligne extraite
  1236. if (m_versionTomtecAout08)
  1237. {
  1238. // Pour pouvoir afficher les points milieux m�me s'ils sont pas valides
  1239. int res = MeasureLineBuffer (paroi, m_bBuffer, m_cOffsets, dwPoint);
  1240. {
  1241. SetMiddlePoint (paroi.m_slope [0], paroi.m_vMeasure);
  1242. SetMiddlePoint (paroi.m_slope [1], paroi.m_vMeasure);
  1243. // On mesure l'IMT sur la ligne extraite
  1244. SetMiddlePoint (paroi.m_slope [2], paroi.m_vMeasure, true);
  1245. if (res)
  1246. {
  1247. return (true);
  1248. }
  1249. }
  1250. }
  1251. else
  1252. {
  1253. if (MeasureLineBuffer (paroi, m_bBuffer, m_cOffsets, dwPoint) > 0)
  1254. {
  1255. SetMiddlePoint (paroi.m_slope [0], paroi.m_vMeasure);
  1256. SetMiddlePoint (paroi.m_slope [1], paroi.m_vMeasure);
  1257. // On mesure l'IMT sur la ligne extraite
  1258. SetMiddlePoint (paroi.m_slope [2], paroi.m_vMeasure, true);
  1259. return (true);
  1260. }
  1261. }
  1262. return (false);
  1263. } // end of AddVector
  1264. /*----------------------------------------------------------\
  1265. | FindOpposite |
  1266. |-----------------------------------------------------------|
  1267. | DESCRIPTION : |
  1268. | Recherche le point adventice sym�trique|
  1269. |-----------------------------------------------------------|
  1270. | PARAMETRES : |
  1271. | paroi : CEIMInfo � remplir avec les mesures |
  1272. \----------------------------------------------------------*/
  1273. bool CEIMBase::FindOpposite(sParoi &paroi1, sParoi &paroi0)
  1274. {
  1275. long dwSeek = paroi0.m_slope[0].m_dwIntensity,
  1276. dwMax = GetIntensity(paroi1.m_vMeasure[paroi0.m_slope[1].m_dwPos[1]]),
  1277. dwPoint;
  1278. bool fFound, fInGfx;
  1279. // afin de traiter la variation d'intensit� en m�me temps, on r�cup�re le premier
  1280. // point ind�pendamment des autres
  1281. dwPoint = 0;
  1282. fFound = false;
  1283. fInGfx = true;
  1284. do
  1285. {
  1286. const Point &pt = paroi1.m_vMeasure [dwPoint];
  1287. fInGfx = PointInBuffer (pt);
  1288. if (fInGfx)
  1289. {
  1290. unsigned char bLevel = GetIntensity (pt);
  1291. m_bBuffer [dwPoint] = bLevel;
  1292. if (bLevel < dwSeek)
  1293. dwPoint++;
  1294. else if (bLevel > dwMax)
  1295. // la valeur trouv�e d�passe la valeur du sommet de la pente de la paroi
  1296. // du bas, on consid�re que c'est une erreur
  1297. fInGfx = false;
  1298. else
  1299. {
  1300. long dwPos = dwPoint;
  1301. // il est tr�s peu probable que l'on arrive juste sur le milieu de la pente.
  1302. // on cherche donc les extr�mes.
  1303. // recherche du bas de la pente
  1304. while (dwPoint && (m_bBuffer [dwPoint - 1] <= m_bBuffer [dwPoint]))
  1305. dwPoint--;
  1306. paroi1.m_slope [1].m_dwPos [0] = dwPoint;
  1307. // recherche du sommet de la pente
  1308. dwPoint = dwPos + 1;
  1309. paroi1.m_slope [1].m_dwPos [1] = 0; // normalement d�j� fait
  1310. while (!paroi1.m_slope [1].m_dwPos [1])
  1311. {
  1312. const Point &pt = paroi1.m_vMeasure [dwPoint];
  1313. if (!PointInBuffer (pt))
  1314. paroi1.m_slope [1].m_dwPos [1] = dwPoint - 1;
  1315. else
  1316. {
  1317. m_bBuffer [dwPoint] = GetIntensity (pt);
  1318. if (m_bBuffer [dwPoint] > m_bBuffer [dwPoint - 1])
  1319. dwPoint++;
  1320. else
  1321. paroi1.m_slope [1].m_dwPos [1] = dwPoint - 1;
  1322. }
  1323. }
  1324. // la 1� pente est ignor�e par cette m�thode, seule la 2� pente est analys�e
  1325. SetMiddlePoint (paroi1.m_slope [1], paroi1.m_vMeasure);
  1326. fFound = true;
  1327. }
  1328. }
  1329. } while (fInGfx && !fFound);
  1330. return (fFound);
  1331. } // end of FindOpposite
  1332. /*----------------------------------------------------------\
  1333. | SetMiddlePoints |
  1334. |-----------------------------------------------------------|
  1335. | DESCRIPTION : |
  1336. | D�termine la position des deux points encadrants le |
  1337. | milieu d'une des deux pentes. |
  1338. | Les deux points retourn�s peuvent �tre confondus. |
  1339. |-----------------------------------------------------------|
  1340. | PARAMETRES : |
  1341. | slope : pente sur laquelle effectuer les mesures |
  1342. | vMeasure : vecteur sur lequel cette pente a �t� d�tect�e |
  1343. \----------------------------------------------------------*/
  1344. void CEIMBase::SetMiddlePoint(
  1345. sSlope &slope,
  1346. CVector &vMeasure,
  1347. bool reverseSlope)
  1348. {
  1349. int iMean;
  1350. long dwPos;
  1351. // on utilise le double du milieu, car 80+21/2=50, pas 50.5 puisque c'est un entier
  1352. //assert (AfxIsValidAddress (&slope, sizeof (slope)));
  1353. // [JAK - 06/09/02] l'assert surgit un peu trop souvent lors de mesure de la distensibilit�
  1354. // if ( reverseSlope )
  1355. // ASSERT (m_bBuffer[slope.m_dwPos[0]] > m_bBuffer [slope.m_dwPos[1]]);//ICI
  1356. // else
  1357. // ASSERT (m_bBuffer[slope.m_dwPos[0]] < m_bBuffer [slope.m_dwPos[1]]);
  1358. dwPos = slope.m_dwPos[0];
  1359. iMean = m_bBuffer [dwPos] + m_bBuffer [slope.m_dwPos [1]];
  1360. if (reverseSlope)
  1361. while (m_bBuffer [dwPos] * 2 > iMean) dwPos++;
  1362. else
  1363. while (m_bBuffer [dwPos] * 2 < iMean) dwPos++;
  1364. // La mesure d'EIM est maintenant faite ici, car les intensit�s des points sont
  1365. // n�cessaires pour estimer la position exacte du milieu (en INTENSITE)
  1366. if (m_bBuffer [dwPos] * 2 == iMean)
  1367. {
  1368. // en cas d'�galit�, les deux points sont confondus
  1369. slope.m_ptDraw =
  1370. slope.m_ptMiddle = vMeasure [dwPos];
  1371. slope.m_dblMiddle = 0.0;
  1372. }
  1373. else
  1374. {
  1375. dwPos--;
  1376. slope.m_ptMiddle = vMeasure [dwPos];
  1377. if ( reverseSlope )
  1378. {
  1379. if (iMean - 2 * m_bBuffer [dwPos + 1] < 2 * m_bBuffer [dwPos] - iMean)
  1380. slope.m_ptDraw = slope.m_ptMiddle;
  1381. else
  1382. slope.m_ptDraw = vMeasure [dwPos + 1];
  1383. // [JAK - 3/8/2002] ASSERT (m_bBuffer [dwPos + 1] < m_bBuffer [dwPos]);
  1384. }
  1385. else
  1386. {
  1387. if (2 * m_bBuffer [dwPos + 1] - iMean > iMean - 2 * m_bBuffer [dwPos])
  1388. slope.m_ptDraw = slope.m_ptMiddle;
  1389. else
  1390. slope.m_ptDraw = vMeasure [dwPos + 1];
  1391. //assert (m_bBuffer [dwPos + 1] > m_bBuffer [dwPos]);
  1392. }//
  1393. assert (abs (slope.m_ptMiddle.x - vMeasure [dwPos + 1].x) <= 1);
  1394. assert (abs (slope.m_ptMiddle.y - vMeasure [dwPos + 1].y) <= 1);
  1395. slope.m_dblMiddle =
  1396. ( double (iMean - m_bBuffer [dwPos] * 2)
  1397. * CVector (slope.m_ptMiddle, vMeasure [dwPos + 1]).Norm ()
  1398. / (m_bBuffer [dwPos + 1] - m_bBuffer [dwPos]) // bug potentiel : division par zero [JAK - 15/10/2002]
  1399. / 2
  1400. );
  1401. }
  1402. // permet un affichage beaucoup plus rapide de l'histogramme
  1403. slope.m_dwMiddle = dwPos;
  1404. slope.m_dwIntensity = iMean / 2;
  1405. } // fin de SetMiddlePoints
  1406. /*----------------------------------------------------------\
  1407. | CEIM::MeasureLineBuffer |
  1408. |-----------------------------------------------------------|
  1409. | DESCRIPTION : |
  1410. | Mesure de l'E.I.M. � partir d'un buffer d'intensit� et |
  1411. | de variation |
  1412. |-----------------------------------------------------------|
  1413. | PARAMETRES : |
  1414. | paroi : Info � d�finir sur la mesure d'EIM |
  1415. | pbIntensity : pointeur sur les intensit�s |
  1416. | pcOffsets : pointeur sur les variations d'intensit� |
  1417. | dwPoints : nombre de points � �tudier |
  1418. |-----------------------------------------------------------|
  1419. | RETOUR : |
  1420. | un bool�en indiquant si le profil a �t� reconnu |
  1421. \----------------------------------------------------------*/
  1422. int CEIMBase::MeasureLineBuffer
  1423. (
  1424. sParoi &paroi,
  1425. unsigned char* pbBuffer,
  1426. char *pcOffsets,
  1427. long dwPoints
  1428. )
  1429. {
  1430. m_diag = 0; // Permet de voir o� l'algorithme s'est arr�t� (afin de l'am�liorer)
  1431. // Valeur n�gative
  1432. if (dwPoints < 3)
  1433. {
  1434. return (0);
  1435. }
  1436. else
  1437. {
  1438. long dwStart, dwPos, dwFirst, dwLast, dwLastChanged;
  1439. bool fChanged;
  1440. /////////////////////////////////
  1441. // lissage de la courbe de densit�
  1442. /////////////////////////////////
  1443. // il ne faut pas corriger les ext�rieurs sinon, � cause du report,
  1444. // tous les points seront corrig�s
  1445. // sur 300 points le lissage dure moins d'une milliseconde
  1446. dwFirst = 2;
  1447. dwLastChanged = dwLast = dwPoints - 2;
  1448. do
  1449. {
  1450. char c, c1, c2, c3;
  1451. fChanged = false;
  1452. // on ne prend pas en compte les variations nulles, autrement dit
  1453. // un 1,1,0,-1,1 ->1,1,0,1(ou 0),1.
  1454. // ainsi les variations de 1 pixel sont ignor�es
  1455. // on conserve donc en m�moire le dernier point significatif (au d�but 0...)
  1456. c1 = pcOffsets [dwFirst - 1];
  1457. for (dwPos = dwFirst; dwPos < dwLast; dwPos++)
  1458. {
  1459. c = pcOffsets [dwPos - 1];
  1460. if (c) // non nul
  1461. c1 = c; // nouvelle variation
  1462. c2 = pcOffsets [dwPos ];
  1463. c3 = pcOffsets [dwPos + 1];
  1464. // on met � jour le pt central � jour si les deux extr�mes varient dans le m�me sens
  1465. // et que le point central varie dans le sens inverse.
  1466. if ((c1 == c3) && (c2 != c1))
  1467. {
  1468. pbBuffer [dwPos ] = (unsigned char )((pbBuffer [dwPos - 1] + pbBuffer [dwPos + 1]) / 2);
  1469. // on est oblig� de recalculer les variations
  1470. pcOffsets [dwPos ] = Delta (m_bBuffer [dwPos ], m_bBuffer [dwPos - 1]);
  1471. pcOffsets [dwPos + 1] = Delta (m_bBuffer [dwPos + 1], m_bBuffer [dwPos ]);
  1472. // ce test n'est pas la pour le FUN !! si l'�cart entre deux intensit� est 1
  1473. // le milieu sera le point de plus faible intensit�, ce qui ne changera rien
  1474. if ((pcOffsets [dwPos] != c2) || (pcOffsets [dwPos + 1] != c3))
  1475. {
  1476. if (!fChanged)
  1477. {
  1478. fChanged = true;
  1479. dwFirst = dwPos;
  1480. }
  1481. // d�s que fChanged est VRAI il faut initialiser dwLastChanged (petit oubli !!)
  1482. dwLastChanged = dwPos; // si on change dwLast, on quitte la boucle!!
  1483. }
  1484. }
  1485. }
  1486. dwLast = dwLastChanged;
  1487. } while (fChanged);
  1488. ////////////////////////////////////
  1489. // recherche du profil de densit� //
  1490. ////////////////////////////////////
  1491. // pour un algo avec gestion de seuils voir fichier EIM/AvecSeuil.cpp
  1492. // a) recherche d'une croissance (3 pixels de suite au moins : 2 variations de m�me sens)
  1493. // � partir du pixel donn�, pour un maximum de points donn�
  1494. // le premier est le plus complexe � trouver.
  1495. #ifdef TEST_FOR_FANTOME
  1496. dwStart = 2;
  1497. #endif
  1498. if ( LookForFirstPoint (dwStart, dwPoints, dwPos, m_bBuffer) )
  1499. {
  1500. m_diag = -1;
  1501. paroi.m_slope [0].m_dwPos [0] = dwPos; // sera modifi� si le delta est insuffisant
  1502. // b) recherche d'une d�croissance (3 pixels de suite au moins : 2 variations de m�me sens)
  1503. bool variation = LookForVariation (dwStart, pcOffsets, dwPoints, enumDown, dwPos);
  1504. #ifdef TEST_FOR_FANTOME
  1505. if ( !variation )
  1506. {
  1507. if ( LookForFirstPoint (dwStart, dwPoints, dwPos, m_bBuffer) )
  1508. {
  1509. variation = LookForVariation (dwStart, pcOffsets, dwPoints, enumDown, dwPos);
  1510. }
  1511. }
  1512. #endif
  1513. if ( variation )
  1514. {
  1515. m_diag = -2;
  1516. paroi.m_slope [0].m_dwPos [1] = dwPos;
  1517. paroi.m_slope [2].m_dwPos [0] = dwPos; // Pour INT
  1518. // "g�n�ration" de plateaux. Suppression des petites irr�gularit�s sur des plateaux,
  1519. // afin de d�tecter ais�ment les zones de saturation
  1520. // ce n'est n�cessaire qu'� ce niveau
  1521. for (dwFirst = dwPos; dwFirst < dwPoints - 3; dwFirst++)
  1522. {
  1523. unsigned char b = pbBuffer [dwFirst];
  1524. // il faut �galement mettre � jour pcOffsets, sinon on engendre une incoh�rence
  1525. if ( (b == pbBuffer [dwFirst + 2])
  1526. && (abs (b - pbBuffer [dwFirst + 1]) < 5))
  1527. {
  1528. pbBuffer [dwFirst + 1] = b;
  1529. pcOffsets [dwFirst + 1] = 0;
  1530. }
  1531. else if ( (b == pbBuffer [dwFirst + 3])
  1532. && (abs (b - pbBuffer [dwFirst + 1]) < 5)
  1533. && (abs (b - pbBuffer [dwFirst + 2]) < 5))
  1534. {
  1535. pbBuffer [dwFirst + 1] = b;
  1536. pbBuffer [dwFirst + 2] = b;
  1537. pcOffsets [dwFirst + 1] = 0;
  1538. pcOffsets [dwFirst + 2] = 0;
  1539. }
  1540. }
  1541. // c) recherche d'une croissance (3 pixels de suite au moins : 2 variations de m�me sens)
  1542. if (LookForVariation (dwStart, pcOffsets, dwPoints, enumUp, dwPos))
  1543. {
  1544. m_diag = -3;
  1545. if (pbBuffer [paroi.m_slope [0].m_dwPos [1]] <= m_bDelta2 + pbBuffer [dwStart - 1])
  1546. {
  1547. m_diag = -4;
  1548. // Test Ajout test 1 180808
  1549. if ((m_versionTomtecAout08 && ((2 * pbBuffer [dwStart - 1])> m_bSeuil1)) || (!m_versionTomtecAout08))
  1550. {
  1551. // if ((2 * pbBuffer [dwStart - 1])> (2 * pbBuffer [paroi.m_slope [0].m_dwPos [1]]))
  1552. {
  1553. paroi.m_slope[1].m_dwPos[0] = dwPos;
  1554. paroi.m_slope[1].m_dwPos[1] = dwStart - 1;
  1555. paroi.m_slope[2].m_dwPos[1] = dwPos;
  1556. }
  1557. return (1);
  1558. }
  1559. }
  1560. if (m_versionTomtecAout08)
  1561. {
  1562. dwStart += 3;
  1563. // On fait 2 fois de suite la recherche d'une croissance 180808
  1564. // La premi�re croissance peut �tre une erreur
  1565. // d) recherche d'une seconde croissance (3 pixels de suite au moins : 2 variations de m�me sens)
  1566. if (LookForVariation (dwStart, pcOffsets, dwPoints, enumUp, dwPos))
  1567. {
  1568. m_diag = -5;
  1569. if (pbBuffer [paroi.m_slope [0].m_dwPos [1]] <= m_bDelta2 + pbBuffer [dwStart - 1])
  1570. {
  1571. m_diag = -6;
  1572. // Test Ajout test 1 180808
  1573. if ((2 * pbBuffer [dwStart - 1])> m_bSeuil1)
  1574. {
  1575. // if ((2 * pbBuffer [dwStart - 1])> (2 * pbBuffer [paroi.m_slope [0].m_dwPos [1]]))
  1576. {
  1577. paroi.m_slope[1].m_dwPos[0] = dwPos;
  1578. paroi.m_slope[1].m_dwPos[1] = dwStart - 1;
  1579. paroi.m_slope[2].m_dwPos[1] = dwPos;
  1580. }
  1581. return (1);
  1582. }
  1583. }
  1584. }
  1585. }
  1586. /*
  1587. // d) recherche d'une d�croissance (3 pixels de suite au moins : 2 variations de m�me sens)
  1588. // il faut que le maximal de la deuxi�me pente soit plus haut que le maximal de la premi�re
  1589. // (c'est un crit�re tr�s efficace pour �liminer de mauvaise mesures, en g�n�ral lorsque la
  1590. // "1�" paroi qui a �t� d�tect�e n'est pas la bonne)
  1591. if (LookForVariation (dwStart, pcOffsets, dwPoints, enumDown, dwPos))
  1592. {
  1593. // on cherche le d�but du plateau si on est dessus, le dernier point doit �tre la fin
  1594. // d'une croissance STRICTE
  1595. dwFirst = dwPos; // on veut conna�tre la taille du plateau
  1596. while (pbBuffer [dwPos] == pbBuffer [dwPos - 1])
  1597. dwPos--;
  1598. if ( (pbBuffer [paroi.m_dwPos [1]] + m_bDelta2 < pbBuffer [dwPos])
  1599. || ((dwFirst - dwPos >= 2) && (pbBuffer [dwPos] >= 240))
  1600. )
  1601. {
  1602. paroi.m_dwPos[3] = dwPos;
  1603. return (1);
  1604. }
  1605. }
  1606. */
  1607. }
  1608. }
  1609. }
  1610. }
  1611. return (0);
  1612. } // end of Measure
  1613. /*----------------------------------------------------------\
  1614. | LookForFirstPoint |
  1615. |-----------------------------------------------------------|
  1616. | DESCRIPTION : |
  1617. | Recherche du premier point caract�ristique de la paroi |
  1618. | Il m�rite � lui seul une fonction... |
  1619. |-----------------------------------------------------------|
  1620. | PARAMETRES : |
  1621. | dwStart : premier point � examine |
  1622. | dwMax : dernier point examinable |
  1623. | dwPos : o� stocker la position trouv�e |
  1624. | pbBuffer : ligne d'intensit� |
  1625. |-----------------------------------------------------------|
  1626. | RETOURNE : |
  1627. | un bool�en indiquant si la variation recherch�e a �t� |
  1628. | trouv�e |
  1629. \----------------------------------------------------------*/
  1630. bool CEIMBase::LookForFirstPoint
  1631. ( long &dwStart,
  1632. long dwMax,
  1633. long &dwPos,
  1634. unsigned char* pbBuffer
  1635. )
  1636. {
  1637. // r�gles de d�tection de la premi�re pente:
  1638. // 1. trois points doivent se se suivre avec une intensit� croissante
  1639. // 2. le dernier des points, doit avoir une intensit� �gal � m_bDelta1 + la moyenne des pr�c�dents
  1640. // 3. au moins trois points cons�cutifs doivent ensuite avoir une intensit� inf�rieur au premier sommet
  1641. //
  1642. // l'intensit� du premier point sert de rep�re
  1643. unsigned char bFirst = pbBuffer [1]; // intensit� du premier point
  1644. unsigned char* pb;
  1645. #ifndef TEST_FOR_FANTOME
  1646. dwStart = 2; // on commence � 2 pour avoir acc�s � -1 et -2
  1647. #endif
  1648. pb = &pbBuffer [dwStart];
  1649. while ( (dwStart < dwMax) &&
  1650. ( ( ( pb [ 0] - bFirst ) < m_bDelta1) // tant que le point courant n'est pas assez lumineux, on continue
  1651. || ( pb [-2] >= pb [-1] ) ) )
  1652. {
  1653. pb++, dwStart++;
  1654. }
  1655. if (dwStart >= dwMax)
  1656. {
  1657. return (false);
  1658. }
  1659. else
  1660. {
  1661. dwPos = dwStart - 1;
  1662. // on incr�mente dwStart jusqu'� une d�croissance STRICTE double
  1663. // une simple d�croissance est une irr�gularit� � ignorer
  1664. while ((dwStart < dwMax) && ((pb [1] >= pb [0]) || (pb [2] >= pb [0])))
  1665. {
  1666. pb++, dwStart++;
  1667. }
  1668. dwStart++; // il faut que l'on pointe sur le d�but de la d�croissance
  1669. if (dwStart >= dwMax)
  1670. {
  1671. return (false);
  1672. }
  1673. else
  1674. {
  1675. pb = &pbBuffer [dwPos];
  1676. // on cherche le premier point � m_bDelta1 du sommet
  1677. // on est certain de trouver un point (au pire dwStart)
  1678. // bFirst = BYTE (pbBuffer [dwStart - 1] - m_bDelta1); // dwStart pointe juste apr�s le sommet
  1679. // while (bFirst < pb [0]) // comparaison STRICTE
  1680. // pb--, dwPos--;
  1681. // on continue tant qu'il y a une d�croissance STRICTE (on autorise UNE irr�gularit� m�me apr�s lissage)
  1682. // sinon si que du noir, on arrive au d�but du segment!!
  1683. // le test sur m_bDelta1 emp�che fr�quemment la d�tection r�elle du d�but de la pente
  1684. while (dwPos && ((pb[0] > pb[-1]) || ((dwPos > 1) && (pb[0] > pb[-2]))))
  1685. {
  1686. pb--, dwPos--;
  1687. }
  1688. return (true);
  1689. }
  1690. }
  1691. } // fin de LookForFirstPoint
  1692. /*----------------------------------------------------------\
  1693. | CEIM::LookForVariation |
  1694. |-----------------------------------------------------------|
  1695. | DESCRIPTION : |
  1696. | Recherche dans le buffer une variation de densit� dans le|
  1697. | sens donn�, et d�place le pointeur tant que cette |
  1698. | variation est maintenue |
  1699. |-----------------------------------------------------------|
  1700. | PARAMETRES : |
  1701. | dwStart : premier point � examine |
  1702. | pcOffsets : tableau de variation de densit�s |
  1703. | dwMax : dernier point examinable |
  1704. | dir : sens de variation recherch� |
  1705. | dwPos : o� stocker la position trouv�e |
  1706. |-----------------------------------------------------------|
  1707. | RETOURNE : |
  1708. | un bool�en indiquant si la variation recherch�e a �t� |
  1709. | trouv�e |
  1710. \----------------------------------------------------------*/
  1711. bool CEIMBase::LookForVariation (long &dwStart, char *pcOffsets, long dwMax, enumDirection dir, long &dwPos)
  1712. {
  1713. char c1, c2;
  1714. assert (dwStart); // le tableau de variation d�bute � 1
  1715. while (dwStart < dwMax)
  1716. {
  1717. c1 = pcOffsets [dwStart];
  1718. c2 = pcOffsets [dwStart + 1];
  1719. if (c1 && (c1 == c2)) // il faut une variation (c1 != 0) <=> (c2 != 0)
  1720. {
  1721. if (dir == enumUp)
  1722. {
  1723. if (c1 < 0)
  1724. {
  1725. return (false); // Sens inverse de celui recherch�
  1726. }
  1727. else
  1728. {
  1729. dwPos = dwStart - 1;
  1730. dwStart++;
  1731. do
  1732. {
  1733. dwStart++;
  1734. // } while ((dwStart < dwMax) && (pcOffsets [dwStart] >= 0));
  1735. } while ((dwStart < dwMax) && (pcOffsets [dwStart] > 0));
  1736. return (true);
  1737. }
  1738. }
  1739. else
  1740. {
  1741. if (c1 > 0)
  1742. {
  1743. return (false); // croissance, au lieu de d�croissance
  1744. }
  1745. else
  1746. {
  1747. dwPos = dwStart - 1;
  1748. dwStart++;
  1749. do
  1750. {
  1751. dwStart++;
  1752. } while ((dwStart < dwMax) && (pcOffsets [dwStart] <= 0));
  1753. return (true);
  1754. }
  1755. }
  1756. }
  1757. dwStart++;
  1758. }
  1759. return (false);
  1760. } // fin de LookForVariation
  1761. /*----------------------------------------------------------\
  1762. | Update |
  1763. |-----------------------------------------------------------|
  1764. | DESCRIPTION : |
  1765. | Mesures des parois reconnues et statistiques |
  1766. |-----------------------------------------------------------|
  1767. | RETOURNE : |
  1768. | VRAI si au moins un profil a �t� reconnu |
  1769. \----------------------------------------------------------*/
  1770. bool CEIMBase::Update (CEIMResult *m_res)
  1771. {
  1772. // ATTENTION, il se peut qu'aucun profil n'ait �t� d�tect�
  1773. // [JAK - 24/6/2002] no histogram window
  1774. //initialisation
  1775. GraphMeanInit();
  1776. m_arVariance.clear();
  1777. m_arVarianceAA.clear();
  1778. m_arVarianceII.clear();
  1779. m_arVarianceINT.clear();
  1780. m_dwValidPoints = 0;
  1781. m_dblDistance = 0.0;
  1782. m_dblEIMMin =
  1783. m_dblEIMMean =
  1784. m_dblEIMMax =
  1785. m_dblINTMin =
  1786. m_dblINTMean =
  1787. m_dblINTMax =
  1788. m_dblEIMdMean =
  1789. m_dblINTdMean =
  1790. m_dblMEDdMean =
  1791. m_dblIAd =
  1792. m_dblDiaAAMin =
  1793. m_dblDiaAAMean =
  1794. m_dblDiaAAMax =
  1795. m_dblDiaIIMin =
  1796. m_dblDiaIIMean =
  1797. m_dblDiaIIMax = 0.0;
  1798. if (m_pMeasures == NULL)
  1799. return (false);
  1800. else
  1801. {
  1802. CEIMInfo *pInfo = &m_pMeasures [0];
  1803. long dw;
  1804. double dblMeanEIM, // valeur moyenne de l'EIM lors de la 1� phase
  1805. dblMeanINT,
  1806. dblMeanEIMd,
  1807. dblMeanINTd,
  1808. dblMeanMEDd,
  1809. dblGapEIM,
  1810. dblMeanQI,
  1811. dblMeanDia, // valeur moyenne du diam�tre lors de la 1� phase
  1812. dblGapDia,
  1813. dblMeanDist, // distance moyenne du 1� milieu au trait utilisateur
  1814. dblStdDist,
  1815. dblGapDist,
  1816. dblII; // diam�tre intima/intima
  1817. // dblGapQI;
  1818. // la premi�re �tape consiste:
  1819. // - � calculer la valeur de l'EIM � partir des points d�tect�s
  1820. // - � calculer la moyenne des mesures afin d'�liminer ensuite
  1821. // celles qui s'�cartent trop de cette valeur moyenne.
  1822. dblGapEIM = 0;
  1823. dblGapDist = 0;
  1824. dblGapDia = 0;
  1825. dblII = 0;
  1826. dblMeanEIM = 0;
  1827. dblMeanINT = 0;
  1828. dblMeanEIMd = 0;
  1829. dblMeanINTd = 0;
  1830. dblMeanMEDd = 0;
  1831. dblMeanDia = 0;
  1832. dblMeanDist = 0;
  1833. dblStdDist = 0.0;
  1834. dblMeanQI = 0.0;
  1835. for (dw = 0; dw < m_dwPoints; dw++)
  1836. {
  1837. if (pInfo->m_fValid) // le profil a �t� rep�r�
  1838. {
  1839. dblMeanEIM += pInfo->m_dblEIM;
  1840. dblMeanINT += pInfo->m_dblINT;//PJT
  1841. dblMeanEIMd += pInfo->m_dblEIMd;
  1842. dblMeanINTd += pInfo->m_dblINTd;
  1843. dblMeanMEDd += pInfo->m_dblMEDd;
  1844. dblMeanDia += pInfo->m_dblDia;
  1845. dblMeanDist += pInfo->m_dblDist;
  1846. dblStdDist += pInfo->m_dblDist * pInfo->m_dblDist;
  1847. dblMeanQI += pInfo->m_dblQI;
  1848. m_dwValidPoints++; // requis pour obtenir la moyenne
  1849. }
  1850. pInfo++;
  1851. }
  1852. if (m_dwValidPoints == 0)
  1853. {
  1854. m_uErrorID = IDS_EIM_FAILED;//BUG ICI //[JAK - 09/09/02]
  1855. return (false); // aucune mesure valide
  1856. }
  1857. else
  1858. {
  1859. try// [JAK - 5/7/2002]
  1860. {
  1861. // calcul des moyennes
  1862. dblMeanEIM /= m_dwValidPoints;
  1863. dblMeanDia /= m_dwValidPoints;
  1864. dblMeanDist /= m_dwValidPoints;
  1865. dblStdDist /= m_dwValidPoints;
  1866. dblMeanINT /= m_dwValidPoints;//PJT
  1867. dblMeanEIMd /= m_dwValidPoints;
  1868. dblMeanINTd /= m_dwValidPoints;
  1869. dblMeanMEDd /= m_dwValidPoints;
  1870. dblMeanQI /= m_dwValidPoints;
  1871. // l'�cart autoris� est �gal � 25% de la moyenne 23/02/99 Touboul
  1872. // l'�cart autoris� est �gal � 50% de la moyenne 06/05/99 Touboul
  1873. // l'�cart autoris� est �gal � 35% de la moyenne 19/07/99 Touboul
  1874. // l'�cart autoris� est �gal � 10% de la moyenne 19/07/05 Touboul
  1875. if (m_versionTomtecAout08)
  1876. {
  1877. dblGapEIM = dblMeanEIM *.25;//.35 20/10/05 PJT // 0.2 180808
  1878. dblGapDia = dblMeanDia *.02;//.04 20/10/05 PJT
  1879. dblGapDist = dblMeanDist *.15;//.25 20/10/05 PJT // 0.2 180808
  1880. }
  1881. else
  1882. {
  1883. dblGapEIM = dblMeanEIM *.20;
  1884. dblGapDia = dblMeanDia *.02;
  1885. dblGapDist = dblMeanDist *.20;
  1886. }
  1887. // dblGapDist = sqrt(dblStdDist - dblMeanDist * dblMeanDist);// 20/12/06 FP
  1888. pInfo = &m_pMeasures[0];
  1889. // exclusion de tous les points hors normes
  1890. for (dw = 0; dw < m_dwPoints; dw++)
  1891. {
  1892. if ( pInfo->m_fValid
  1893. // on exclut tous les point qui s'�cartent trop de la moyenne
  1894. && ( (fabs (pInfo->m_dblEIM - dblMeanEIM ) > dblGapEIM) // EIM incoh�rent
  1895. || (fabs (pInfo->m_dblDist - dblMeanDist) > dblGapDist) // ou distance � l'axe incoh�rente
  1896. || (m_fDiameter && (fabs (pInfo->m_dblDia - dblMeanDia) > dblGapDia)) // ou diam�tre incoh�rent
  1897. || (fabs (pInfo->m_dblQI)> 0.3) // IQ < 50% Touboul
  1898. )
  1899. )
  1900. {
  1901. pInfo->m_fThrownOut = true; // par d�faut � FALSE gr�ce au memset (on laisse valide pour affichage palette)
  1902. pInfo->m_fValid = false;
  1903. m_dwValidPoints--;
  1904. }
  1905. pInfo++;
  1906. }
  1907. // il se peut que TOUS les points soient � + de 20% de la moyenne
  1908. // (par exemple deux lignes tr�s �loign�es)
  1909. if (m_dwValidPoints == 0)
  1910. {
  1911. m_uErrorID = IDS_EIM_FAILED;
  1912. return (false); // aucune mesure valide
  1913. }
  1914. else
  1915. {
  1916. if (m_fDiameter) // Calcul de la moyenne des diam�tres trouv�s
  1917. {
  1918. std::vector<double> arrayAA, arrayII;//il s'agit en faite d'une duplication de m_arVarianceAA et m_arVarianceII
  1919. double dblMeanAA = 0.0;
  1920. double dblMeanII = 0.0;
  1921. double dblVarianceAA = 0.0;
  1922. double dblVarianceII = 0.0;
  1923. // recherche du premier profil valide
  1924. pInfo = &m_pMeasures [0];
  1925. for (dw = 0; !pInfo->m_fValid; dw++)
  1926. {
  1927. pInfo++;
  1928. }
  1929. // on est certain qu'un pInfo valide va �tre trouv�
  1930. //----- resultat d'un calcul de diametre [JAK - 13/1/2003]
  1931. m_dblDiaAAMin = m_dblDiaAAMean = m_dblDiaAAMax = pInfo->m_dblDia;
  1932. m_dblDiaIIMin = m_dblDiaIIMean = m_dblDiaIIMax = pInfo->m_dblDia - 2 * pInfo->m_dblEIM;
  1933. arrayII.push_back(g_pCurrentScale->Distance(m_dblDiaIIMean));
  1934. arrayAA.push_back(g_pCurrentScale->Distance(m_dblDiaAAMean));
  1935. GraphMeanAddMeasure(true, pInfo->m_dblDia);
  1936. m_arVarianceAA.push_back (g_pCurrentScale->Distance (pInfo->m_dblDia));
  1937. m_arVarianceII.push_back (g_pCurrentScale->Distance (pInfo->m_dblDia- 2 * pInfo->m_dblEIM));
  1938. dblMeanAA = g_pCurrentScale->Distance (pInfo->m_dblDia);
  1939. dblMeanII = g_pCurrentScale->Distance (pInfo->m_dblDia - 2 * pInfo->m_dblEIM);
  1940. dw++,pInfo++;
  1941. while (dw < m_dwPoints)
  1942. {
  1943. if (pInfo->m_fValid)
  1944. {
  1945. m_dblDiaAAMean += pInfo->m_dblDia;
  1946. if (pInfo->m_dblDia < m_dblDiaAAMin) m_dblDiaAAMin = pInfo->m_dblDia;
  1947. if (pInfo->m_dblDia > m_dblDiaAAMax) m_dblDiaAAMax = pInfo->m_dblDia;
  1948. dblII = pInfo->m_dblDia - 2 * pInfo->m_dblEIM;
  1949. m_dblDiaIIMean += dblII;
  1950. if (dblII < m_dblDiaIIMin) m_dblDiaIIMin = dblII;
  1951. if (dblII > m_dblDiaIIMax) m_dblDiaIIMax = dblII;
  1952. // [JAK - 24/6/2002] no histogram window
  1953. GraphMeanAddMeasure (true, pInfo->m_dblDia);
  1954. arrayAA.push_back(g_pCurrentScale->Distance(pInfo->m_dblDia));
  1955. arrayII.push_back(g_pCurrentScale->Distance(dblII));
  1956. m_arVarianceAA.push_back (g_pCurrentScale->Distance (pInfo->m_dblDia));
  1957. m_arVarianceII.push_back (g_pCurrentScale->Distance (dblII));
  1958. dblMeanAA += g_pCurrentScale->Distance (pInfo->m_dblDia);
  1959. dblMeanII += g_pCurrentScale->Distance (dblII);
  1960. }
  1961. dw++;
  1962. pInfo++;
  1963. }
  1964. /* if (m_vUser.Length () < QI_MIN)
  1965. {
  1966. CString msg; msg.Format(MyLoadString(IDS_EIM_QI_0), QI_MIN);
  1967. CMessage::Info (msg);
  1968. m_dblQI = 0.;
  1969. }
  1970. else*/
  1971. m_dblQI = double (m_dwValidPoints) / m_dwPoints;
  1972. // calcul de la variance
  1973. dblMeanAA /= (double)m_arVarianceAA.size ();
  1974. dblMeanII /= (double)m_arVarianceII.size ();
  1975. dblVarianceAA = 0.0;
  1976. dblVarianceII = 0.0;
  1977. for (unsigned int i = 0; i < m_arVarianceAA.size (); i++)
  1978. {
  1979. dblVarianceAA += (m_arVarianceAA [i] - dblMeanAA) * (m_arVarianceAA [i] - dblMeanAA);
  1980. dblVarianceII += (m_arVarianceII [i] - dblMeanII) * (m_arVarianceII [i] - dblMeanII);
  1981. }
  1982. dblVarianceAA /= (double)m_arVarianceAA.size ();
  1983. dblVarianceII /= (double)m_arVarianceII.size ();
  1984. m_dblDistance = m_vUser.Norm (g_pCurrentScale);
  1985. m_dblDiaAAMean /= (double)m_dwValidPoints;
  1986. m_dblDiaIIMean /= (double)m_dwValidPoints;
  1987. m_dblDiaAAMin = g_pCurrentScale->Distance (m_dblDiaAAMin);
  1988. m_dblDiaAAMean = g_pCurrentScale->Distance (m_dblDiaAAMean);
  1989. m_dblDiaAAMax = g_pCurrentScale->Distance (m_dblDiaAAMax);
  1990. m_dblDiaIIMin = g_pCurrentScale->Distance (m_dblDiaIIMin);
  1991. m_dblDiaIIMean = g_pCurrentScale->Distance (m_dblDiaIIMean);
  1992. m_dblDiaIIMax = g_pCurrentScale->Distance (m_dblDiaIIMax);
  1993. assert(arrayAA.size() == (size_t)m_dwValidPoints);
  1994. assert(arrayII.size() == (size_t)m_dwValidPoints);
  1995. // double diam = CMeanEstimate::GetMeanEstimate(&arrayAA);
  1996. // m_dblDiaAAMean = (CMeanEstimate::IsANumber(diam)? diam : -1);
  1997. m_dblDiaAAMean = CMeanEstimate::GetMeanEstimate(&arrayAA);
  1998. m_dblDiaIIMean = CMeanEstimate::GetMeanEstimate(&arrayII);
  1999. m_dblVarianceAA = dblVarianceAA;
  2000. m_dblVarianceII = dblVarianceII;
  2001. PrintDiameter();
  2002. if (!CMeanEstimate::IsANumber(m_dblDiaAAMean))
  2003. { //if is is infinite because of the estimate
  2004. return false;
  2005. }
  2006. }
  2007. else // de l'EIM
  2008. {
  2009. double dblMean = 0.0, dblMeanINT = 0.0;
  2010. // double dblMeanEIMd = 0.0, dblMeanINTd = 0.0, dblMeanMEDd = 0.0;
  2011. double dblVariance = 0.0, dblVarianceINT = 0.0;
  2012. imt::Point invalidPoint, tmpPt;
  2013. invalidPoint.x = -1;
  2014. invalidPoint.y = -1;
  2015. if ( m_res )
  2016. {
  2017. m_res->result->numberOfPoints = m_dwPoints;
  2018. m_res->allocate_vectors( m_dwPoints );
  2019. }
  2020. // recherche du premier profil valide
  2021. pInfo = &m_pMeasures [0];
  2022. for (dw = 0; !pInfo->m_fValid; dw++)
  2023. {
  2024. if ( m_res )
  2025. {
  2026. m_res->result->vect_adventitia[dw] = invalidPoint;
  2027. m_res->result->vect_media[dw] = invalidPoint;
  2028. m_res->result->vect_intima[dw] = invalidPoint;
  2029. }
  2030. pInfo++;
  2031. }
  2032. // on est certain qu'un pInfo valide va �tre trouv�
  2033. m_dblEIMMin = m_dblEIMMean = m_dblEIMMax = pInfo->m_dblEIM;
  2034. m_dblINTMin = m_dblINTMean = m_dblINTMax = pInfo->m_dblINT;
  2035. m_dblEIMdMean = pInfo->m_dblEIMd;
  2036. m_dblINTdMean = pInfo->m_dblINTd;
  2037. m_dblMEDdMean = pInfo->m_dblMEDd;
  2038. // [JAK - 24/6/2002] no histogram window
  2039. GraphMeanAddMeasure (true, pInfo->m_dblEIM);
  2040. m_arVariance.push_back (g_pCurrentScale->Distance (pInfo->m_dblEIM));
  2041. m_arVarianceINT.push_back (g_pCurrentScale->Distance (pInfo->m_dblINT));
  2042. dblMean = g_pCurrentScale->Distance (pInfo->m_dblEIM);
  2043. dblMeanINT = g_pCurrentScale->Distance (pInfo->m_dblINT);
  2044. if ( m_res )
  2045. {
  2046. tmpPt.x = pInfo->m_Paroi[0].m_slope[1].m_ptDraw.x;
  2047. tmpPt.y = pInfo->m_Paroi[0].m_slope[1].m_ptDraw.y;
  2048. m_res->result->vect_adventitia[dw] = tmpPt;
  2049. tmpPt.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  2050. tmpPt.y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  2051. m_res->result->vect_media[dw] = tmpPt;
  2052. tmpPt.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  2053. tmpPt.y = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y;
  2054. m_res->result->vect_intima[dw] = tmpPt;
  2055. }
  2056. dw++,pInfo++;
  2057. while (dw < m_dwPoints)
  2058. {
  2059. if (pInfo->m_fValid)
  2060. {
  2061. m_dblEIMMean += pInfo->m_dblEIM;
  2062. if (pInfo->m_dblEIM < m_dblEIMMin) m_dblEIMMin = pInfo->m_dblEIM;
  2063. if (pInfo->m_dblEIM > m_dblEIMMax) m_dblEIMMax = pInfo->m_dblEIM;
  2064. m_dblINTMean += pInfo->m_dblINT;
  2065. if (pInfo->m_dblINT < m_dblINTMin) m_dblINTMin = pInfo->m_dblINT;
  2066. if (pInfo->m_dblINT > m_dblINTMax) m_dblINTMax = pInfo->m_dblINT;
  2067. m_dblEIMdMean += pInfo->m_dblEIMd;
  2068. m_dblINTdMean += pInfo->m_dblINTd;
  2069. m_dblMEDdMean += pInfo->m_dblMEDd;
  2070. // [JAK - 24/6/2002] no histogram window
  2071. GraphMeanAddMeasure (true, pInfo->m_dblEIM);
  2072. m_arVariance.push_back (g_pCurrentScale->Distance (pInfo->m_dblEIM));
  2073. m_arVarianceINT.push_back (g_pCurrentScale->Distance (pInfo->m_dblINT));
  2074. dblMean += g_pCurrentScale->Distance (pInfo->m_dblEIM);
  2075. dblMeanINT += g_pCurrentScale->Distance (pInfo->m_dblINT);
  2076. if ( m_res )
  2077. {
  2078. tmpPt.x = pInfo->m_Paroi[0].m_slope[1].m_ptDraw.x;
  2079. tmpPt.y = pInfo->m_Paroi[0].m_slope[1].m_ptDraw.y;
  2080. m_res->result->vect_adventitia[dw] = tmpPt;
  2081. tmpPt.x = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.x;
  2082. tmpPt.y = pInfo->m_Paroi[0].m_slope[2].m_ptDraw.y;
  2083. m_res->result->vect_media[dw] = tmpPt;
  2084. tmpPt.x = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x;
  2085. tmpPt.y = pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y;
  2086. m_res->result->vect_intima[dw] = tmpPt;
  2087. }
  2088. }
  2089. else
  2090. {
  2091. if ( m_res )
  2092. {
  2093. m_res->result->vect_adventitia[dw] = invalidPoint;
  2094. m_res->result->vect_media[dw] = invalidPoint;
  2095. m_res->result->vect_intima[dw] = invalidPoint;
  2096. }
  2097. }
  2098. dw++;
  2099. pInfo++;
  2100. }
  2101. if (m_vUser.Length () < QI_MIN)
  2102. {
  2103. PrintErrorQIMin();
  2104. m_dblQI = 0.;
  2105. }
  2106. else
  2107. {
  2108. m_dblQI = double (m_dwValidPoints) / m_dwPoints;
  2109. }
  2110. // calcul de la variance
  2111. dblMean /= (double)m_arVariance.size ();
  2112. dblVariance = 0.0;
  2113. dblMeanINT /= (double)m_arVarianceINT.size ();
  2114. dblVarianceINT = 0.0;
  2115. unsigned int i;
  2116. for (i = 0; i < m_arVariance.size (); i++)
  2117. dblVariance += (m_arVariance [i] - dblMean) * (m_arVariance [i] - dblMean);
  2118. dblVariance /= (double)m_arVariance.size ();
  2119. for (i = 0; i < m_arVarianceINT.size (); i++)
  2120. dblVarianceINT += (m_arVarianceINT [i] - dblMeanINT) *
  2121. (m_arVarianceINT [i] - dblMeanINT);
  2122. dblVarianceINT /= (double)m_arVarianceINT.size ();
  2123. m_dblDistance = m_vUser.Norm (g_pCurrentScale);
  2124. // calcul des valeurs moyennes et mise � l'�chelle des normes
  2125. m_dblEIMMean /= (double)m_dwValidPoints;
  2126. m_dblEIMMin = g_pCurrentScale->Distance (m_dblEIMMin);
  2127. m_dblEIMMean = g_pCurrentScale->Distance (m_dblEIMMean);
  2128. m_dblEIMMax = g_pCurrentScale->Distance (m_dblEIMMax);
  2129. m_dblINTMean /= (double)m_dwValidPoints;
  2130. m_dblINTMin = g_pCurrentScale->Distance (m_dblINTMin);
  2131. m_dblINTMean = g_pCurrentScale->Distance (m_dblINTMean);
  2132. m_dblINTMax = g_pCurrentScale->Distance (m_dblINTMax);
  2133. m_dblIA = m_dblINTMean / m_dblEIMMean;
  2134. m_dblEIMdMean /= (double)m_dwValidPoints;
  2135. m_dblINTdMean /= (double)m_dwValidPoints;
  2136. m_dblMEDdMean /= (double)m_dwValidPoints;
  2137. m_dblIAd = m_dblINTdMean / m_dblEIMdMean;
  2138. //#ifdef VERSION_SHOW_VARIANCE // [JAK - 17/6/2002]
  2139. m_dblVariance = dblVariance;
  2140. //#endif
  2141. // [JAK - 4/7/2002] IDS_EIM_RESULT4 = \tE .I.M.\nI.Q.: \t%.2f\nMaximale : \t%.3f mm\nMoyenne : \t%.3f mm\nEcart Type : \t%.3f mm\nMesures Valides :\td%
  2142. PrintResult();
  2143. if ( m_res )
  2144. {
  2145. m_res->result->imt_max = m_dblEIMMax;
  2146. m_res->result->imt_mean = m_dblEIMMean;
  2147. m_res->result->imt_standardDeviation = sqrt (dblVariance);
  2148. m_res->result->intima_mean = m_dblINTMean;
  2149. m_res->result->media_mean = m_dblEIMMean - m_dblINTMean;
  2150. m_res->result->qualityIndex = m_dblQI;
  2151. }
  2152. }
  2153. return (true);
  2154. }
  2155. }catch(...){ // [JAK - 5/7/2002]
  2156. assert(0);
  2157. // not very clean to catch any exception, but it is at least efficient
  2158. //TODO change the "catch(...)" for something more precise like "catch(Float Divide by Zero)"
  2159. m_uErrorID = IDS_EIM_FAILED;
  2160. return (false); // aucune mesure valide
  2161. }
  2162. }
  2163. }
  2164. } // end of Update
  2165. /*----------------------------------------------------------\
  2166. | ComputeEIM |
  2167. |-----------------------------------------------------------|
  2168. | DESCRIPTION : |
  2169. | calcule l'�paisseur EIM et la distance au vecteur trac� |
  2170. | par l'utilisateur � l'aide points d�tect�s |
  2171. |-----------------------------------------------------------|
  2172. | PARAMETRES : |
  2173. | pInfo : une info sur un segment de paroi |
  2174. \----------------------------------------------------------*/
  2175. void CEIMBase::ComputeEIM (CEIMInfo *pInfo)
  2176. {
  2177. pInfo->m_fValid = true;
  2178. // en approximation, m_ptMiddle [0] suffit largement pour la distance, qui n'intervient
  2179. // dans la mesure que pour �carter les points trop �loign�s de la moyenne
  2180. pInfo->m_dblDist = CVector (pInfo->m_Paroi [0].m_slope [0].m_ptMiddle, pInfo->m_Paroi [0].m_vMeasure [0]).Norm ();
  2181. pInfo->m_dblEIM = CVector (pInfo->m_Paroi [0].m_slope [0].m_ptMiddle, pInfo->m_Paroi [0].m_slope [1].m_ptMiddle).Norm ()
  2182. - pInfo->m_Paroi [0].m_slope [0].m_dblMiddle
  2183. + pInfo->m_Paroi [0].m_slope [1].m_dblMiddle;
  2184. pInfo->m_dblINT = CVector (pInfo->m_Paroi [0].m_slope [0].m_ptMiddle, pInfo->m_Paroi [0].m_slope [2].m_ptMiddle).Norm ()
  2185. - pInfo->m_Paroi [0].m_slope [0].m_dblMiddle
  2186. + pInfo->m_Paroi [0].m_slope [2].m_dblMiddle;
  2187. // dans le cas de la paroi, on additionne les deux �carts, car la paroi du bas est mesur�
  2188. // dans le sens oppos� � la paroi du haut
  2189. if (m_fDiameter)
  2190. {
  2191. pInfo->m_dblDia = CVector (pInfo->m_Paroi [0].m_slope [1].m_ptMiddle, pInfo->m_Paroi [1].m_slope [1].m_ptMiddle).Norm ()
  2192. + pInfo->m_Paroi [0].m_slope [1].m_dblMiddle
  2193. + pInfo->m_Paroi [1].m_slope [1].m_dblMiddle;
  2194. }
  2195. else // Calcul des moyennes des intensites entre les differents points
  2196. {
  2197. pInfo->m_dblEIMd = pInfo->m_dblINTd = pInfo->m_dblMEDd = 0.0;
  2198. long dw, nb=0, nbTot=0;
  2199. for ( dw=pInfo->m_Paroi[0].m_slope[0].m_dwMiddle; dw<pInfo->m_Paroi[0].m_slope[2].m_dwMiddle; dw++ )
  2200. {
  2201. nb++;
  2202. nbTot++;
  2203. pInfo->m_dblEIMd += m_bBuffer[dw];
  2204. pInfo->m_dblINTd += m_bBuffer[dw];
  2205. }
  2206. if (nb != 0 ) // Contre la division par 0
  2207. {
  2208. pInfo->m_dblINTd /= (double) nb;
  2209. }
  2210. else
  2211. {
  2212. pInfo->m_dblINTd = 0;
  2213. }
  2214. nb = 0;
  2215. for ( dw=pInfo->m_Paroi[0].m_slope[2].m_dwMiddle; dw<pInfo->m_Paroi[0].m_slope[1].m_dwMiddle; dw++ )
  2216. {
  2217. nb++;
  2218. nbTot++;
  2219. pInfo->m_dblEIMd += m_bBuffer[dw];
  2220. pInfo->m_dblMEDd += m_bBuffer[dw];
  2221. }
  2222. if (nb != 0) // Contre la division par 0
  2223. {
  2224. pInfo->m_dblMEDd /= (double) nb;
  2225. }
  2226. else
  2227. {
  2228. pInfo->m_dblMEDd = 0;
  2229. }
  2230. if (nbTot != 0) // Contre la division par 0
  2231. {
  2232. pInfo->m_dblEIMd /= (double) nbTot;
  2233. }
  2234. else
  2235. {
  2236. pInfo->m_dblEIMd = 0;
  2237. }
  2238. }
  2239. } // fin de ComputeEIM
  2240. /*----------------------------------------------------------\
  2241. | Direction |
  2242. |-----------------------------------------------------------|
  2243. | DESCRIPTION : |
  2244. | Retourne la direction de la droite approxim�e constitu�e |
  2245. | d'apr�s l'ensemble des points mesur�s! |
  2246. \----------------------------------------------------------*/
  2247. double CEIMBase::Direction()
  2248. {
  2249. double r = 0;
  2250. double x = 0, y = 0;
  2251. Point LastPoint( 0, 0 );
  2252. double Valide = 0;
  2253. double sx, sx2, sy, sy2;
  2254. int nbPoints;
  2255. double xmin, xmax, ymin, ymax;
  2256. double moyx, moyy, stdx, stdy;
  2257. if (m_pMeasures)
  2258. {
  2259. sx = sx2 = sy = sy2 = 0.0;
  2260. nbPoints = 0;
  2261. // Calcul de la somme des x et des y et de la somme des x2 et des y2
  2262. CEIMInfo *pInfo = &m_pMeasures[0];
  2263. for (long dw = 0; dw < m_dwPoints; dw++)
  2264. {
  2265. if (pInfo->m_fValid)
  2266. {
  2267. if (dw)
  2268. {
  2269. x = (pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x - LastPoint.x);
  2270. y = (pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y - LastPoint.y);
  2271. if (x)
  2272. {
  2273. sx += x;
  2274. sx2 += (x * x);
  2275. sy += y;
  2276. sy2 += (y * y);
  2277. nbPoints++;
  2278. }
  2279. }
  2280. LastPoint = pInfo->m_Paroi[0].m_slope[0].m_ptDraw;
  2281. }
  2282. pInfo++;
  2283. }
  2284. // Calcul des moyennes et des �carts types
  2285. if (nbPoints != 0)
  2286. {
  2287. moyx = sx / (double) nbPoints;
  2288. moyy = sy / (double) nbPoints;
  2289. stdx = sqrt( (sx2 / (double) nbPoints) - sx * sx);
  2290. stdy = sqrt( (sy2 / (double) nbPoints) - sy * sy);
  2291. xmin = moyx - 2 * stdx;
  2292. xmax = moyx + 2 * stdx;
  2293. ymin = moyy - 2 * stdy;
  2294. ymax = moyy + 2 * stdy;
  2295. }
  2296. pInfo = &m_pMeasures[0];
  2297. for (long dw = 0; dw < m_dwPoints; dw++)
  2298. {
  2299. if (pInfo->m_fValid)
  2300. {
  2301. if (dw)
  2302. {
  2303. x = (pInfo->m_Paroi[0].m_slope[0].m_ptDraw.x - LastPoint.x);
  2304. y = (pInfo->m_Paroi[0].m_slope[0].m_ptDraw.y - LastPoint.y);
  2305. if (x)
  2306. {
  2307. // if ((x >= xmin) && (x <= xmax) && (y >= ymin) && (y <= ymax))
  2308. {
  2309. r += y / x;
  2310. Valide++;
  2311. }
  2312. }
  2313. }
  2314. LastPoint = pInfo->m_Paroi[0].m_slope [0].m_ptDraw;
  2315. }
  2316. pInfo++;
  2317. }
  2318. }
  2319. if (Valide < 20) return 0; // Nombre de points valides insuffisants
  2320. Point PtDirect(100, (int) (100.0 * r / Valide));
  2321. PtDirect.Offset(m_vUser.StartPoint());
  2322. if ( (m_vUser.Angle(PtDirect) > 20) && (m_vUser.Angle(PtDirect) < 160) ) return 0;
  2323. return (r / Valide);
  2324. }
  2325. unsigned int CEIMBase::GetErrorID(void)
  2326. {
  2327. return m_uErrorID;
  2328. }