/*
* Copyright (c) 2014 Oculus Info Inc. http://www.oculusinfo.com/
*
* Released under the MIT License.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oculusinfo.annotation.util;
import com.oculusinfo.annotation.AnnotationData;
import com.oculusinfo.annotation.AnnotationTile;
import com.oculusinfo.annotation.impl.JSONAnnotation;
import com.oculusinfo.annotation.index.AnnotationIndexer;
import com.oculusinfo.binning.BinIndex;
import com.oculusinfo.binning.TileAndBinIndices;
import com.oculusinfo.binning.TileIndex;
import com.oculusinfo.binning.TilePyramid;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.*;
public class AnnotationGenerator {
static final double EPSILON = 0.001;
static final int MAX_LEVEL_POINT = 10;
static final int MAX_LEVEL_RANGE = 4;
private List<String> _groups;
private List<Double> _bounds;
final Random _rand = new Random();
public AnnotationGenerator( double[] bounds, String[] groups ) {
_bounds = new ArrayList<>();
_bounds.add( bounds[0] + EPSILON );
_bounds.add( bounds[1] + EPSILON );
_bounds.add( bounds[2] - EPSILON );
_bounds.add( bounds[3] - EPSILON );
_groups = Arrays.asList( groups );
}
public AnnotationData<?> generateJSONAnnotation() {
return JSONAnnotation.fromJSON(generateJSON());
}
public List<AnnotationData<?>> generateJSONAnnotations( int numEntries ) {
List<AnnotationData<?>> annotations = new ArrayList<>();
for (int i=0; i<numEntries; i++) {
annotations.add( generateJSONAnnotation() );
}
return annotations;
}
public JSONObject generateJSON() {
if ( _rand.nextBoolean() ) {
// range based
if ( _rand.nextBoolean() ) {
// uni-variate
return generateUnivariateRangeJSON();
} else {
// bi-variate
return generateBivariateRangeJSON();
}
} else {
// point based
if ( _rand.nextBoolean() ) {
// uni-variate
return generateUnivariatePointJSON();
} else {
// bi-variate
return generateBivariatePointJSON();
}
}
}
public List<AnnotationTile> generateTiles( List<AnnotationData<?>> annotations, AnnotationIndexer indexer, TilePyramid pyramid ) {
Map<TileIndex, AnnotationTile> tiles = new HashMap<>();
for ( AnnotationData<?> annotation : annotations ) {
List<TileAndBinIndices> indices = indexer.getIndices( annotation, pyramid );
for ( TileAndBinIndices index : indices ) {
TileIndex tileIndex = index.getTile();
BinIndex binIndex = index.getBin();
if ( tiles.containsKey( tileIndex ) ) {
tiles.get( tileIndex ).addDataToBin(binIndex, annotation);
} else {
AnnotationTile tile = new AnnotationTile( tileIndex );
tile.addDataToBin(binIndex, annotation);
tiles.put( tileIndex, tile );
}
}
}
return new ArrayList<>( tiles.values() );
}
public JSONObject generateUnivariatePointJSON() {
JSONObject anno = generateJSONBody( (int)(_rand.nextDouble() * MAX_LEVEL_POINT) );
double [] xy = randomPosition();
try {
if ( _rand.nextBoolean() ) {
anno.put("x", xy[0]);
} else {
anno.put("y", xy[1]);
}
return anno;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public JSONObject generateUnivariateRangeJSON() {
JSONObject anno = generateJSONBody( (int)(_rand.nextDouble() * MAX_LEVEL_RANGE) );
double [] xy0 = randomPosition();
double [] xy1 = randomPosition();
try {
if ( _rand.nextBoolean() ) {
JSONArray x = new JSONArray();
x.put( Math.min( xy0[0], xy1[0] ) );
x.put( Math.max( xy0[0], xy1[0] ) );
anno.put( "x", x );
} else {
JSONArray y = new JSONArray();
y.put( Math.min( xy0[1], xy1[1] ) );
y.put( Math.max( xy0[1], xy1[1] ) );
anno.put( "y", y );
}
return anno;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public JSONObject generateBivariatePointJSON() {
JSONObject anno = generateJSONBody( (int)(_rand.nextDouble() * MAX_LEVEL_POINT) );
double [] xy = randomPosition();
try {
anno.put("x", xy[0]);
anno.put("y", xy[1]);
return anno;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public JSONObject generateBivariateRangeJSON() {
JSONObject anno = generateJSONBody( (int)(_rand.nextDouble() * MAX_LEVEL_RANGE) );
double [] xy0 = randomPosition();
double [] xy1 = randomPosition();
try {
JSONArray x = new JSONArray();
x.put( Math.min( xy0[0], xy1[0] ) );
x.put( Math.max( xy0[0], xy1[0] ) );
anno.put( "x", x );
JSONArray y = new JSONArray();
y.put( Math.min( xy0[1], xy1[1] ) );
y.put( Math.max( xy0[1], xy1[1] ) );
anno.put( "y", y );
return anno;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private JSONObject generateJSONBody( int level ) {
try {
JSONObject anno = new JSONObject();
anno.put("level", level );
JSONObject range = new JSONObject();
range.put("min", 0 );
range.put("max", level );
anno.put("range", range );
anno.put("group", randomGroup() );
JSONObject data = new JSONObject();
data.put("comment", randomComment() );
anno.put("data", data);
return anno;
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public double[] randomPosition() {
double [] xy = new double[2];
xy[0] = _bounds.get(0) + ( _rand.nextDouble() * (_bounds.get(2) - _bounds.get(0)) );
xy[1] = _bounds.get(1) + ( _rand.nextDouble() * (_bounds.get(3) - _bounds.get(1)) );
return xy;
}
public String randomGroup() {
int index = (int)( _rand.nextDouble() * _groups.size() );
return _groups.get( index );
}
public String randomComment() {
int LENGTH = 256;
String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
char[] text = new char[LENGTH];
for (int i = 0; i < LENGTH; i++)
{
text[i] = CHARACTERS.charAt(_rand.nextInt(CHARACTERS.length()));
}
return new String(text);
}
}