EIMBase.cpp 81 KB

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