VinnoImageData.cs 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Text;
  5. namespace Tools
  6. {
  7. internal enum OperationMode
  8. {
  9. Open,
  10. Create
  11. }
  12. public class VinnoStreamReader
  13. {
  14. private readonly Stream _stream;
  15. public VinnoStreamReader(Stream stream)
  16. {
  17. _stream = stream;
  18. }
  19. /// <summary>
  20. /// Read string from stream.
  21. /// </summary>
  22. /// <returns></returns>
  23. public string ReadString()
  24. {
  25. var dataLength = ReadInt();
  26. var data = new byte[dataLength];
  27. _stream.Read(data, 0, dataLength);
  28. return Encoding.Unicode.GetString(data, 0, data.Length);
  29. }
  30. /// <summary>
  31. /// Read a int32 value from the stream.
  32. /// </summary>
  33. /// <returns></returns>
  34. public int ReadInt()
  35. {
  36. var data = new byte[sizeof(int)];
  37. _stream.Read(data, 0, sizeof(int));
  38. return BitConverter.ToInt32(data, 0);
  39. }
  40. /// <summary>
  41. /// Read a short value from the stream.
  42. /// </summary>
  43. /// <returns></returns>
  44. public short ReadShort()
  45. {
  46. var data = new byte[sizeof(short)];
  47. _stream.Read(data, 0, sizeof(short));
  48. return BitConverter.ToInt16(data, 0);
  49. }
  50. /// <summary>
  51. /// Read a Int64 value from the stream.
  52. /// </summary>
  53. /// <returns></returns>
  54. public long ReadLong()
  55. {
  56. var data = new byte[sizeof(long)];
  57. _stream.Read(data, 0, sizeof(long));
  58. return BitConverter.ToInt64(data, 0);
  59. }
  60. /// <summary>
  61. /// Read a float value from the stream.
  62. /// </summary>
  63. /// <returns></returns>
  64. public float ReadFloat()
  65. {
  66. var data = new byte[sizeof(float)];
  67. _stream.Read(data, 0, sizeof(float));
  68. return BitConverter.ToSingle(data, 0);
  69. }
  70. /// <summary>
  71. /// Read a double value from the stream.
  72. /// </summary>
  73. /// <returns></returns>
  74. public double ReadDouble()
  75. {
  76. var data = new byte[sizeof(double)];
  77. _stream.Read(data, 0, sizeof(double));
  78. return BitConverter.ToDouble(data, 0);
  79. }
  80. /// <summary>
  81. /// Read a bool value from the stream.
  82. /// </summary>
  83. /// <returns></returns>
  84. public bool ReadBool()
  85. {
  86. var data = new byte[sizeof(bool)];
  87. _stream.Read(data, 0, sizeof(bool));
  88. return BitConverter.ToBoolean(data, 0);
  89. }
  90. /// <summary>
  91. /// Read a byte value from the stream.
  92. /// </summary>
  93. /// <returns></returns>
  94. public byte ReadByte()
  95. {
  96. return (byte)(_stream.ReadByte());
  97. }
  98. /// <summary>
  99. /// Read a byte array from the stream.
  100. /// </summary>
  101. /// <returns></returns>
  102. public byte[] ReadBytes()
  103. {
  104. var size = ReadInt();
  105. var data = new byte[size];
  106. _stream.Read(data, 0, size);
  107. return data;
  108. }
  109. public long[] ReadLongs()
  110. {
  111. var data = ReadBytes();
  112. var result = new long[data.Length / sizeof(long)];
  113. Buffer.BlockCopy(data, 0, result, 0, data.Length);
  114. return result;
  115. }
  116. }
  117. public class VinnoStreamWriter
  118. {
  119. private readonly Stream _stream;
  120. public VinnoStreamWriter(Stream stream)
  121. {
  122. _stream = stream;
  123. }
  124. /// <summary>
  125. /// Write a string to stream.
  126. /// </summary>
  127. /// <param name="value"></param>
  128. public void WriteString(string value)
  129. {
  130. var data = Encoding.Unicode.GetBytes(value);
  131. WriteInt(data.Length);
  132. _stream.Write(data, 0, data.Length);
  133. }
  134. /// <summary>
  135. /// Write a int32 value to stream.
  136. /// </summary>
  137. /// <param name="value"></param>
  138. public void WriteInt(int value)
  139. {
  140. _stream.Write(BitConverter.GetBytes(value), 0, sizeof(int));
  141. }
  142. /// <summary>
  143. /// Write a short value to stream.
  144. /// </summary>
  145. /// <param name="value"></param>
  146. public void WriteShort(short value)
  147. {
  148. _stream.Write(BitConverter.GetBytes(value), 0, sizeof(short));
  149. }
  150. /// <summary>
  151. /// Write a int64 value to stream.
  152. /// </summary>
  153. /// <param name="value"></param>
  154. public void WriteLong(long value)
  155. {
  156. _stream.Write(BitConverter.GetBytes(value), 0, sizeof(long));
  157. }
  158. /// <summary>
  159. /// Write a float value to stream.
  160. /// </summary>
  161. /// <param name="value"></param>
  162. public void WriteFloat(float value)
  163. {
  164. _stream.Write(BitConverter.GetBytes(value), 0, sizeof(float));
  165. }
  166. /// <summary>
  167. /// Write a double value to stream.
  168. /// </summary>
  169. /// <param name="value"></param>
  170. public void WriteDouble(double value)
  171. {
  172. _stream.Write(BitConverter.GetBytes(value), 0, sizeof(double));
  173. }
  174. /// <summary>
  175. /// Write a bool value to stream.
  176. /// </summary>
  177. /// <param name="value"></param>
  178. public void WriteBool(bool value)
  179. {
  180. _stream.Write(BitConverter.GetBytes(value), 0, sizeof(bool));
  181. }
  182. /// <summary>
  183. /// Write a byte value to stream.
  184. /// </summary>
  185. /// <param name="value"></param>
  186. public void WriteByte(byte value)
  187. {
  188. _stream.WriteByte(value);
  189. }
  190. /// <summary>
  191. /// Write a array in to stream.
  192. /// </summary>
  193. public void WriteBytes(byte[] value)
  194. {
  195. WriteInt(value.Length);
  196. _stream.Write(value, 0, value.Length);
  197. }
  198. /// <summary>
  199. /// Write long array into stream.
  200. /// </summary>
  201. /// <param name="value"></param>
  202. public void WriteLongs(long[] value)
  203. {
  204. var data = new byte[value.Length * sizeof(long)];
  205. Buffer.BlockCopy(value, 0, data, 0, data.Length);
  206. WriteBytes(data);
  207. }
  208. }
  209. public enum VinnoProbeType
  210. {
  211. Undefined,
  212. Linear,
  213. Convex,
  214. Sector,
  215. };
  216. public class VinnoApplication
  217. {
  218. /// <summary>
  219. /// Gets the application's ID
  220. /// </summary>
  221. public string ApplicationId { get; }
  222. /// <summary>
  223. /// Gets the OriginalId of the applciation.
  224. /// </summary>
  225. public string ApplicationOriginalId { get; }
  226. /// <summary>
  227. /// Gets the application's name.
  228. /// </summary>
  229. public string ApplicationName { get; }
  230. /// <summary>
  231. /// Gets the applciation's category name.
  232. /// </summary>
  233. public string ApplicationCategoryName { get; }
  234. /// <summary>
  235. /// Gets if is user defined.
  236. /// </summary>
  237. public bool IsUserDefined { get; }
  238. public VinnoApplication(string applicationId, string applicationOriginalId, string applicationName, string applicationCategoryName, bool isUserDefined)
  239. {
  240. ApplicationId = applicationId;
  241. ApplicationOriginalId = applicationOriginalId;
  242. ApplicationName = applicationName;
  243. ApplicationCategoryName = applicationCategoryName;
  244. IsUserDefined = isUserDefined;
  245. }
  246. public byte[] ToBytes()
  247. {
  248. byte[] result;
  249. using (var stream = new MemoryStream())
  250. {
  251. var writer = new VinnoStreamWriter(stream);
  252. writer.WriteString(ApplicationId);
  253. writer.WriteString(ApplicationOriginalId);
  254. writer.WriteString(ApplicationName);
  255. writer.WriteString(ApplicationCategoryName);
  256. writer.WriteBool(IsUserDefined);
  257. result = stream.ToArray();
  258. }
  259. return result;
  260. }
  261. public static VinnoApplication FromBytes(byte[] bytes)
  262. {
  263. VinnoApplication result;
  264. using (var stream = new MemoryStream(bytes))
  265. {
  266. stream.Position = 0;
  267. var reader = new VinnoStreamReader(stream);
  268. var applicationId = reader.ReadString();
  269. var applicationOriginalId = reader.ReadString();
  270. var applicationName = reader.ReadString();
  271. var applicationCategoryName = reader.ReadString();
  272. var isUserDefined = reader.ReadBool();
  273. result = new VinnoApplication(applicationId, applicationOriginalId, applicationName, applicationCategoryName, isUserDefined);
  274. }
  275. return result;
  276. }
  277. }
  278. public class VinnoProbe
  279. {
  280. public string Name { get; }
  281. public VinnoProbeType Type { get; }
  282. public VinnoApplication Application { get; }
  283. public double FrameRate { get; }
  284. public VinnoProbe(string name, VinnoProbeType type, VinnoApplication application, double frameRate)
  285. {
  286. Name = name; //探头的型号名
  287. Type = type; //探头的类型
  288. Application = application;
  289. FrameRate = frameRate;
  290. }
  291. public byte[] ToBytes()
  292. {
  293. byte[] result;
  294. using (var stream = new MemoryStream())
  295. {
  296. var writer = new VinnoStreamWriter(stream);
  297. writer.WriteString(Name);
  298. writer.WriteByte((byte)Type);
  299. writer.WriteBytes(Application.ToBytes());
  300. writer.WriteDouble(FrameRate);
  301. result = stream.ToArray();
  302. }
  303. return result;
  304. }
  305. public static VinnoProbe FromBytes(byte[] bytes)
  306. {
  307. if (bytes == null)
  308. {
  309. return null;
  310. }
  311. VinnoProbe result;
  312. using (var stream = new MemoryStream(bytes))
  313. {
  314. stream.Position = 0;
  315. var reader = new VinnoStreamReader(stream);
  316. var name = reader.ReadString();
  317. var type = (VinnoProbeType)reader.ReadByte();
  318. var application = VinnoApplication.FromBytes(reader.ReadBytes());
  319. var frameRate = reader.ReadDouble();
  320. if (frameRate == 0)
  321. {
  322. frameRate = 15;
  323. }
  324. if (frameRate < 10 && frameRate >= 1)
  325. {
  326. frameRate = 10;
  327. }
  328. result = new VinnoProbe(name, type, application, frameRate);
  329. }
  330. return result;
  331. }
  332. }
  333. internal enum VidImageFormat
  334. {
  335. Jpeg = 0,
  336. Png = 1,
  337. H264 = 2,
  338. Zip = 3,
  339. Diff = 4,
  340. }
  341. internal interface IImageDataContainer
  342. {
  343. byte[] ImageData { get; set; }
  344. }
  345. internal class VinnoImageUpdater
  346. {
  347. private readonly IImageDataContainer _imageDataContainer;
  348. public VinnoImageUpdater(VinnoImage image)
  349. {
  350. _imageDataContainer = image;
  351. }
  352. /// <summary>
  353. /// Update VinnoImage's image data
  354. /// </summary>
  355. /// <param name="imageData">The image data to be updated.</param>
  356. public void Update(byte[] imageData)
  357. {
  358. _imageDataContainer.ImageData = imageData;
  359. }
  360. }
  361. public enum VinnoVisualType
  362. {
  363. V2D = 0,
  364. V3D,
  365. }
  366. public enum VinnoVisualIndicator
  367. {
  368. A = 0,
  369. B = 1,
  370. C = 2,
  371. D = 3
  372. }
  373. public enum VinnoDisplayMode
  374. {
  375. /// <summary>
  376. /// Normal B mode
  377. /// </summary>
  378. Normal = 0,
  379. /// <summary>
  380. /// Up/Down, B holds 1/3, Other hodes 2/3
  381. /// </summary>
  382. UpDown13B = 1,
  383. /// <summary>
  384. /// Up/Down, half, half
  385. /// </summary>
  386. UpDownHalfHalf = 2,
  387. /// <summary>
  388. /// Up/Down, B holds2/3, Other hodes1/3
  389. /// </summary>
  390. UpDown23B = 3,
  391. ///// <summary>
  392. ///// Left/Right, B holds 1/3, other hodes 2/3
  393. ///// </summary>
  394. //SideBySide13B = 3,
  395. /// <summary>
  396. /// Left/Right, half, half
  397. /// </summary>
  398. SideBySideHalfHalf = 4,
  399. /// <summary>
  400. /// Left/Right, B holds2/3, Other hodes1/3
  401. /// </summary>
  402. SideBySide14BOther = 5,
  403. /// <summary>
  404. /// All Image area are Other image instead of B image
  405. /// </summary>
  406. FullOther = 6,
  407. FullTissue = 7,
  408. }
  409. public enum VinnoModeType
  410. {
  411. Undefined = 0,
  412. Tissue,
  413. Flow,
  414. Doppler,
  415. TissueTM,
  416. Tissue3D,
  417. FlowM,
  418. };
  419. public class VinnoMode
  420. {
  421. public string Name { get; }
  422. public string DisplayName { get; }
  423. public VinnoModeType Type { get; }
  424. public VinnoMode(string name, string displayName, VinnoModeType type)
  425. {
  426. Name = name;
  427. DisplayName = displayName;
  428. Type = type;
  429. }
  430. public byte[] ToBytes()
  431. {
  432. byte[] result;
  433. using (var stream = new MemoryStream())
  434. {
  435. var writer = new VinnoStreamWriter(stream);
  436. writer.WriteString(Name);
  437. writer.WriteString(DisplayName);
  438. writer.WriteByte((byte)Type);
  439. result = stream.ToArray();
  440. }
  441. return result;
  442. }
  443. public static VinnoMode FromBytes(byte[] bytes)
  444. {
  445. VinnoMode result;
  446. using (var stream = new MemoryStream(bytes))
  447. {
  448. stream.Position = 0;
  449. var reader = new VinnoStreamReader(stream);
  450. var name = reader.ReadString();
  451. var displayName = reader.ReadString();
  452. var type = (VinnoModeType)reader.ReadByte();
  453. result = new VinnoMode(name, displayName, type);
  454. }
  455. return result;
  456. }
  457. }
  458. internal enum VinnoVisualAreaType
  459. {
  460. Tissue = 0,
  461. Flow,
  462. TimeMotion,
  463. Doppler,
  464. TissueTimeMotion,
  465. Trace,
  466. Colorbar,
  467. Tissue3D,
  468. ZoomTissue,
  469. ZoomFlow,
  470. AssociateTissue,
  471. AssociateFlow,
  472. }
  473. internal enum VinnoUnit
  474. {
  475. None = 0,
  476. percent = 1,
  477. cm = 10,
  478. mm = 11,
  479. inch = 12,
  480. ft = 13,
  481. s = 20,
  482. minute = 21,
  483. hour = 22,
  484. day = 23,
  485. week = 24,
  486. week_day = 25,
  487. Tick = 26,
  488. msec = 27,
  489. degree = 30,
  490. radian = 31,
  491. g = 40,
  492. mg = 41,
  493. ng = 42,
  494. kg = 43,
  495. oz = 44,
  496. lb = 45,
  497. cm2 = 50,
  498. mm2 = 51,
  499. m2 = 52,
  500. cm3 = 60,
  501. mm3 = 61,
  502. ml = 62,
  503. L = 63,
  504. cms = 70,
  505. mms = 71,
  506. ms = 72,
  507. cms2 = 80,
  508. mms2 = 81,
  509. cm3s = 90,
  510. mls = 91,
  511. mlmin = 92,
  512. Lmin = 93,
  513. gcm3 = 100,
  514. gml = 101,
  515. ngml = 102,
  516. mmHg = 110,
  517. mV = 120,
  518. Hz = 130,
  519. KHz = 131,
  520. /// <summary>
  521. /// beats per minute
  522. /// </summary>
  523. HR = 132,
  524. //SI
  525. cm3m2 = 140,
  526. mlm2 = 141,
  527. //CI
  528. cm3sm2 = 150,
  529. mlsm2 = 151,
  530. cm3minm2 = 153,
  531. mlminm2 = 154,
  532. Lminm2 = 155,
  533. /// <summary>
  534. /// MVCF:mean velocity of circumferential fiber shortening
  535. /// </summary>
  536. circs = 160,
  537. //CO
  538. mlbeat = 170,
  539. mm2pa = 180,
  540. d1mpa = 181,
  541. kpa = 182,
  542. mmHgs = 190,
  543. gm2 = 200,
  544. /// AVA Index
  545. cm2m2 = 210
  546. }
  547. internal class VinnoPoint
  548. {
  549. public double X { get; }
  550. public double Y { get; }
  551. public VinnoPoint(double x, double y)
  552. {
  553. X = x;
  554. Y = y;
  555. }
  556. public override string ToString()
  557. {
  558. return $"X:{X},Y:{Y}";
  559. }
  560. protected bool Equals(VinnoPoint other)
  561. {
  562. return X.Equals(other.X) && Y.Equals(other.Y);
  563. }
  564. public override bool Equals(object obj)
  565. {
  566. if (ReferenceEquals(null, obj)) return false;
  567. if (ReferenceEquals(this, obj)) return true;
  568. if (obj.GetType() != this.GetType()) return false;
  569. return Equals((VinnoPoint)obj);
  570. }
  571. public override int GetHashCode()
  572. {
  573. unchecked
  574. {
  575. return (X.GetHashCode() * 397) ^ Y.GetHashCode();
  576. }
  577. }
  578. public static bool operator ==(VinnoPoint left, VinnoPoint right)
  579. {
  580. return Equals(left, right);
  581. }
  582. public static bool operator !=(VinnoPoint left, VinnoPoint right)
  583. {
  584. return !Equals(left, right);
  585. }
  586. }
  587. internal class VinnoRect
  588. {
  589. public double Left { get; }
  590. public double Right { get; }
  591. public double Top { get; }
  592. public double Bottom { get; }
  593. public double Width => Math.Abs(Right - Left);
  594. public double Height => Math.Abs(Bottom - Top);
  595. public VinnoPoint TopLeft => new VinnoPoint(Left, Top);
  596. public VinnoPoint TopRight => new VinnoPoint(Right, Top);
  597. public VinnoPoint BottomLeft => new VinnoPoint(Left, Bottom);
  598. public VinnoPoint BottomRight => new VinnoPoint(Right, Bottom);
  599. public VinnoRect(double x, double y, double width, double height)
  600. {
  601. if ((width < 0.0) || (height < 0.0))
  602. {
  603. throw new ArgumentException("width and height can not less than 0.");
  604. }
  605. Left = x;
  606. Top = y;
  607. Right = Left + width;
  608. Bottom = Top + height;
  609. }
  610. public VinnoRect(VinnoPoint topLeft, VinnoPoint bottomRight)
  611. {
  612. Left = topLeft.X;
  613. Top = topLeft.Y;
  614. Right = bottomRight.X;
  615. Bottom = bottomRight.Y;
  616. }
  617. public static bool operator ==(VinnoRect rect1, VinnoRect rect2)
  618. {
  619. return ((((rect1.Left == rect2.Left) && (rect1.Right == rect2.Right)) && (rect1.Bottom == rect2.Bottom)) &&
  620. (rect1.Top == rect2.Top));
  621. }
  622. public static bool operator !=(VinnoRect rect1, VinnoRect rect2)
  623. {
  624. return !(rect1 == rect2);
  625. }
  626. public static bool Equals(VinnoRect rect1, VinnoRect rect2)
  627. {
  628. return ((((rect1.Left == rect2.Left) && (rect1.Right == rect2.Right)) && (rect1.Bottom == rect2.Bottom)) &&
  629. (rect1.Top == rect2.Top));
  630. }
  631. public override bool Equals(object o)
  632. {
  633. if ((o == null) || !(o is VinnoRect))
  634. {
  635. return false;
  636. }
  637. VinnoRect rect = (VinnoRect)o;
  638. return Equals(this, rect);
  639. }
  640. public bool Equals(VinnoRect value)
  641. {
  642. return Equals(this, value);
  643. }
  644. public override int GetHashCode()
  645. {
  646. return (((Left.GetHashCode() ^ Right.GetHashCode()) ^ Top.GetHashCode()) ^ Bottom.GetHashCode());
  647. }
  648. public override string ToString()
  649. {
  650. return $"L:{Left},R:{Right},T:{Top},B:{Bottom}";
  651. }
  652. }
  653. internal class VinnoLogicalCoordinate
  654. {
  655. public bool IsFlipHorizontal { get; }
  656. public bool IsFlipVertical { get; }
  657. public VinnoRect Region { get; }
  658. public VinnoUnit XUnit { get; }
  659. public VinnoUnit YUnit { get; }
  660. public VinnoLogicalCoordinate(bool isFlipHorizontal, bool isFlipVertical, VinnoRect region, VinnoUnit xUnit, VinnoUnit yUnit)
  661. {
  662. YUnit = yUnit;
  663. XUnit = xUnit;
  664. Region = region;
  665. IsFlipVertical = isFlipVertical;
  666. IsFlipHorizontal = isFlipHorizontal;
  667. }
  668. public byte[] ToBytes()
  669. {
  670. byte[] result;
  671. using (var stream = new MemoryStream())
  672. {
  673. var writer = new VinnoStreamWriter(stream);
  674. writer.WriteBool(IsFlipHorizontal);
  675. writer.WriteBool(IsFlipVertical);
  676. writer.WriteByte((byte)XUnit);
  677. writer.WriteByte((byte)YUnit);
  678. writer.WriteDouble(Region.Left);
  679. writer.WriteDouble(Region.Top);
  680. writer.WriteDouble(Region.Right);
  681. writer.WriteDouble(Region.Bottom);
  682. result = stream.ToArray();
  683. }
  684. return result;
  685. }
  686. public static VinnoLogicalCoordinate FromBytes(byte[] bytes)
  687. {
  688. VinnoLogicalCoordinate result;
  689. using (var stream = new MemoryStream(bytes))
  690. {
  691. stream.Position = 0;
  692. var reader = new VinnoStreamReader(stream);
  693. var isFlipHorizontal = reader.ReadBool();
  694. var isFlipVertical = reader.ReadBool();
  695. var xUnit = (VinnoUnit)reader.ReadByte();
  696. var yUnit = (VinnoUnit)reader.ReadByte();
  697. var left = reader.ReadDouble();
  698. var top = reader.ReadDouble();
  699. var right = reader.ReadDouble();
  700. var bottom = reader.ReadDouble();
  701. var region = new VinnoRect(new VinnoPoint(left, top), new VinnoPoint(right, bottom));
  702. result = new VinnoLogicalCoordinate(isFlipHorizontal, isFlipVertical, region, xUnit, yUnit);
  703. }
  704. return result;
  705. }
  706. }
  707. internal enum PhysicalCoordinateType
  708. {
  709. Tissue = 0,
  710. TimeMotion,
  711. ConvexTissue,
  712. LinearTissue,
  713. ConvexTVTissue,
  714. LinearTVTissue,
  715. Doppler,
  716. TissueTimeMotion,
  717. MAM,
  718. PWV
  719. }
  720. internal abstract class VinnoPhysicalCoordinate
  721. {
  722. public PhysicalCoordinateType Type { get; protected set; }
  723. public virtual byte[] ToBytes()
  724. {
  725. byte[] result;
  726. using (var stream = new MemoryStream())
  727. {
  728. var writer = new VinnoStreamWriter(stream);
  729. writer.WriteByte((byte)Type);
  730. result = stream.ToArray();
  731. }
  732. return result;
  733. }
  734. public static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  735. {
  736. VinnoPhysicalCoordinate physicalCoordinate = null;
  737. using (var stream = new MemoryStream(bytes))
  738. {
  739. stream.Position = 0;
  740. var reader = new VinnoStreamReader(stream);
  741. var type = (PhysicalCoordinateType)reader.ReadByte();
  742. switch (type)
  743. {
  744. case PhysicalCoordinateType.ConvexTissue:
  745. physicalCoordinate = VinnoConvexTissuePhysicalCoordinate.FromBytes(bytes);
  746. break;
  747. case PhysicalCoordinateType.LinearTissue:
  748. physicalCoordinate = VinnoLinearTissuePhysicalCoordinate.FromBytes(bytes);
  749. break;
  750. case PhysicalCoordinateType.ConvexTVTissue:
  751. physicalCoordinate = VinnoConvexTVTissuePhysicalCoordinate.FromBytes(bytes);
  752. break;
  753. case PhysicalCoordinateType.LinearTVTissue:
  754. physicalCoordinate = VinnoLinearTVTissuePhysicalCoordinate.FromBytes(bytes);
  755. break;
  756. case PhysicalCoordinateType.Doppler:
  757. physicalCoordinate = VinnoDopplerPhysicalCoordinate.FromBytes(bytes);
  758. break;
  759. case PhysicalCoordinateType.TissueTimeMotion:
  760. physicalCoordinate = VinnoTissueTimeMotionPhysicalCoordinate.FromBytes(bytes);
  761. break;
  762. case PhysicalCoordinateType.MAM:
  763. physicalCoordinate = VinnoMAMPhysicalCoordinate.FromBytes(bytes);
  764. break;
  765. case PhysicalCoordinateType.PWV:
  766. physicalCoordinate = VinnoPWVPhysicalCoordinate.FromBytes(bytes);
  767. break;
  768. }
  769. }
  770. return physicalCoordinate;
  771. }
  772. }
  773. internal abstract class VinnoTissuePhysicalCoordinate : VinnoPhysicalCoordinate
  774. {
  775. public double DepthEnd { get; }
  776. public double DepthStart { get; }
  777. public double Width { get; }
  778. public double BeamPosition { get; }
  779. protected VinnoTissuePhysicalCoordinate(double depthEnd, double depthStart, double width, double beamPosition)
  780. {
  781. Type = PhysicalCoordinateType.Tissue;
  782. BeamPosition = beamPosition;
  783. Width = width;
  784. DepthStart = depthStart;
  785. DepthEnd = depthEnd;
  786. }
  787. public override byte[] ToBytes()
  788. {
  789. byte[] result;
  790. using (var stream = new MemoryStream())
  791. {
  792. var baseData = base.ToBytes();
  793. stream.Write(baseData, 0, baseData.Length);
  794. stream.Position = stream.Length;
  795. var writer = new VinnoStreamWriter(stream);
  796. writer.WriteDouble(DepthStart);
  797. writer.WriteDouble(DepthEnd);
  798. writer.WriteDouble(Width);
  799. writer.WriteDouble(BeamPosition);
  800. result = stream.ToArray();
  801. }
  802. return result;
  803. }
  804. }
  805. internal abstract class VinnoTimeMotionPhysicalCoordinate : VinnoPhysicalCoordinate
  806. {
  807. public double SweepSpeed { get; }
  808. public double Max { get; }
  809. public double Min { get; }
  810. protected VinnoTimeMotionPhysicalCoordinate(double sweepSpeed, double max, double min)
  811. {
  812. Type = PhysicalCoordinateType.TimeMotion;
  813. Min = min;
  814. Max = max;
  815. SweepSpeed = sweepSpeed;
  816. }
  817. public override byte[] ToBytes()
  818. {
  819. byte[] result;
  820. using (var stream = new MemoryStream())
  821. {
  822. var baseData = base.ToBytes();
  823. stream.Write(baseData, 0, baseData.Length);
  824. stream.Position = stream.Length;
  825. var writer = new VinnoStreamWriter(stream);
  826. writer.WriteDouble(Min);
  827. writer.WriteDouble(Max);
  828. writer.WriteDouble(SweepSpeed);
  829. result = stream.ToArray();
  830. }
  831. return result;
  832. }
  833. }
  834. internal class VinnoConvexTissuePhysicalCoordinate : VinnoTissuePhysicalCoordinate
  835. {
  836. public double ZeroRadius { get; private set; }
  837. public VinnoConvexTissuePhysicalCoordinate(double depthEnd, double depthStart, double width, double beamPosition, double zeroRadius)
  838. : base(depthEnd, depthStart, width, beamPosition)
  839. {
  840. Type = PhysicalCoordinateType.ConvexTissue;
  841. ZeroRadius = zeroRadius;
  842. }
  843. public override byte[] ToBytes()
  844. {
  845. byte[] result;
  846. using (var stream = new MemoryStream())
  847. {
  848. var baseData = base.ToBytes();
  849. stream.Write(baseData, 0, baseData.Length);
  850. stream.Position = stream.Length;
  851. var writer = new VinnoStreamWriter(stream);
  852. writer.WriteDouble(ZeroRadius);
  853. result = stream.ToArray();
  854. }
  855. return result;
  856. }
  857. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  858. {
  859. VinnoPhysicalCoordinate result;
  860. using (var stream = new MemoryStream(bytes))
  861. {
  862. stream.Position = 0;
  863. var reader = new VinnoStreamReader(stream);
  864. var type = (PhysicalCoordinateType)reader.ReadByte();
  865. if (type != PhysicalCoordinateType.ConvexTissue)
  866. {
  867. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.ConvexTissue}, source type:{type}");
  868. }
  869. var depthStart = reader.ReadDouble();
  870. var depthEnd = reader.ReadDouble();
  871. var width = reader.ReadDouble();
  872. var beamPosition = reader.ReadDouble();
  873. var zeroRadius = reader.ReadDouble();
  874. result = new VinnoConvexTissuePhysicalCoordinate(depthEnd, depthStart, width, beamPosition, zeroRadius);
  875. }
  876. return result;
  877. }
  878. }
  879. internal class VinnoLinearTissuePhysicalCoordinate : VinnoTissuePhysicalCoordinate
  880. {
  881. public double Steer { get; }
  882. public VinnoLinearTissuePhysicalCoordinate(double depthEnd, double depthStart, double width, double beamPosition, double steer)
  883. : base(depthEnd, depthStart, width, beamPosition)
  884. {
  885. Type = PhysicalCoordinateType.LinearTissue;
  886. Steer = steer;
  887. }
  888. public override byte[] ToBytes()
  889. {
  890. byte[] result;
  891. using (var stream = new MemoryStream())
  892. {
  893. var baseData = base.ToBytes();
  894. stream.Write(baseData, 0, baseData.Length);
  895. stream.Position = stream.Length;
  896. var writer = new VinnoStreamWriter(stream);
  897. writer.WriteDouble(Steer);
  898. result = stream.ToArray();
  899. }
  900. return result;
  901. }
  902. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  903. {
  904. VinnoPhysicalCoordinate result;
  905. using (var stream = new MemoryStream(bytes))
  906. {
  907. stream.Position = 0;
  908. var reader = new VinnoStreamReader(stream);
  909. var type = (PhysicalCoordinateType)reader.ReadByte();
  910. if (type != PhysicalCoordinateType.LinearTissue)
  911. {
  912. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.LinearTissue}, source type:{type}");
  913. }
  914. var depthStart = reader.ReadDouble();
  915. var depthEnd = reader.ReadDouble();
  916. var width = reader.ReadDouble();
  917. var beamPosition = reader.ReadDouble();
  918. var steer = reader.ReadDouble();
  919. result = new VinnoLinearTissuePhysicalCoordinate(depthEnd, depthStart, width, beamPosition, steer);
  920. }
  921. return result;
  922. }
  923. }
  924. internal class VinnoConvexTVTissuePhysicalCoordinate : VinnoConvexTissuePhysicalCoordinate
  925. {
  926. public double OriginalZeroRadius { get; private set; }
  927. public double OriginalRocx { get; private set; }
  928. public VinnoConvexTVTissuePhysicalCoordinate(double depthEnd, double depthStart, double width, double beamPosition, double zeroRadius, double originalZeroRadius, double originalRocx)
  929. : base(depthEnd, depthStart, width, beamPosition, zeroRadius)
  930. {
  931. Type = PhysicalCoordinateType.ConvexTVTissue;
  932. OriginalRocx = originalRocx;
  933. OriginalZeroRadius = originalZeroRadius;
  934. }
  935. public override byte[] ToBytes()
  936. {
  937. byte[] result;
  938. using (var stream = new MemoryStream())
  939. {
  940. var baseData = base.ToBytes();
  941. stream.Write(baseData, 0, baseData.Length);
  942. stream.Position = stream.Length;
  943. var writer = new VinnoStreamWriter(stream);
  944. writer.WriteDouble(OriginalZeroRadius);
  945. writer.WriteDouble(OriginalRocx);
  946. result = stream.ToArray();
  947. }
  948. return result;
  949. }
  950. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  951. {
  952. VinnoPhysicalCoordinate result;
  953. using (var stream = new MemoryStream(bytes))
  954. {
  955. stream.Position = 0;
  956. var reader = new VinnoStreamReader(stream);
  957. var type = (PhysicalCoordinateType)reader.ReadByte();
  958. if (type != PhysicalCoordinateType.ConvexTVTissue)
  959. {
  960. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.ConvexTVTissue}, source type:{type}");
  961. }
  962. var depthStart = reader.ReadDouble();
  963. var depthEnd = reader.ReadDouble();
  964. var width = reader.ReadDouble();
  965. var beamPosition = reader.ReadDouble();
  966. var zeroRadius = reader.ReadDouble();
  967. var originalZeroRadius = reader.ReadDouble();
  968. var originalRocx = reader.ReadDouble();
  969. result = new VinnoConvexTVTissuePhysicalCoordinate(depthEnd, depthStart, width, beamPosition, zeroRadius, originalZeroRadius, originalRocx);
  970. }
  971. return result;
  972. }
  973. }
  974. internal class VinnoLinearTVTissuePhysicalCoordinate : VinnoConvexTissuePhysicalCoordinate
  975. {
  976. public VinnoLinearTVTissuePhysicalCoordinate(double depthEnd, double depthStart, double width, double beamPosition, double zeroRadius)
  977. : base(depthEnd, depthStart, width, beamPosition, zeroRadius)
  978. {
  979. Type = PhysicalCoordinateType.LinearTVTissue;
  980. }
  981. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  982. {
  983. VinnoPhysicalCoordinate result;
  984. using (var stream = new MemoryStream(bytes))
  985. {
  986. stream.Position = 0;
  987. var reader = new VinnoStreamReader(stream);
  988. var type = (PhysicalCoordinateType)reader.ReadByte();
  989. if (type != PhysicalCoordinateType.LinearTVTissue)
  990. {
  991. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.LinearTVTissue}, source type:{type}");
  992. }
  993. var depthStart = reader.ReadDouble();
  994. var depthEnd = reader.ReadDouble();
  995. var width = reader.ReadDouble();
  996. var beamPosition = reader.ReadDouble();
  997. var zeroRadius = reader.ReadDouble();
  998. result = new VinnoLinearTVTissuePhysicalCoordinate(depthEnd, depthStart, width, beamPosition, zeroRadius);
  999. }
  1000. return result;
  1001. }
  1002. }
  1003. internal class VinnoDopplerPhysicalCoordinate : VinnoTimeMotionPhysicalCoordinate
  1004. {
  1005. public double BaseLine { get; }
  1006. public VinnoDopplerPhysicalCoordinate(double sweepSpeed, double max, double min, double baseLine)
  1007. : base(sweepSpeed, max, min)
  1008. {
  1009. Type = PhysicalCoordinateType.Doppler;
  1010. BaseLine = baseLine;
  1011. }
  1012. public override byte[] ToBytes()
  1013. {
  1014. byte[] result;
  1015. using (var stream = new MemoryStream())
  1016. {
  1017. var baseData = base.ToBytes();
  1018. stream.Write(baseData, 0, baseData.Length);
  1019. stream.Position = stream.Length;
  1020. var writer = new VinnoStreamWriter(stream);
  1021. writer.WriteDouble(BaseLine);
  1022. result = stream.ToArray();
  1023. }
  1024. return result;
  1025. }
  1026. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  1027. {
  1028. VinnoPhysicalCoordinate result;
  1029. using (var stream = new MemoryStream(bytes))
  1030. {
  1031. stream.Position = 0;
  1032. var reader = new VinnoStreamReader(stream);
  1033. var type = (PhysicalCoordinateType)reader.ReadByte();
  1034. if (type != PhysicalCoordinateType.Doppler)
  1035. {
  1036. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.Doppler}, source type:{type}");
  1037. }
  1038. var min = reader.ReadDouble();
  1039. var max = reader.ReadDouble();
  1040. var sweepSpeed = reader.ReadDouble();
  1041. var baseLine = reader.ReadDouble();
  1042. result = new VinnoDopplerPhysicalCoordinate(sweepSpeed, max, min, baseLine);
  1043. }
  1044. return result;
  1045. }
  1046. }
  1047. internal class VinnoTissueTimeMotionPhysicalCoordinate : VinnoTimeMotionPhysicalCoordinate
  1048. {
  1049. public double DepthStart { get; }
  1050. public double DepthEnd { get; }
  1051. public VinnoTissueTimeMotionPhysicalCoordinate(double sweepSpeed, double max, double min, double depthStart, double depthEnd)
  1052. : base(sweepSpeed, max, min)
  1053. {
  1054. Type = PhysicalCoordinateType.TissueTimeMotion;
  1055. DepthEnd = depthEnd;
  1056. DepthStart = depthStart;
  1057. }
  1058. public override byte[] ToBytes()
  1059. {
  1060. byte[] result;
  1061. using (var stream = new MemoryStream())
  1062. {
  1063. var baseData = base.ToBytes();
  1064. stream.Write(baseData, 0, baseData.Length);
  1065. stream.Position = stream.Length;
  1066. var writer = new VinnoStreamWriter(stream);
  1067. writer.WriteDouble(DepthStart);
  1068. writer.WriteDouble(DepthEnd);
  1069. result = stream.ToArray();
  1070. }
  1071. return result;
  1072. }
  1073. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  1074. {
  1075. VinnoPhysicalCoordinate result;
  1076. using (var stream = new MemoryStream(bytes))
  1077. {
  1078. stream.Position = 0;
  1079. var reader = new VinnoStreamReader(stream);
  1080. var type = (PhysicalCoordinateType)reader.ReadByte();
  1081. if (type != PhysicalCoordinateType.TissueTimeMotion)
  1082. {
  1083. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.TissueTimeMotion}, source type:{type}");
  1084. }
  1085. var min = reader.ReadDouble();
  1086. var max = reader.ReadDouble();
  1087. var sweepSpeed = reader.ReadDouble();
  1088. var depthStart = reader.ReadDouble();
  1089. var depthEnd = reader.ReadDouble();
  1090. result = new VinnoTissueTimeMotionPhysicalCoordinate(sweepSpeed, max, min, depthStart, depthEnd);
  1091. }
  1092. return result;
  1093. }
  1094. }
  1095. internal class VinnoMAMPhysicalCoordinate : VinnoTissueTimeMotionPhysicalCoordinate
  1096. {
  1097. public VinnoMAMPhysicalCoordinate(double sweepSpeed, double max, double min, double depthStart, double depthEnd)
  1098. : base(sweepSpeed, max, min, depthStart, depthEnd)
  1099. {
  1100. Type = PhysicalCoordinateType.MAM;
  1101. }
  1102. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  1103. {
  1104. VinnoPhysicalCoordinate result;
  1105. using (var stream = new MemoryStream(bytes))
  1106. {
  1107. stream.Position = 0;
  1108. var reader = new VinnoStreamReader(stream);
  1109. var type = (PhysicalCoordinateType)reader.ReadByte();
  1110. if (type != PhysicalCoordinateType.MAM)
  1111. {
  1112. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.MAM}, source type:{type}");
  1113. }
  1114. var min = reader.ReadDouble();
  1115. var max = reader.ReadDouble();
  1116. var sweepSpeed = reader.ReadDouble();
  1117. var depthStart = reader.ReadDouble();
  1118. var depthEnd = reader.ReadDouble();
  1119. result = new VinnoMAMPhysicalCoordinate(sweepSpeed, max, min, depthStart, depthEnd);
  1120. }
  1121. return result;
  1122. }
  1123. }
  1124. internal class VinnoPWVPhysicalCoordinate : VinnoTissueTimeMotionPhysicalCoordinate
  1125. {
  1126. public VinnoPWVPhysicalCoordinate(double sweepSpeed, double max, double min, double depthStart, double depthEnd)
  1127. : base(sweepSpeed, max, min, depthStart, depthEnd)
  1128. {
  1129. Type = PhysicalCoordinateType.PWV;
  1130. }
  1131. public new static VinnoPhysicalCoordinate FromBytes(byte[] bytes)
  1132. {
  1133. VinnoPhysicalCoordinate result;
  1134. using (var stream = new MemoryStream(bytes))
  1135. {
  1136. stream.Position = 0;
  1137. var reader = new VinnoStreamReader(stream);
  1138. var type = (PhysicalCoordinateType)reader.ReadByte();
  1139. if (type != PhysicalCoordinateType.PWV)
  1140. {
  1141. throw new InvalidCastException($"Type not matched, target type:{PhysicalCoordinateType.PWV}, source type:{type}");
  1142. }
  1143. var min = reader.ReadDouble();
  1144. var max = reader.ReadDouble();
  1145. var sweepSpeed = reader.ReadDouble();
  1146. var depthStart = reader.ReadDouble();
  1147. var depthEnd = reader.ReadDouble();
  1148. result = new VinnoPWVPhysicalCoordinate(sweepSpeed, max, min, depthStart, depthEnd);
  1149. }
  1150. return result;
  1151. }
  1152. }
  1153. internal class Vinno2DVisual : VinnoVisual
  1154. {
  1155. /// <summary>
  1156. /// Gets all LogicalCoordinates of this visual.
  1157. /// </summary>
  1158. public Dictionary<VinnoVisualAreaType, VinnoLogicalCoordinate> LogicalCoordinates { get; }
  1159. /// <summary>
  1160. /// Gets all PhysicalCoordinates of this visual.
  1161. /// </summary>
  1162. public Dictionary<VinnoVisualAreaType, VinnoPhysicalCoordinate> PhysicalCoordinates { get; }
  1163. public Vinno2DVisual()
  1164. {
  1165. VisualType = VinnoVisualType.V2D;
  1166. LogicalCoordinates = new Dictionary<VinnoVisualAreaType, VinnoLogicalCoordinate>();
  1167. PhysicalCoordinates = new Dictionary<VinnoVisualAreaType, VinnoPhysicalCoordinate>();
  1168. }
  1169. public override byte[] ToBytes()
  1170. {
  1171. var baseData = base.ToBytes();
  1172. byte[] result;
  1173. using (var stream = new MemoryStream())
  1174. {
  1175. stream.Write(baseData, 0, baseData.Length);
  1176. var writer = new VinnoStreamWriter(stream);
  1177. writer.WriteByte((byte)PhysicalCoordinates.Count);
  1178. foreach (var key in PhysicalCoordinates.Keys)
  1179. {
  1180. writer.WriteByte((byte)key);
  1181. writer.WriteBytes(PhysicalCoordinates[key].ToBytes());
  1182. }
  1183. writer.WriteByte((byte)LogicalCoordinates.Count);
  1184. foreach (var key in LogicalCoordinates.Keys)
  1185. {
  1186. writer.WriteByte((byte)key);
  1187. writer.WriteBytes(LogicalCoordinates[key].ToBytes());
  1188. }
  1189. result = stream.ToArray();
  1190. }
  1191. return result;
  1192. }
  1193. public new static VinnoVisual FromBytes(byte[] bytes)
  1194. {
  1195. Vinno2DVisual result = null;
  1196. using (var stream = new MemoryStream(bytes))
  1197. {
  1198. stream.Position = 0;
  1199. var reader = new VinnoStreamReader(stream);
  1200. var visualType = (VinnoVisualType)reader.ReadByte();
  1201. var displayMode = (VinnoDisplayMode)reader.ReadByte();
  1202. if (visualType == VinnoVisualType.V2D)
  1203. {
  1204. var indicator = (VinnoVisualIndicator)reader.ReadByte();
  1205. var activeModeType = (VinnoModeType)reader.ReadByte();
  1206. var modeCount = reader.ReadByte();
  1207. var modes = new List<VinnoMode>();
  1208. for (var i = 0; i < modeCount; i++)
  1209. {
  1210. var mode = VinnoMode.FromBytes(reader.ReadBytes());
  1211. modes.Add(mode);
  1212. }
  1213. result = new Vinno2DVisual { Indicator = indicator };
  1214. foreach (var mode in modes)
  1215. {
  1216. result.Modes.Add(mode);
  1217. }
  1218. result.ActiveModeType = activeModeType;
  1219. var physicalCoordinateCount = reader.ReadByte();
  1220. var physicalCoordinates = new Dictionary<VinnoVisualAreaType, VinnoPhysicalCoordinate>();
  1221. for (var i = 0; i < physicalCoordinateCount; i++)
  1222. {
  1223. var visualAreaType = (VinnoVisualAreaType)reader.ReadByte();
  1224. var physicalCoordinate = VinnoPhysicalCoordinate.FromBytes(reader.ReadBytes());
  1225. physicalCoordinates.Add(visualAreaType, physicalCoordinate);
  1226. }
  1227. var logicalCoordinateCount = reader.ReadByte();
  1228. var logicalCoordinates = new Dictionary<VinnoVisualAreaType, VinnoLogicalCoordinate>();
  1229. for (var i = 0; i < logicalCoordinateCount; i++)
  1230. {
  1231. var visualAreaType = (VinnoVisualAreaType)reader.ReadByte();
  1232. var logicalCoordinate = VinnoLogicalCoordinate.FromBytes(reader.ReadBytes());
  1233. logicalCoordinates.Add(visualAreaType, logicalCoordinate);
  1234. }
  1235. foreach (var key in physicalCoordinates.Keys)
  1236. {
  1237. result.PhysicalCoordinates.Add(key, physicalCoordinates[key]);
  1238. }
  1239. foreach (var key in logicalCoordinates.Keys)
  1240. {
  1241. result.LogicalCoordinates.Add(key, logicalCoordinates[key]);
  1242. }
  1243. result.DisplayMode = displayMode;
  1244. }
  1245. }
  1246. return result;
  1247. }
  1248. }
  1249. internal enum VinnoAreaIndicator
  1250. {
  1251. Global = 0,
  1252. A,
  1253. B,
  1254. C,
  1255. ThreeD
  1256. }
  1257. internal class VinnoTissue3DArea
  1258. {
  1259. public VinnoRect Bounds { get; }
  1260. public double CmPerPixel { get; }
  1261. public VinnoPoint GlobalOffset { get; }
  1262. public VinnoAreaIndicator Indicator { get; }
  1263. public VinnoTissue3DArea(VinnoRect bounds, double cmPerPixel, VinnoPoint globalOffset, VinnoAreaIndicator indicator)
  1264. {
  1265. Indicator = indicator;
  1266. GlobalOffset = globalOffset;
  1267. CmPerPixel = cmPerPixel;
  1268. Bounds = bounds;
  1269. }
  1270. public byte[] ToBytes()
  1271. {
  1272. byte[] result;
  1273. using (var stream = new MemoryStream())
  1274. {
  1275. var writer = new VinnoStreamWriter(stream);
  1276. writer.WriteByte((byte)Indicator);
  1277. writer.WriteDouble(CmPerPixel);
  1278. writer.WriteDouble(GlobalOffset.X);
  1279. writer.WriteDouble(GlobalOffset.Y);
  1280. writer.WriteDouble(Bounds.Left);
  1281. writer.WriteDouble(Bounds.Top);
  1282. writer.WriteDouble(Bounds.Right);
  1283. writer.WriteDouble(Bounds.Bottom);
  1284. result = stream.ToArray();
  1285. }
  1286. return result;
  1287. }
  1288. public static VinnoTissue3DArea FromBytes(byte[] tissue3DAreaData)
  1289. {
  1290. VinnoTissue3DArea result;
  1291. using (var stream = new MemoryStream(tissue3DAreaData))
  1292. {
  1293. var reader = new VinnoStreamReader(stream);
  1294. var indicator = (VinnoAreaIndicator)reader.ReadByte();
  1295. var cmPerPixel = reader.ReadDouble();
  1296. var x = reader.ReadDouble();
  1297. var y = reader.ReadDouble();
  1298. var globalOffset = new VinnoPoint(x, y);
  1299. var left = reader.ReadDouble();
  1300. var top = reader.ReadDouble();
  1301. var right = reader.ReadDouble();
  1302. var bottom = reader.ReadDouble();
  1303. var bounds = new VinnoRect(new VinnoPoint(left, top), new VinnoPoint(right, bottom));
  1304. result = new VinnoTissue3DArea(bounds, cmPerPixel, globalOffset, indicator);
  1305. }
  1306. return result;
  1307. }
  1308. }
  1309. internal class Vinno3DVisual : VinnoVisual
  1310. {
  1311. /// <summary>
  1312. /// Gets the tissue 3d areas for this visual.
  1313. /// </summary>
  1314. public IList<VinnoTissue3DArea> Tissue3DAreas { get; }
  1315. public Vinno3DVisual()
  1316. {
  1317. VisualType = VinnoVisualType.V3D;
  1318. Tissue3DAreas = new List<VinnoTissue3DArea>();
  1319. }
  1320. public override byte[] ToBytes()
  1321. {
  1322. var baseData = base.ToBytes();
  1323. byte[] result;
  1324. using (var stream = new MemoryStream())
  1325. {
  1326. stream.Write(baseData, 0, baseData.Length);
  1327. var writer = new VinnoStreamWriter(stream);
  1328. writer.WriteByte((byte)Tissue3DAreas.Count);
  1329. foreach (var tissue3DArea in Tissue3DAreas)
  1330. {
  1331. writer.WriteBytes(tissue3DArea.ToBytes());
  1332. }
  1333. result = stream.ToArray();
  1334. }
  1335. return result;
  1336. }
  1337. public new static VinnoVisual FromBytes(byte[] bytes)
  1338. {
  1339. Vinno3DVisual result = null;
  1340. using (var stream = new MemoryStream(bytes))
  1341. {
  1342. stream.Position = 0;
  1343. var reader = new VinnoStreamReader(stream);
  1344. var visualType = (VinnoVisualType)reader.ReadByte();
  1345. var displayMode = (VinnoDisplayMode)reader.ReadByte();
  1346. if (visualType == VinnoVisualType.V3D)
  1347. {
  1348. var indicator = (VinnoVisualIndicator)reader.ReadByte();
  1349. result = new Vinno3DVisual { Indicator = indicator };
  1350. var activeModeType = (VinnoModeType)reader.ReadByte();
  1351. var modeCount = reader.ReadByte();
  1352. var modes = new List<VinnoMode>();
  1353. for (int i = 0; i < modeCount; i++)
  1354. {
  1355. var mode = VinnoMode.FromBytes(reader.ReadBytes());
  1356. modes.Add(mode);
  1357. }
  1358. foreach (var mode in modes)
  1359. {
  1360. result.Modes.Add(mode);
  1361. }
  1362. result.ActiveModeType = activeModeType;
  1363. var tissue3DAreaCount = reader.ReadByte();
  1364. var tissue3DAreas = new List<VinnoTissue3DArea>();
  1365. for (int i = 0; i < tissue3DAreaCount; i++)
  1366. {
  1367. var tissue3DArea = VinnoTissue3DArea.FromBytes(reader.ReadBytes());
  1368. tissue3DAreas.Add(tissue3DArea);
  1369. }
  1370. foreach (var tissue3DArea in tissue3DAreas)
  1371. {
  1372. result.Tissue3DAreas.Add(tissue3DArea);
  1373. }
  1374. result.DisplayMode = displayMode;
  1375. }
  1376. }
  1377. return result;
  1378. }
  1379. }
  1380. public class VinnoVisual
  1381. {
  1382. /// <summary>
  1383. /// Gets or sets the Display mode of this image.
  1384. /// </summary>
  1385. public VinnoDisplayMode DisplayMode { get; set; }
  1386. /// <summary>
  1387. /// Gets the visual type of this Visual.
  1388. /// </summary>
  1389. protected VinnoVisualType VisualType;
  1390. /// <summary>
  1391. /// Gets or sets the Indicator of this Visual.
  1392. /// </summary>
  1393. public VinnoVisualIndicator Indicator { get; set; }
  1394. /// <summary>
  1395. /// Gets or set the active mode type of this visual.
  1396. /// </summary>
  1397. public VinnoModeType ActiveModeType { get; set; }
  1398. /// <summary>
  1399. /// Gets all modse of this visual.
  1400. /// </summary>
  1401. public IList<VinnoMode> Modes { get; }
  1402. public VinnoVisual()
  1403. {
  1404. ActiveModeType = VinnoModeType.Undefined;
  1405. Modes = new List<VinnoMode>();
  1406. //Default is A
  1407. Indicator = VinnoVisualIndicator.A;
  1408. //Default is Normal
  1409. DisplayMode = VinnoDisplayMode.Normal;
  1410. }
  1411. public virtual byte[] ToBytes()
  1412. {
  1413. byte[] result;
  1414. using (var stream = new MemoryStream())
  1415. {
  1416. var writer = new VinnoStreamWriter(stream);
  1417. writer.WriteByte((byte)VisualType);
  1418. writer.WriteByte((byte)DisplayMode);
  1419. writer.WriteByte((byte)Indicator);
  1420. writer.WriteByte((byte)ActiveModeType);
  1421. writer.WriteByte((byte)Modes.Count);
  1422. foreach (var mode in Modes)
  1423. {
  1424. writer.WriteBytes(mode.ToBytes());
  1425. }
  1426. result = stream.ToArray();
  1427. }
  1428. return result;
  1429. }
  1430. public static VinnoVisual FromBytes(byte[] bytes)
  1431. {
  1432. VinnoVisual result = null;
  1433. using (var stream = new MemoryStream(bytes))
  1434. {
  1435. stream.Position = 0;
  1436. var reader = new VinnoStreamReader(stream);
  1437. var visualType = (VinnoVisualType)reader.ReadByte();
  1438. if (visualType == VinnoVisualType.V2D)
  1439. {
  1440. result = Vinno2DVisual.FromBytes(bytes);
  1441. }
  1442. if (visualType == VinnoVisualType.V3D)
  1443. {
  1444. result = Vinno3DVisual.FromBytes(bytes);
  1445. }
  1446. }
  1447. return result;
  1448. }
  1449. }
  1450. internal class VinnoImage : IImageDataContainer
  1451. {
  1452. /// <summary>
  1453. /// Gets the index of this image.
  1454. /// </summary>
  1455. public int Index { get; }
  1456. /// <summary>
  1457. /// Gets the width of this image data.
  1458. /// </summary>
  1459. public int Width { get; }
  1460. /// <summary>
  1461. /// Gets the height of this image data.
  1462. /// </summary>
  1463. public int Height { get; }
  1464. /// <summary>
  1465. /// Gets the image data of this image.
  1466. /// </summary>
  1467. public byte[] ImageData { get; private set; }
  1468. /// <summary>
  1469. /// Gets all visuals of this image.
  1470. /// </summary>
  1471. public IList<VinnoVisual> Visuals { get; }
  1472. /// <summary>
  1473. /// Implement the interface for update the image data.
  1474. /// </summary>
  1475. byte[] IImageDataContainer.ImageData
  1476. {
  1477. get => ImageData;
  1478. set => ImageData = value;
  1479. }
  1480. public VinnoImage(int index, int width, int height, byte[] imageData)
  1481. {
  1482. Visuals = new List<VinnoVisual>();
  1483. Index = index;
  1484. Width = width;
  1485. Height = height;
  1486. ImageData = imageData;
  1487. }
  1488. /// <summary>
  1489. /// Convert image to bytes.
  1490. /// </summary>
  1491. /// <returns>The converted bytes.</returns>
  1492. public byte[] ToBytes()
  1493. {
  1494. byte[] result = new byte[0];
  1495. using (var stream = new MemoryStream())
  1496. {
  1497. var writer = new VinnoStreamWriter(stream);
  1498. if (writer != null)
  1499. {
  1500. writer.WriteInt(Index);
  1501. writer.WriteByte((byte)Visuals.Count);
  1502. foreach (var visual in Visuals)
  1503. {
  1504. var buffer = visual?.ToBytes();
  1505. if (buffer != null)
  1506. {
  1507. writer.WriteBytes(buffer);
  1508. }
  1509. }
  1510. writer.WriteShort((short)Width);
  1511. writer.WriteShort((short)Height);
  1512. writer.WriteBytes(ImageData);
  1513. result = stream.ToArray();
  1514. }
  1515. }
  1516. return result;
  1517. }
  1518. /// <summary>
  1519. /// Convert bytes to a <see cref="VinnoImage"/>
  1520. /// </summary>
  1521. /// <param name="bytes">The bytes to be converted.</param>
  1522. /// <returns>The converted <see cref="VinnoImage"/></returns>
  1523. public static VinnoImage FromBytes(byte[] bytes)
  1524. {
  1525. VinnoImage result;
  1526. using (var stream = new MemoryStream(bytes))
  1527. {
  1528. stream.Position = 0;
  1529. var reader = new VinnoStreamReader(stream);
  1530. var index = reader.ReadInt();
  1531. var visualCount = reader.ReadByte();
  1532. var visuals = new List<VinnoVisual>();
  1533. for (int i = 0; i < visualCount; i++)
  1534. {
  1535. var visual = VinnoVisual.FromBytes(reader.ReadBytes());
  1536. visuals.Add(visual);
  1537. }
  1538. var widht = reader.ReadShort();
  1539. var height = reader.ReadShort();
  1540. var imageData = reader.ReadBytes();
  1541. result = new VinnoImage(index, widht, height, imageData);
  1542. foreach (var visual in visuals)
  1543. {
  1544. result.Visuals.Add(visual);
  1545. }
  1546. }
  1547. return result;
  1548. }
  1549. }
  1550. internal class VinnoImageData : IDisposable
  1551. {
  1552. private readonly OperationMode _operationMode;
  1553. private readonly Stream _stream;
  1554. private readonly VinnoStreamReader _reader;
  1555. private readonly VinnoStreamWriter _writer;
  1556. private readonly string _filePath;
  1557. private readonly List<long> _imagePositionList;
  1558. private bool _disposed;
  1559. private bool _closed;
  1560. private readonly object _addGetLocker = new object();
  1561. private const string Header = "VINNO IMAGE DATA";
  1562. private const string CacheHeader = "VINNOIMGCACHE";
  1563. /// <summary>
  1564. /// Gets the version of this image data.
  1565. /// </summary>
  1566. public int Version { get; }
  1567. /// <summary>
  1568. /// Gets the image count of this image data.
  1569. /// </summary>
  1570. public int ImageCount { get; private set; }
  1571. /// <summary>
  1572. /// Gets the probe information.
  1573. /// </summary>
  1574. public VinnoProbe Probe { get; private set; }
  1575. /// <summary>
  1576. /// Gets the image format of this image data.
  1577. /// </summary>
  1578. public VidImageFormat ImageFormat { get; }
  1579. /// <summary>
  1580. /// Gets or sets the extended data.
  1581. /// </summary>
  1582. public byte[] ExtendedData { get; set; }
  1583. /// <summary>
  1584. /// Create a VINNO Image Data.
  1585. /// </summary>
  1586. /// <param name="filePath">The file path to read or create.</param>
  1587. /// <param name="mode">The operation mode, create to create a vid file, open to open a vid file.</param>
  1588. public VinnoImageData(string filePath, OperationMode mode)
  1589. {
  1590. try
  1591. {
  1592. ImageFormat = VidImageFormat.Jpeg;
  1593. _filePath = filePath;
  1594. _operationMode = mode;
  1595. ExtendedData = new byte[0];
  1596. if (mode == OperationMode.Create)
  1597. {
  1598. //Create temp file.
  1599. var tempFile = _filePath + ".tmp";
  1600. _stream = new FileStream(tempFile, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
  1601. _writer = new VinnoStreamWriter(_stream);
  1602. Version = 3;
  1603. Probe = null;
  1604. _imagePositionList = new List<long>();
  1605. ImageCount = 0;
  1606. }
  1607. else
  1608. {
  1609. if (!File.Exists(_filePath) && File.Exists(_filePath + ".tmp"))
  1610. {
  1611. _filePath = _filePath + ".tmp";
  1612. }
  1613. _stream = new FileStream(_filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
  1614. _reader = new VinnoStreamReader(_stream);
  1615. var header = _reader.ReadString();
  1616. if (header != Header && header != CacheHeader)
  1617. {
  1618. _stream.Dispose();
  1619. throw new InvalidDataException("File is not a VID file.");
  1620. }
  1621. Version = _reader.ReadInt();
  1622. //Get probe info
  1623. var probeData = _reader.ReadBytes();
  1624. Probe = VinnoProbe.FromBytes(probeData);
  1625. ImageFormat = (VidImageFormat)_reader.ReadInt();
  1626. ExtendedData = _reader.ReadBytes();
  1627. //Get the index list.
  1628. _imagePositionList = new List<long>(_reader.ReadLongs());
  1629. ImageCount = _imagePositionList.Count;
  1630. }
  1631. }
  1632. catch (Exception ex)
  1633. {
  1634. _stream?.Dispose();
  1635. }
  1636. }
  1637. /// <summary>
  1638. /// Create a VINNO Image Data.
  1639. /// </summary>
  1640. /// <param name="stream"></param>
  1641. public VinnoImageData(Stream stream)
  1642. {
  1643. try
  1644. {
  1645. ImageFormat = VidImageFormat.Jpeg;
  1646. ExtendedData = new byte[0];
  1647. _stream = stream;
  1648. _reader = new VinnoStreamReader(_stream);
  1649. var header = _reader.ReadString();
  1650. if (header != Header)
  1651. {
  1652. _stream.Dispose();
  1653. throw new InvalidDataException("File is not a VID file.");
  1654. }
  1655. Version = _reader.ReadInt();
  1656. //Get probe info
  1657. var probeData = _reader.ReadBytes();
  1658. Probe = VinnoProbe.FromBytes(probeData);
  1659. ImageFormat = (VidImageFormat)_reader.ReadInt();
  1660. ExtendedData = _reader.ReadBytes();
  1661. //Get the index list.
  1662. _imagePositionList = new List<long>(_reader.ReadLongs());
  1663. ImageCount = _imagePositionList.Count;
  1664. }
  1665. catch (Exception ex)
  1666. {
  1667. _stream?.Dispose();
  1668. }
  1669. }
  1670. /// <summary>
  1671. /// Add probe info into vid.
  1672. /// </summary>
  1673. /// <param name="probe"></param>
  1674. public void AddProbe(VinnoProbe probe)
  1675. {
  1676. Probe = probe;
  1677. }
  1678. /// <summary>
  1679. /// Add dicom info into vid
  1680. /// </summary>
  1681. /// <param name="extendedData"></param>
  1682. public void AddExtendedData(byte[] extendedData)
  1683. {
  1684. ExtendedData = extendedData;
  1685. }
  1686. /// <summary>
  1687. /// Add one image into vid.
  1688. /// </summary>
  1689. /// <param name="image"></param>
  1690. public void AddImage(VinnoImage image)
  1691. {
  1692. if (_closed)
  1693. {
  1694. throw new InvalidOperationException("ImageData closed.");
  1695. }
  1696. if (_operationMode != OperationMode.Create)
  1697. {
  1698. throw new InvalidOperationException("Can not add image under open mode.");
  1699. }
  1700. lock (_addGetLocker)
  1701. {
  1702. var postion = _stream.Position;
  1703. _writer.WriteBytes(image.ToBytes());
  1704. _imagePositionList.Add(postion);
  1705. ImageCount++;
  1706. }
  1707. }
  1708. /// <summary>
  1709. /// Gets one image from the vid.
  1710. /// </summary>
  1711. /// <param name="index"></param>
  1712. /// <returns></returns>
  1713. public VinnoImage GetImage(int index)
  1714. {
  1715. if (_closed)
  1716. {
  1717. throw new InvalidOperationException("ImageData closed.");
  1718. }
  1719. if (_operationMode != OperationMode.Open)
  1720. {
  1721. throw new InvalidOperationException("Can not open image under create mode.");
  1722. }
  1723. if (index >= ImageCount || index < 0)
  1724. {
  1725. throw new IndexOutOfRangeException("Can not find image Data");
  1726. }
  1727. lock (_addGetLocker)
  1728. {
  1729. //Jump to image.
  1730. _stream.Position = _imagePositionList[index];
  1731. var imageData = _reader.ReadBytes();
  1732. return VinnoImage.FromBytes(imageData);
  1733. }
  1734. }
  1735. public void Close()
  1736. {
  1737. if (!_closed)
  1738. {
  1739. lock (_addGetLocker)
  1740. {
  1741. if (_operationMode == OperationMode.Create && !string.IsNullOrWhiteSpace(_filePath) && ImageCount > 0)
  1742. {
  1743. using (var stream = File.Create(_filePath))
  1744. {
  1745. var writer = new VinnoStreamWriter(stream);
  1746. writer.WriteString(Header);
  1747. writer.WriteInt(Version);
  1748. writer.WriteBytes(Probe.ToBytes());
  1749. writer.WriteInt((int)ImageFormat);
  1750. writer.WriteBytes(ExtendedData);
  1751. //Position data length = imagecount(int 4bytes) + imagecount * positionSize(long 8bytes)
  1752. var positionsDataLength = _imagePositionList.Count * sizeof(long) + 4;
  1753. var offset = stream.Length + positionsDataLength;
  1754. for (var i = 0; i < _imagePositionList.Count; i++)
  1755. {
  1756. _imagePositionList[i] = _imagePositionList[i] + offset;
  1757. }
  1758. writer.WriteLongs(_imagePositionList.ToArray());
  1759. _stream.Position = 0;
  1760. _stream.CopyTo(stream);
  1761. }
  1762. }
  1763. _stream?.Dispose();
  1764. if (_operationMode == OperationMode.Create && !string.IsNullOrWhiteSpace(_filePath))
  1765. {
  1766. var tempFile = _filePath + ".tmp";
  1767. File.Delete(tempFile);
  1768. }
  1769. }
  1770. _closed = true;
  1771. }
  1772. }
  1773. protected void Dispose(bool disposing)
  1774. {
  1775. if (!_disposed)
  1776. {
  1777. Close();
  1778. }
  1779. _disposed = true;
  1780. }
  1781. public void Dispose()
  1782. {
  1783. Dispose(true);
  1784. GC.SuppressFinalize(this);
  1785. }
  1786. }
  1787. /// <summary>
  1788. /// 扫描方位 左侧或右侧
  1789. /// </summary>
  1790. public enum ScanPosition
  1791. {
  1792. Left,
  1793. Right,
  1794. Fusion
  1795. }
  1796. public class Vinno3DPhysicalData
  1797. {
  1798. /// <summary>
  1799. /// Get thyroid scan position.
  1800. /// </summary>
  1801. public ScanPosition ScanPosition { get; }
  1802. /// <summary>
  1803. /// Get vinno visual.
  1804. /// </summary>
  1805. public IList<VinnoVisual> VinnoVisuals { get; }
  1806. /// <summary>
  1807. /// Get vinno visual.
  1808. /// </summary>
  1809. public VinnoProbe VinnoProbe { get; }
  1810. public Vinno3DPhysicalData(ScanPosition scanPosition, VinnoProbe vinnoProbe, IList<VinnoVisual> vinnoVisuals)
  1811. {
  1812. ScanPosition = scanPosition;
  1813. VinnoProbe = vinnoProbe;
  1814. VinnoVisuals = vinnoVisuals;
  1815. }
  1816. /// <summary>
  1817. /// From bytes.
  1818. /// </summary>
  1819. /// <param name="bytes">bytes.</param>
  1820. /// <returns>Instance of vinno carotid 3d physical data.</returns>
  1821. public static Vinno3DPhysicalData FromBytes(byte[] bytes)
  1822. {
  1823. using (var stream = new MemoryStream(bytes))
  1824. {
  1825. stream.Position = 0;
  1826. var reader = new VinnoStreamReader(stream);
  1827. var thyroidType = (ScanPosition)reader.ReadByte();
  1828. var probe = VinnoProbe.FromBytes(reader.ReadBytes());
  1829. var visualCount = reader.ReadByte();
  1830. var visuals = new List<VinnoVisual>();
  1831. for (int i = 0; i < visualCount; i++)
  1832. {
  1833. var visual = VinnoVisual.FromBytes(reader.ReadBytes()); // 全部为null
  1834. visuals.Add(visual);
  1835. }
  1836. return new Vinno3DPhysicalData(thyroidType, probe, visuals);
  1837. }
  1838. }
  1839. }
  1840. }