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.datastructs; 020 021import java.io.Serializable; 022import java.net.URI; 023import java.util.HashMap; 024 025/** 026 * Simple holder class to store one hit from searches. 027 * 028 * @author Marco 029 * @author Carlos Ferreira 030 * @author Pedro Bento 031 * modified by: Frederico Valente 032 */ 033public class SearchResult implements Serializable { 034 private URI location; //a uri that allows us to fetch the result object 035 private double score; //score given by the querier 036 037 //stores extra data, placed by specific plugins or inserted along the way 038 private HashMap<String, Object> extraData = new HashMap<>(); 039 040 public SearchResult(URI location, double score, HashMap<String,Object> data){ 041 this.location = location; 042 this.score = score; 043 044 if(data != null) 045 this.extraData = data; 046 } 047 048 049 /** 050 * Gets the location of the hit 051 * @return URI pointing to dicom object 052 */ 053 public URI getURI(){return location;} 054 055 056 public Object get(String tag){ 057 return extraData.get(tag); 058 } 059 060 public void put(String tag, Object value){ 061 extraData.put(tag, value); 062 } 063 064 public <T> T getData(String extraFieldName){ 065 Object ret = extraData.get(extraFieldName); 066 067 if(ret == null) return null; 068 069 try{ 070 return (T) ret; 071 } 072 catch(ClassCastException e){ 073 return null; 074 } 075 } 076 077 /** 078 * Unlike what the name says, this does not returns the score. 079 * Unless it does. Ok, it does... which is most definitely weird given the method name. 080 * This score is a measure of *dissimilarity* 081 * that is, a score of 0 should mean an exact hit 082 * 083 * @return score of the result; 084 */ 085 public double getScore(){return score;} 086 087 /** 088 * Gets the extra documents fields 089 * @return the table containing the extra fields 090 */ 091 public HashMap<String, Object> getExtraData(){return extraData;} 092 093 @Override 094 public String toString(){ 095 return location.toString()+" "+score; 096 } 097 098 099 /* Returns a tree made of hashmaps 100 * the first key is the patientName, the second the study, followed by series and image uri 101 * 102 * todo: move the goddamned hash train to a class, 103 * just the definition of this makes me sick 104 */ 105 public static HashMap<String, HashMap<String, HashMap<String, HashMap<String, SearchResult>>>> toTree(Iterable<SearchResult> results){ 106 HashMap<String, HashMap<String, HashMap<String, HashMap<String, SearchResult>>>> tree = new HashMap<>(); 107 108 for(SearchResult r : results){ 109 URI fileName = r.getURI(); 110 String patientName = r.<String>getData("PatientName"); 111 String studyUID = r.<String>getData("StudyInstanceUID"); 112 String seriesUID = r.<String>getData("SeriesInstanceUID"); 113 //we could have a SOPInstanceUID here but we use the search result itself as last element 114 115 if(patientName == null) patientName = "undefined PatientName"; 116 else{patientName = patientName.trim();} 117 118 if(studyUID == null) studyUID = "undefined StudyInstanceUID"; 119 else{studyUID = studyUID.trim();} 120 121 if(seriesUID == null) seriesUID = "undefined SeriesInstanceUID"; 122 else{seriesUID = seriesUID.trim();} 123 124 //check patient 125 if(tree.containsKey(patientName)){ 126 if(tree.get(patientName).containsKey(studyUID)){ 127 if(tree.get(patientName).get(studyUID).containsKey(seriesUID)){ 128 tree.get(patientName).get(studyUID).get(seriesUID).put(fileName.toString(), r); 129 } 130 else{ 131 HashMap<String, SearchResult> seriesResults = new HashMap<>(); 132 seriesResults.put(fileName.toString(), r); 133 134 tree.get(patientName).get(studyUID).put(seriesUID, seriesResults); 135 } 136 } 137 else{//no study 138 HashMap<String, SearchResult> seriesResults = new HashMap<>(); 139 seriesResults.put(fileName.toString(), r); 140 141 HashMap<String, HashMap<String, SearchResult>> studySeries = new HashMap<>(); 142 studySeries.put(seriesUID, seriesResults); 143 144 tree.get(patientName).put(studyUID, studySeries); 145 } 146 } 147 else{//no patient name 148 HashMap<String, SearchResult> seriesResults = new HashMap<>(); 149 seriesResults.put(fileName.toString(), r); 150 151 HashMap<String, HashMap<String, SearchResult>> studySeries = new HashMap<>(); 152 studySeries.put(seriesUID, seriesResults); 153 154 HashMap<String, HashMap<String, HashMap<String,SearchResult>>> patientStudies = new HashMap<>(); 155 patientStudies.put(studyUID, studySeries); 156 157 tree.put(patientName, patientStudies);//add patient, study, series, image to tree 158 } 159 } 160 return tree; 161 } 162 163}