io.annot8.common.data.bounds.SpanBounds Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of annot8-common-data Show documentation
Show all versions of annot8-common-data Show documentation
Common data (bounds and content) definitions
The newest version!
/* Annot8 (annot8.io) - Licensed under Apache-2.0. */
package io.annot8.common.data.bounds;
import io.annot8.api.bounds.Bounds;
import io.annot8.api.data.Content;
import io.annot8.api.exceptions.InvalidBoundsException;
import jakarta.json.bind.annotation.JsonbCreator;
import jakarta.json.bind.annotation.JsonbProperty;
import jakarta.json.bind.annotation.JsonbTransient;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;
import javax.sound.sampled.AudioInputStream;
/** Implementation of Bounds for a simple 2D span, such as an offset of text. */
public class SpanBounds implements Bounds {
private final int begin;
private final int end;
/**
* Create a new object with the specified begin and end values
*
* @param begin start offset, at least 0
* @param end (must be greater than begin)
*/
@JsonbCreator
public SpanBounds(@JsonbProperty("begin") final int begin, @JsonbProperty("end") final int end) {
if (begin < 0) {
throw new InvalidBoundsException("Begin must be greater than or equal to 0");
}
if (end < begin) {
throw new InvalidBoundsException("End must be greater than or equal to Begin");
}
this.begin = begin;
this.end = end;
}
/**
* The begin position of this object
*
* @return the offset
*/
public int getBegin() {
return begin;
}
/**
* The end position of this object
*
* @return the offset
*/
public int getEnd() {
return end;
}
/**
* The length of this span
*
* @return length (end-begin)
*/
@JsonbTransient
public int getLength() {
return end - begin;
}
@Override
public , R> Optional getData(C content, Class requiredClass) {
D data = content.getData();
if (requiredClass.isAssignableFrom(String.class) && data.getClass().equals(String.class)) {
String s = (String) data;
int normBegin = Math.max(0, begin);
int normEnd = Math.min(s.length(), end);
@SuppressWarnings("unchecked") // This is checked R = String.class
R r = (R) s.substring(normBegin, normEnd);
return Optional.of(r);
} else if (requiredClass.isAssignableFrom(AudioInputStream.class)
&& data.getClass().equals(AudioInputStream.class)) {
AudioInputStream ais = (AudioInputStream) data;
try {
int frameSize = ais.getFormat().getFrameSize();
long framesBegin = Math.max(0, begin);
long bytesBegin = framesBegin * frameSize;
long framesEnd = Math.min(ais.getFrameLength(), end);
long skipped = ais.skip(bytesBegin);
if (skipped != bytesBegin) {
throw new IOException("Could not skip to position " + bytesBegin + " in audio stream");
}
@SuppressWarnings("unchecked") // This is checked R = AudioInputStream.class
R r = (R) new AudioInputStream(ais, ais.getFormat(), framesEnd - framesBegin);
return Optional.of(r);
} catch (IOException e) {
return Optional.empty();
}
}
return Optional.empty();
}
@Override
public > boolean isValid(C content) {
D data = content.getData();
if (data.getClass().equals(String.class)) {
String s = (String) data;
return begin >= 0 && end <= s.length();
} else if (data instanceof AudioInputStream) {
try (AudioInputStream ais = (AudioInputStream) data) {
return begin >= 0 && end <= ais.getFrameLength();
} catch (IOException e) {
return false;
}
}
return false;
}
@Override
public String toString() {
return this.getClass().getName() + " [begin=" + begin + ", end=" + end + "]";
}
@Override
public int hashCode() {
return Objects.hash(begin, end);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof SpanBounds)) {
return false;
}
SpanBounds sb = (SpanBounds) o;
return Objects.equals(begin, sb.getBegin()) && Objects.equals(end, sb.getEnd());
}
/**
* If the provided begin and end is within this object's bounds
*
* @param begin the begin offset
* @param end the end offset
* @return true if completely within
*/
public boolean isWithin(int begin, int end) {
return this.begin <= begin && end <= this.end;
}
/**
* If the provided utils bounds is within this object's bounds
*
* @param other the bounds to test against
* @return true if completely within
*/
public boolean isWithin(SpanBounds other) {
return this.isWithin(other.getBegin(), other.getEnd());
}
/**
* Check if this is before (lower position than) the offset
*
* @param offset the offset to test against
* @return true is this is before
*/
public boolean isBefore(int offset) {
return getEnd() < offset;
}
/**
* Check if this is before (lower position than) the utils
*
* @param other the bounds to test against
* @return true is this is before
*/
public boolean isBefore(SpanBounds other) {
return isBefore(other.getBegin());
}
/**
* Check if this is after (higher position than) the utils
*
* @param other the bounds to test against
* @return true is this is after
*/
public boolean isAfter(SpanBounds other) {
return isAfter(other.getEnd());
}
/**
* Check if this is after (higher position than) the offset
*
* @param offset the bounds to test against
* @return true is this is after
*/
public boolean isAfter(int offset) {
return getBegin() > offset;
}
/**
* Check if this is same bounds as the utils
*
* @param other the bounds to test against
* @return true if the same
*/
public boolean isSame(SpanBounds other) {
return getBegin() == other.getBegin() && getEnd() == other.getEnd();
}
/**
* Check if the bounds overlaps one another
*
* @param other the bounds to test against
* @return true if the same
*/
public boolean isOverlaps(SpanBounds other) {
return !isAfter(other) && !isBefore(other);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy