00001 package edu.stanford.hci.r3.pattern.coordinates;
00002
00003 import java.io.File;
00004 import java.io.FileNotFoundException;
00005 import java.io.FileOutputStream;
00006 import java.util.HashMap;
00007 import java.util.List;
00008 import java.util.Map;
00009 import java.util.Set;
00010
00011 import edu.stanford.hci.r3.PaperToolkit;
00012 import edu.stanford.hci.r3.paper.Region;
00013 import edu.stanford.hci.r3.paper.Sheet;
00014 import edu.stanford.hci.r3.pattern.coordinates.conversion.PatternCoordinateConverter;
00015 import edu.stanford.hci.r3.pattern.coordinates.conversion.TiledPatternCoordinateConverter;
00016 import edu.stanford.hci.r3.pen.PenSample;
00017 import edu.stanford.hci.r3.units.PatternDots;
00018 import edu.stanford.hci.r3.units.coordinates.PercentageCoordinates;
00019 import edu.stanford.hci.r3.units.coordinates.StreamedPatternCoordinates;
00020 import edu.stanford.hci.r3.util.DebugUtils;
00021 import edu.stanford.hci.r3.util.MathUtils;
00022 import edu.stanford.hci.r3.util.files.FileUtils;
00023
00047 public class PatternLocationToSheetLocationMapping {
00048
00049
00050 private static final String[] PATTERN_INFO_EXTENSION_FILTER = new String[] { "patternInfo.xml" };
00051
00056 private Map<Region, PatternCoordinateConverter> regionToPatternBounds = new HashMap<Region, PatternCoordinateConverter>();
00057
00061 private Sheet sheet;
00062
00074 public PatternLocationToSheetLocationMapping(Sheet s) {
00075 sheet = s;
00076 final List<Region> regions = s.getRegions();
00077 warnIfThereAreNoRegions(regions);
00078 initializeMap(regions);
00079 loadConfigurationFromAutomaticallyDiscoveredXMLFiles();
00080 }
00081
00088 public PatternLocationToSheetLocationMapping(Sheet s, File patternInfoFile) {
00089 sheet = s;
00090 final List<Region> regions = s.getRegions();
00091 warnIfThereAreNoRegions(regions);
00092 initializeMap(regions);
00093 loadConfigurationFromXML(patternInfoFile);
00094 }
00095
00103 public PatternCoordinateConverter getCoordinateConverterForSample(PenSample sample) {
00104 for (Region r : regionToPatternBounds.keySet()) {
00105 PatternCoordinateConverter converter = regionToPatternBounds.get(r);
00106 final StreamedPatternCoordinates coord = new StreamedPatternCoordinates(sample);
00107 if (converter.contains(coord)) {
00108
00109
00110
00111 final PercentageCoordinates relativeLocation = converter.getRelativeLocation(coord);
00112
00113
00114
00115 if (relativeLocation.getPercentageInXDirection() > 100
00116 || relativeLocation.getPercentageInYDirection() > 100) {
00117 DebugUtils.println("FALLBACK HACK. It's actually outside the bounds. "
00118 + "Going on to check the next region...");
00119 continue;
00120 } else {
00121 return converter;
00122 }
00123 }
00124 }
00125 return null;
00126 }
00127
00133 public PatternCoordinateConverter getPatternBoundsOfRegion(Region r) {
00134 DebugUtils.println(regionToPatternBounds.size() + " " + r.getName() + " "
00135 + regionToPatternBounds);
00136
00137 return regionToPatternBounds.get(r);
00138 }
00139
00146 public Map<Region, PatternCoordinateConverter> getRegionToPatternMapping() {
00147 return regionToPatternBounds;
00148 }
00149
00153 public Sheet getSheet() {
00154 return sheet;
00155 }
00156
00164 public void initializeMap(List<Region> regions) {
00165 regionToPatternBounds.clear();
00166 for (final Region r : regions) {
00167 if (r.isActive()) {
00168
00169
00170
00171
00172
00173 regionToPatternBounds.put(r, new TiledPatternCoordinateConverter(r.getName()));
00174 }
00175 }
00176 }
00177
00181 private void loadConfigurationFromAutomaticallyDiscoveredXMLFiles() {
00182
00183
00184 final Set<File> configurationPaths = sheet.getConfigurationPaths();
00185 if (configurationPaths.size() == 0) {
00186 DebugUtils.println("This Sheet does not have any pattern configuration paths. "
00187 + "Either add one so that we can automatically look for *.patternInfo.xml "
00188 + "files, or add patternInfo files explicitly.");
00189 return;
00190 }
00191
00192 DebugUtils.println("This Sheet has configuration paths for *.patternInfo.xml files.");
00193
00194 for (File path : configurationPaths) {
00195
00196 List<File> patternInfoFiles = FileUtils.listVisibleFiles(path,
00197 PATTERN_INFO_EXTENSION_FILTER);
00198
00199 for (File f : patternInfoFiles) {
00200 DebugUtils.println("Trying to automatically load " + f.getName());
00201 loadConfigurationFromXML(f);
00202 }
00203 }
00204 }
00205
00212 @SuppressWarnings("unchecked")
00213 public void loadConfigurationFromXML(File xmlFile) {
00214
00215 final HashMap<RegionID, PatternCoordinateConverter> regionIDToPattern = (HashMap<RegionID, PatternCoordinateConverter>) PaperToolkit
00216 .fromXML(xmlFile);
00217 for (Region r : regionToPatternBounds.keySet()) {
00218 final RegionID xmlKey = new RegionID(r);
00219
00220
00221
00222
00223 if (regionIDToPattern.containsKey(xmlKey)) {
00224 DebugUtils.println("Loaded Pattern Configuration for " + xmlKey);
00225 regionToPatternBounds.put(r, regionIDToPattern.get(xmlKey));
00226 }
00227 }
00228 }
00229
00233 public void printMapping() {
00234 System.out.println(this);
00235 }
00236
00243 public void saveConfigurationToXML(File xmlFile) {
00244 try {
00245
00246
00247 final HashMap<RegionID, PatternCoordinateConverter> regionIDToPattern = new HashMap<RegionID, PatternCoordinateConverter>();
00248 final Set<Region> regions = regionToPatternBounds.keySet();
00249 for (Region r : regions) {
00250 if (!r.isActive()) {
00251 continue;
00252 }
00253 final RegionID rid = new RegionID(r);
00254 regionIDToPattern.put(rid, regionToPatternBounds.get(r));
00255 }
00256 if (xmlFile.exists()) {
00257 DebugUtils.println("Overwriting XML File: " + xmlFile.getName());
00258 xmlFile.delete();
00259 }
00260 PaperToolkit.toXML(regionIDToPattern, new FileOutputStream(xmlFile));
00261 } catch (FileNotFoundException e) {
00262 e.printStackTrace();
00263 }
00264 }
00265
00274 public void setPatternInformationOfRegion(Region r, PatternCoordinateConverter coordinateInfo) {
00275 if (regionToPatternBounds.containsKey(r) || sheet.containsRegion(r)) {
00276
00277
00278 regionToPatternBounds.put(r, coordinateInfo);
00279 } else {
00280 System.err.println("PatternLocationToSheetLocationMapping.java: Region unknown. "
00281 + "Please add it to the sheet before updating this mapping.");
00282 }
00283 }
00284
00295 public void setPatternInformationOfRegion(Region region,
00296 PatternDots x, PatternDots y, PatternDots width, PatternDots height) {
00297 setPatternInformationOfRegion(region, new TiledPatternCoordinateConverter(region.getName(),
00298 x.getValue(), y.getValue(),
00299 MathUtils.rint(width.getValue()), MathUtils.rint(height.getValue())));
00300 }
00301
00305 public void setSheet(Sheet s) {
00306 sheet = s;
00307 }
00308
00312 public String toString() {
00313 final StringBuilder sb = new StringBuilder();
00314 for (final Region r : regionToPatternBounds.keySet()) {
00315 sb.append(r.getName() + " --> ");
00316 final PatternCoordinateConverter bounds = regionToPatternBounds.get(r);
00317 sb.append(bounds + ", ");
00318 }
00319 String string = sb.toString();
00320 if (string.length() > 2) {
00321 return string.substring(0, string.length() - 2);
00322 } else {
00323 return string;
00324 }
00325 }
00326
00330 private void warnIfThereAreNoRegions(final List<Region> regions) {
00331
00332
00333 if (regions.size() == 0) {
00334 DebugUtils.println("There aren't any regions. Did you perhaps add the "
00335 + "regions _after_ you added the sheet to the application?");
00336 }
00337 }
00338 }