EIMBase.cpp 82 KB

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