001/** 002 * Copyright (C) 2014 Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/ 003 * 004 * This file is part of Dicoogle/dicoogle-sdk. 005 * 006 * Dicoogle/dicoogle-sdk is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Dicoogle/dicoogle-sdk is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Dicoogle. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package pt.ua.dicoogle.sdk.utils; 020 021 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.List; 026import java.util.Map; 027import java.util.Map.Entry; 028import java.util.Set; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032import org.apache.commons.collections4.BidiMap; 033import org.apache.commons.collections4.SetUtils; 034import org.apache.commons.collections4.bidimap.DualHashBidiMap; 035 036/** 037 * Structure to manage all the tags inside Dicoogle. 038 * 039 * There are three groups. DIM Fields, DICOM Fields and PrivateFields 040 * DIM Fields may either be DICOM or Private. 041 * A DICOM and Private groups do not overlap 042 * 043 * Other fields is the common designation for fields that do not belong to the DIM. 044 * 045 * @author Luís A. Bastião Silva <bastiao@ua.pt> 046 * @author Tiago Marques Godinho <tmgodinho@ua.pt> Refactor 047 */ 048public class TagsStruct 049{ 050 private static final Logger logger = LoggerFactory.getLogger(TagsStruct.class); 051 052 //Optimization @TODO 053 //Map Structures 054 private BidiMap<Integer, String> tagNameMappings; 055 private HashMap<Integer, TagValue> tagValueMappings; 056 //Lists (DIM, DICOM, PrivateFields) 057 private Set<TagValue> nDIMFields; 058 private Set<TagValue> nDICOMFields; 059 private Set<TagValue> nPrivateFields; 060 //Modalities 061 private Set<String> modalitiesSet; 062 //Index All Modalities 063 private boolean indexAllModalities = false; 064 //DeepSearch modalities 065 private boolean deepSearchModalities = true; 066 067 private List<String> dictionaries = new ArrayList<>(); 068 069 private static TagsStruct instance = null ; 070 071 public static synchronized TagsStruct getInstance() 072 { 073 if (instance == null) { 074 instance = new TagsStruct(); 075 } 076 return instance; 077 } 078 079 080 private TagsStruct() 081 { 082 //Initialize fields; 083 this.tagNameMappings = new DualHashBidiMap<>(); 084 this.tagValueMappings = new HashMap<>(); 085 this.nDICOMFields = new HashSet<>(); 086 this.nDIMFields = new HashSet<>(); 087 this.nPrivateFields = new HashSet<>(); 088 this.modalitiesSet = new HashSet<>(); 089 090 Map<String, Integer> tmp = DictionaryAccess.getInstance().getTagList(); 091 for(Entry<String, Integer> e : tmp.entrySet()){ 092 addDICOMField(new TagValue(e.getValue(), e.getKey())); 093 } 094 095 addDIMField(new TagValue(Integer.parseInt("1021c0", 16), "PregnancyStatus")); 096 addDIMField(new TagValue( 097 Integer.parseInt("81050", 16),"PerformingPhysicianName")); 098 addDIMField(new TagValue( 099 Integer.parseInt("400243", 16),"PerformedLocation")); 100 addDIMField(new TagValue( 101 Integer.parseInt("100020", 16),"PatientID")); 102 addDIMField(new TagValue( 103 Integer.parseInt("80080", 16),"InstitutionName")); 104 addDIMField(new TagValue( 105 Integer.parseInt("80050", 16),"AccessionNumber")); 106 addDIMField(new TagValue( 107 Integer.parseInt("80020", 16),"StudyDate")); 108 addDIMField(new TagValue( 109 Integer.parseInt("102154", 16),"PatientTelephoneNumbers")); 110 addDIMField(new TagValue( 111 Integer.parseInt("101010", 16),"PatientAge")); 112 addDIMField(new TagValue( 113 Integer.parseInt("81070", 16),"OperatorName")); 114 addDIMField(new TagValue( 115 Integer.parseInt("200010", 16),"StudyID")); 116 addDIMField(new TagValue( 117 Integer.parseInt("81040", 16),"InstitutionDepartmentName")); 118 addDIMField(new TagValue( 119 Integer.parseInt("20000e", 16),"SeriesInstanceUID")); 120 addDIMField(new TagValue( 121 Integer.parseInt("20000d", 16),"StudyInstanceUID")); 122 addDIMField(new TagValue( 123 Integer.parseInt("100040", 16),"PatientSex")); 124 addDIMField(new TagValue( 125 Integer.parseInt("201208", 16),"NumberOfStudyRelatedInstances")); 126 addDIMField(new TagValue( 127 Integer.parseInt("100010", 16),"PatientName")); 128 addDIMField(new TagValue( 129 Integer.parseInt("80070", 16),"Manufacturer")); 130 addDIMField(new TagValue( 131 Integer.parseInt("81090", 16),"ManufacturerModelName")); 132 addDIMField(new TagValue( 133 Integer.parseInt("81030", 16),"StudyDescription")); 134 addDIMField(new TagValue( 135 Integer.parseInt("700", 16),"Priority")); 136 addDIMField(new TagValue( 137 Integer.parseInt("80090", 16),"ReferringPhysicianName")); 138 addDIMField(new TagValue( 139 Integer.parseInt("80061", 16),"ModalitiesInStudy")); 140 addDIMField(new TagValue( 141 Integer.parseInt("80060", 16),"Modality")); 142 addDIMField(new TagValue( 143 Integer.parseInt("80030", 16),"StudyTime")); 144 addDIMField(new TagValue( 145 Integer.parseInt("80018", 16),"SOPInstanceUID")); 146 addDIMField(new TagValue( 147 Integer.parseInt("80050", 16),"AccessionNumber")); 148 addDIMField(new TagValue( 149 Integer.parseInt("80070", 16),"Manufacturer")); 150 addDIMField(new TagValue( 151 Integer.parseInt("700", 16),"Priority")); 152 addDIMField(new TagValue( 153 Integer.parseInt("200011", 16),"SeriesNumber")); 154 addDIMField(new TagValue( 155 Integer.parseInt("08103e", 16),"SeriesDescription")); 156 addDIMField(new TagValue( 157 Integer.parseInt("100030", 16),"PatientBirthDate")); 158 159 addModality("XA"); 160 addModality("CT"); 161 addModality("US"); 162 addModality("MG"); 163 addModality("MR"); 164 } 165 166 /** 167 * Adds a new Tag to the structure. 168 * 169 * @param field 170 */ 171 private synchronized void addTag(TagValue field){ 172 TagValue tmp = this.tagValueMappings.get(field.getTagNumber()); 173 if(tmp == null){ 174 this.tagNameMappings.put(field.getTagNumber(), field.getName()); 175 this.tagValueMappings.put(field.getTagNumber(), field); 176 }else{ 177 //merge tag information 178 tmp.updateTagInformation(field); 179 this.tagNameMappings.put(tmp.getTagNumber(), tmp.getName()); 180 } 181 } 182 183 /** 184 * Removes a given Tag from the structure 185 * @param field 186 */ 187 private synchronized void removeTag(TagValue field){ 188 this.tagNameMappings.remove(field.getTagNumber()); 189 this.tagValueMappings.remove(field.getTagNumber()); 190 } 191 192 /** 193 * Adds a DIM Field. If the field already exists its information is updated. 194 * @param field 195 */ 196 public synchronized void addDIMField(TagValue field){ 197 //this.dimFields.put(field.getTagNumber(), field); 198 this.nDIMFields.add(field); 199 if(!isDICOMField(field) && !isPrivateField(field)) 200 addPrivateField(field); 201 addTag(field); 202 } 203 204 /** 205 * Adds a private field. Checks if the field is already present in the DICOM fields. 206 * @param field 207 * @return 208 */ 209 public synchronized boolean addPrivateField(TagValue field){ 210 addTag(field); 211 if(this.nDICOMFields.contains(field)){ 212 return true; 213 } 214 this.nPrivateFields.add(field); 215 return true; 216 } 217 218 /** 219 * Removes a Private Field. It is not possible to remove the field if it belongs to the DIM or to the DICOM group. 220 * @param tagNumber 221 * @return 222 */ 223 public synchronized boolean removePrivateField(int tagNumber){ 224 //this.dimFields.put(field.getTagNumber(), field); 225 TagValue tag = this.tagValueMappings.get(tagNumber); 226 if(this.nDICOMFields.contains(tag)){ 227 return false; 228 } 229 230 this.nPrivateFields.remove(tag); 231 this.nDIMFields.remove(tag); 232 removeTag(tag); 233 return true; 234 } 235 236 /** 237 * Adds a DICOM Field. 238 * @param field 239 */ 240 private synchronized void addDICOMField(TagValue field){ 241 //this.dimFields.put(field.getTagNumber(), field); 242 this.nDICOMFields.add(field); 243 addTag(field); 244 } 245 246 /** 247 * Adds a new Modality. 248 * @param modalityName 249 */ 250 public void addModality(String modalityName){ 251 this.modalitiesSet.add(modalityName); 252 } 253 254 /** 255 * Removes All modalities. 256 */ 257 public void removeAllModalities(){ 258 this.modalitiesSet = new HashSet<>(); 259 } 260 261 /** 262 * Removes the specified modality. 263 * @param modality 264 * @return true if the modality was present in the structure. 265 */ 266 public boolean removeModality(String modality){ 267 return this.modalitiesSet.remove(modality); 268 } 269 270 /** 271 * Gets a read-only view of the DIM Fields 272 * @return 273 */ 274 public Set<TagValue> getDIMFields(){ 275 return SetUtils.unmodifiableSet(this.nDIMFields); 276 } 277 278 /** 279 * Gets a List with the DIM fields names. 280 * @return 281 */ 282 public ArrayList<String> getDIMTagNames() 283 { 284 ArrayList<String> tagNames = new ArrayList<>(this.nDIMFields.size()); 285 for(TagValue tag : this.nDIMFields){ 286 tagNames.add(tag.getName()); 287 } 288 return tagNames; 289 } 290 291 /** 292 * Gets a List with the DIM fields alias. 293 * @return 294 */ 295 public ArrayList<String> getDIMAlias() 296 { 297 ArrayList<String> alias = new ArrayList<>(this.nDIMFields.size()); 298 for(TagValue tag : this.nDIMFields){ 299 alias.add(tag.getAlias()); 300 } 301 return alias; 302 } 303 304 /** 305 * @return a Read-only view of all fields. 306 */ 307 public Set<TagValue> getAllFields(){ 308 return SetUtils.unmodifiableSet( new HashSet<>(tagValueMappings.values()) ); 309 } 310 311 /** 312 * @return a Read only view of the Private Fields 313 */ 314 public Set<TagValue> getPrivateFields(){ 315 return SetUtils.unmodifiableSet(nPrivateFields); 316 } 317 318 /** 319 * @return the Fields which do not belong to the DIM. (DICOM+Private) 320 */ 321 public Set<TagValue> getOtherFields(){ 322 323 HashSet<TagValue> tags = new HashSet<>(this.nDICOMFields.size()+this.nPrivateFields.size()); 324 for(TagValue tag : this.tagValueMappings.values()){ 325 if(!isDICOMField(tag)) 326 tags.add(tag); 327 328 } 329 return tags; 330 } 331 332 /** 333 * 334 * @param tagNumber 335 * @return The TagValue object for the given Number, or null. 336 */ 337 public TagValue getTagValue(int tagNumber){ 338 return this.tagValueMappings.get(tagNumber); 339 } 340 341 /** 342 * 343 * @param tagName 344 * @return The TagValue object for the given its name, or null. 345 */ 346 public TagValue getTagValue(String tagName){ 347 Integer x = this.tagNameMappings.getKey(tagName); 348 if(x == null) 349 return null; 350 return this.getTagValue(x); 351 } 352 353 /** 354 * @param tag 355 * @return Whether the given tag is a DIM Field or not. 356 */ 357 public boolean isDIMField(TagValue tag){ 358 return this.nDIMFields.contains(tag); 359 } 360 361 /** 362 * @param tag 363 * @return Whether the given tag is a DICOM Field or not. 364 */ 365 public boolean isDICOMField(TagValue tag){ 366 return this.nDICOMFields.contains(tag); 367 } 368 369 /** 370 * @param tag 371 * @return Whether the given tag is a Private Field or not. 372 */ 373 public boolean isPrivateField(TagValue tag){ 374 return this.nPrivateFields.contains(tag); 375 } 376 377 /** 378 * @param tag 379 * @return Whether the given tag is an other field or not. (OtherFields = PrivateFields + DICOMFields) 380 */ 381 public boolean isOtherField(TagValue tag){ 382 return containsTag(tag.getTagNumber()) && !isDICOMField(tag); 383 } 384 385 /** 386 * Checks if the tag is present in the structure. 387 * @param tag 388 * @return 389 */ 390 public boolean containsTag(int tag){ 391 return this.tagValueMappings.containsKey(tag); 392 } 393 394 /** 395 * Checks if the given modality is present in the structure. 396 * @param modality 397 * @return 398 */ 399 public boolean containsModality(String modality){ 400 return this.modalitiesSet.contains(modality); 401 } 402 403 /** 404 * @return a Read-only view of the Modalities. 405 */ 406 public Set<String> getModalities() { 407 return SetUtils.unmodifiableSet(modalitiesSet); 408 } 409 410 /** 411 * Checks if the given modality is Enabled. 412 * @param modality 413 * @return 414 */ 415 public boolean isModalityEnable(String modality) 416 { 417 return isIndexAllModalitiesEnabled() || this.containsModality(modality); 418 } 419 420 /** 421 * @return the indexAllModalities 422 */ 423 public boolean isIndexAllModalitiesEnabled() { 424 return indexAllModalities; 425 } 426 427 /** 428 * @param indexAllModalities the indexAllModalities to set 429 */ 430 public void enableIndexAllModalities(boolean indexAllModalities) { 431 this.indexAllModalities = indexAllModalities; 432 } 433 434 public boolean isDeepSearchModalitiesEnabled() { 435 return deepSearchModalities; 436 } 437 438 439 public void enableDeepSearchModalities(boolean deepSearchModalities) { 440 this.deepSearchModalities = deepSearchModalities; 441 } 442 443 444 /** 445 * @return the dictionaries 446 */ 447 public List<String> getDictionaries() { 448 return dictionaries; 449 } 450 451 /** 452 * @param dictionaries the dictionaries to set 453 */ 454 public void setDictionaries(List<String> dictionaries) { 455 this.dictionaries = dictionaries; 456 } 457 458 459 public void addDicionary(String dic) 460 { 461 this.dictionaries.add(dic); 462 } 463 public void removeDicionary(String dic) 464 { 465 this.dictionaries.remove(dic); 466 } 467 468 469}