diff --git a/openbis-common/source/java/ch/systemsx/cisd/bds/StringUtils.java b/openbis-common/source/java/ch/systemsx/cisd/bds/StringUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..0e6d79a290c6c1d4e968335195da789bcb7a86f9 --- /dev/null +++ b/openbis-common/source/java/ch/systemsx/cisd/bds/StringUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds; + +/** + * Operations on {@link java.lang.String} that are <code>null</code> safe. + * + * @author Christian Ribeaud + */ +public final class StringUtils +{ + public static final String EMPTY_STRING = ""; + + private StringUtils() + { + // Can not be instantiated + } + + /** + * Whether given <var>value</var> is blank or not. + */ + public final static boolean isBlank(final String value) + { + return value == null || value.trim().length() == 0; + } + + /** + * Whether given <var>value</var> is empty or not. + */ + public final static boolean isEmpty(final String value) + { + return value == null || value.length() == 0; + } + + /** Returns an empty if given <var>stringOrNull</var> is <code>null</code>. */ + public final static String emptyIfNull(final String stringOrNull) + { + return stringOrNull == null ? EMPTY_STRING : stringOrNull; + } +} diff --git a/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Channel.java b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Channel.java new file mode 100644 index 0000000000000000000000000000000000000000..028e546ce3dd06c4de8df16b773f766ec5628305 --- /dev/null +++ b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Channel.java @@ -0,0 +1,97 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds.hcs; + + +/** + * A channel is composed of only one child: <code>wavelength</code>. + * <p> + * Each channel has its <code>counter</code> which uniquely identifies it. It implements + * {@link Comparable} based on the <code>wavelength</code> value. + * </p> + * + * @author Christian Ribeaud + */ +public final class Channel implements Comparable<Channel> +{ + static final String CHANNEL = "channel"; + + static final String WAVELENGTH = "wavelength"; + + private final int counter; + + private final int wavelength; + + public Channel(final int counter, final int wavelength) + { + assert counter > 0 : "Given counter must be > 0."; + this.counter = counter; + this.wavelength = wavelength; + } + + public final int getCounter() + { + return counter; + } + + public final int getWavelength() + { + return wavelength; + } + + // + // Object + // + + @Override + public final boolean equals(final Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof Channel == false) + { + return false; + } + final Channel channel = (Channel) obj; + return channel.counter == counter; + } + + @Override + public final int hashCode() + { + return 17 * 37 + counter; + } + + @Override + public final String toString() + { + return CHANNEL + counter + "[" + wavelength + "=" + getWavelength() + "]"; + } + + // + // Comparable + // + + @Override + public final int compareTo(final Channel o) + { + assert o != null : "Unspecified Channel."; + return counter - o.counter; + } +} diff --git a/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Geometry.java b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Geometry.java new file mode 100644 index 0000000000000000000000000000000000000000..31855a613aef87b614d18f8b8827b7aa0fe3f82b --- /dev/null +++ b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Geometry.java @@ -0,0 +1,150 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds.hcs; + + +/** + * A <code>Geometry</code> is composed of 2 dimensions: + * <ul> + * <li>rows</li> + * <li>columns</li> + * </ul> + * <p> + * This class is not <code>abstract</code> but {@link #getGeometryDirectoryName()} must be + * overridden by subclasses in order to work properly. + * </p> + * + * @author Christian Ribeaud + */ +public class Geometry +{ + /** + * The <code>rows</code>-<code>columns</code> separator in the string representation of + * this object. + */ + private static final String X = "x"; + + static final String NOT_POSITIVE = "Given geometry component '%s' must be > 0 (%d <= 0)."; + + final static String ROWS = "rows"; + + final static String COLUMNS = "columns"; + + private final int rows; + + private final int columns; + + public Geometry(final int rows, final int columns) + { + assert columns > 0 : String.format(NOT_POSITIVE, "columns", columns); + this.columns = columns; + assert rows > 0 : String.format(NOT_POSITIVE, "rows", rows); + this.rows = rows; + } + + /** Return the number of columns this <code>Geometry</code> is composed of. */ + public final int getColumns() + { + return columns; + } + + /** Return the number of rows this <code>Geometry</code> is composed of. */ + public final int getRows() + { + return rows; + } + + /** + * Loads a <code>Geometry</code> from given <var>toString</var>. + * + * @param toString the output you get when calling {@link #toString()}. + * @return <code>null</code> if operation fails. + */ + public static Geometry createFromString(final String toString) + { + assert toString != null : "Given string can not be null."; + final int index = toString.indexOf(X); + if (index > -1) + { + try + { + int rows = Integer.parseInt(toString.substring(0, index)); + int columns = Integer.parseInt(toString.substring(index + X.length())); + return new Geometry(rows, columns); + } catch (NumberFormatException ex) + { + // Nothing to do here. + } + } + return null; + } + + /** + * Whether this <code>Geometry</code> contains given <var>location</var>, meaning that it is + * a valid <code>Location</code>. + */ + public final boolean contains(final Location location) + { + assert location != null : "Given location can not be null."; + return location.getX() <= getColumns() && location.getY() <= getRows(); + } + + /** + * Returns the directory name where this <code>Geometry</code> is saved. + * <p> + * Currently this method is not supported and must be implemented. + * </p> + */ + protected String getGeometryDirectoryName() + { + throw new UnsupportedOperationException(); + } + + // + // Object + // + + @Override + public final boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof Geometry == false) + { + return false; + } + final Geometry geometry = (Geometry) obj; + return geometry.rows == rows && geometry.columns == columns; + } + + @Override + public final int hashCode() + { + int hashCode = 17; + hashCode = hashCode * 37 + getRows(); + hashCode = hashCode * 37 + getColumns(); + return hashCode; + } + + @Override + public final String toString() + { + return getRows() + X + getColumns(); + } +} \ No newline at end of file diff --git a/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Location.java b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Location.java new file mode 100644 index 0000000000000000000000000000000000000000..d55369d7de3d8ff1e36d1743d89ffbd9d4df1916 --- /dev/null +++ b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/Location.java @@ -0,0 +1,205 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds.hcs; + +import java.io.Serializable; + +import ch.systemsx.cisd.common.geometry.ConversionUtils; +import ch.systemsx.cisd.common.geometry.Point; + +/** + * A location in (x, y) coordinate space, specified in integer precision. X and Y start from 1. * + * + * @author Christian Ribeaud + */ +public final class Location implements Serializable +{ + private static final long serialVersionUID = 1L; + + static final String NOT_POSITIVE = "Given coordinate '%s' must be > 0 (%d <= 0)."; + + /** + * The <i>x</i> (or <i>column</i>) coordinate. + */ + private final int x; + + /** + * The <i>y</i> (or <i>row</i>) coordinate. + */ + private final int y; + + public Location(final int x, final int y) + { + assert x > 0 : String.format(NOT_POSITIVE, "x", x); + this.x = x; + assert y > 0 : String.format(NOT_POSITIVE, "y", y); + this.y = y; + } + + public static final Location createLocationFromRowAndColumn(final int row, final int column) + { + return new Location(column, row); + } + + /** + * For given <var>position</var> in given <code>geometry</code> returns corresponding + * <code>Location</code>. Position should be greater than 0.<br> + * Assumes that element index grows as column/row numbers grow, so for a 3x2 geometry elements + * would be numbered like:<br> + * 1 2 3<br> + * 4 5 6<br> + * + * @return <code>null</code> if position is out of range. + */ + public static final Location tryCreateLocationFromRowwisePosition(final int position, + final Geometry geometry) + { + return tryCreateLocationFromPosition(position, geometry, false); + } + + /** + * For given <var>position</var> in given <code>geometry</code> returns corresponding + * <code>Location</code>. Position should be greater than 0.<br> + * Assumes that element index grows as row/column numbers grow, so for a 3x2 geometry elements + * would be numbered like:<br> + * 1 3 5<br> + * 2 4 6<br> + * + * @return <code>null</code> if position is out of range. + */ + public static final Location tryCreateLocationFromColumnwisePosition(final int position, + final Geometry geometry) + { + return tryCreateLocationFromPosition(position, geometry, true); + } + + private static final Location tryCreateLocationFromPosition(final int position, + final Geometry geometry, boolean isColumnwise) + { + assert geometry != null : "Given geometry can not be null."; + int rows = geometry.getRows(); + int columns = geometry.getColumns(); + int divisor = (isColumnwise ? rows : columns); + final int max = columns * rows; + // Given position is within the range. + if (position > 0 && position <= max) + { + final int modulo = position % divisor; + final int x = modulo == 0 ? divisor : modulo; + final int y = (int) Math.ceil(position / (float) divisor); + if (isColumnwise) + { + return new Location(y, x); + } else + { + return new Location(x, y); + } + } + return null; + } + + /** + * For given matrix <var>coordinate</var> (<strong>which is given in transposed form</strong>) + * returns corresponding <code>Location</code>. + * + * @return <code>null</code> if given <var>coordinate</var> is not a matrix coordinate. + */ + public static final Location tryCreateLocationFromTransposedMatrixCoordinate( + final String coordinate) + { + try + { + Point point = ConversionUtils.parseSpreadsheetLocation(coordinate); + return new Location(point.getY() + 1, point.getX() + 1); + } catch (IllegalArgumentException ex) + { + return null; + } + } + + /** + * Do the matrix coordinate conversion for coordinates that are specified this way, but in two + * columns. <strong>Note that first the <var>columnCoord</var> is given and then the + * <var>rowCoord</var>. + * + * @return <code>null</code> if given <var>coordinate</var> is not a matrix coordinate. + */ + public static final Location tryCreateLocationFromTransposedSplitMatrixCoordinate( + final String columnCoord, final String rowCoord) + { + return tryCreateLocationFromTransposedMatrixCoordinate(columnCoord + rowCoord); + } + + /** + * For given location returns corresponding matrix coordinate. + */ + public final String createMatrixCoordinateFromLocation() + { + Point point = new Point(getY() - 1, getX() - 1); + return ConversionUtils.convertToSpreadsheetLocation(point); + } + + // + // Object + // + + @Override + public final boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof Location == false) + { + return false; + } + final Location location = (Location) obj; + return location.x == x && location.y == y; + } + + @Override + public final int hashCode() + { + int hashCode = 17; + hashCode = hashCode * 37 + x; + hashCode = hashCode * 37 + y; + return hashCode; + } + + @Override + public final String toString() + { + return "[x=" + x + ",y=" + y + "]"; + } + + /** + * Returns the <i>x</i> (or <i>column</i>) coordinate. + */ + public int getX() + { + return x; + } + + /** + * Returns the <i>y</i> (or <i>row</i>) coordinate. + */ + public int getY() + { + return y; + } +} \ No newline at end of file diff --git a/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/PlateGeometry.java b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/PlateGeometry.java new file mode 100644 index 0000000000000000000000000000000000000000..6396ec2342cb3f75eb45f07974e4334cf8cb7a5d --- /dev/null +++ b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/PlateGeometry.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds.hcs; + + +/** + * An <code>AbstractGeometry</code> implementation suitable for <i>Plate</i>. + * + * @author Christian Ribeaud + */ +public final class PlateGeometry extends Geometry +{ + + /** + * Directory name which contains the plate geometry. + * <p> + */ + public static final String PLATE_GEOMETRY = "plate_geometry"; + + public PlateGeometry(final Geometry geometry) + { + this(geometry.getRows(), geometry.getColumns()); + } + + public PlateGeometry(final int rows, final int columns) + { + super(rows, columns); + } + + /** + * Creates a new <code>WellGeometry</code> from given <var>toString</var>. + */ + public final static Geometry createFromString(final String toString) + { + return new PlateGeometry(Geometry.createFromString(toString)); + } + + // + // Geometry + // + + @Override + protected final String getGeometryDirectoryName() + { + return PLATE_GEOMETRY; + } + +} diff --git a/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/WellGeometry.java b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/WellGeometry.java new file mode 100644 index 0000000000000000000000000000000000000000..55830ba4c77f6f60a47fa3c6e7f52c3c1e4b5ccd --- /dev/null +++ b/openbis-common/source/java/ch/systemsx/cisd/bds/hcs/WellGeometry.java @@ -0,0 +1,62 @@ +/* + * Copyright 2007 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.bds.hcs; + + +/** + * An <code>AbstractGeometry</code> implementation suitable for <i>Well</i>. + * + * @author Christian Ribeaud + */ +public final class WellGeometry extends Geometry +{ + + /** + * Directory name which contains the well geometry. + * <p> + */ + public static final String WELL_GEOMETRY = "well_geometry"; + + public WellGeometry(final Geometry geometry) + { + this(geometry.getRows(), geometry.getColumns()); + } + + public WellGeometry(final int rows, final int columns) + { + super(rows, columns); + } + + /** + * Creates a new <code>WellGeometry</code> from given <var>toString</var>. + */ + public final static Geometry createFromString(final String toString) + { + return new WellGeometry(Geometry.createFromString(toString)); + } + + // + // Geometry + // + + @Override + protected final String getGeometryDirectoryName() + { + return WELL_GEOMETRY; + } + +}