package org.eclipse.mdm.openatfx.mdf.mdf4; | |
import java.io.IOException; | |
import java.nio.ByteBuffer; | |
import java.nio.ByteOrder; | |
import java.nio.channels.SeekableByteChannel; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.List; | |
public class CABLOCK extends BLOCK | |
{ | |
public static final String BLOCK_ID = "##CA"; | |
/** | |
* Array of composed elements: Pointer to a CNBLOCK for array of structures, or to a CABLOCK for array of arrays (can be NIL). | |
* If a CABLOCK is referenced, it must use the "CN template" storage type (ca_storage = 0). | |
*/ | |
private long lnkComposition; | |
/** | |
* List of links to either a data block (DTBLOCK or DZBLOCK for this block type) or a data list block (DLBLOCK of data blocks or its HLBLOCK) for each element. | |
* <p> | |
* Only present for storage type "DG template" (ca_storage = 2)! | |
* </p> | |
* <p> | |
* A link in this list may only be NIL if the cycle count of the respective element is 0: ca_data[k] = NIL => ca_cycle_count[k] = 0<br> | |
* The links are stored line-oriented, i.e. element k uses ca_data[k]. The size of the list must be equal to Π N(d), | |
* i.e. to the product of the number of elements per dimension N(d) over all dimensions D.<br> | |
* </p> | |
* <p> | |
* Note: link ca_data[0] must be equal to dg_data link of the parent DGBLOCK. | |
* </p> | |
*/ | |
private long[] lnksData; | |
/** | |
* References to channels for size signal of each dimension (can be NIL). | |
* <p> | |
* Only present if "dynamic size" flag (bit 0) is set. | |
* </p> | |
* <p> | |
* Each reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel | |
* (either all three links are assigned or NIL). Thus the links have the following order:<br> | |
* DGBLOCK for size signal of dimension 1<br> | |
* CGBLOCK for size signal of dimension 1<br> | |
* CNBLOCK for size signal of dimension 1<br> | |
* …<br> | |
* DGBLOCK for size signal of dimension D<br> | |
* CGBLOCK for size signal of dimension D<br> | |
* CNBLOCK for size signal of dimension D<br> | |
* </p> | |
* <p> | |
* The size signal can be used to model arrays whose number of elements per dimension can vary over time. | |
* If a size signal is specified for a dimension, the number of elements for this dimension at some point in time | |
* is equal to the value of the size signal at this time (i.e. for time-synchronized signals, | |
* the size signal value with highest time stamp less or equal to current time stamp). | |
* If the size signal has no recorded signal value for this time (yet), assume 0 as size. | |
* </p> | |
* <p> | |
* Since each referenced channel defines the current size of a dimension, its physical values must be Integer values ≥ 0 and ≤ N(d), | |
* i.e. the values must not exceed the maximum number of elements for the respective dimension. | |
* Usually, a size signal should have some Integer data type (cn_data_type ≤ 3) without conversion rule and without unit. | |
* </p> | |
* <p> | |
* Since the size signal and the array signal must be synchronized, their channel groups must contain at least one common master channel type. | |
* </p> | |
* <p> | |
* Note: the "positions" of the array elements are fixed as defined for the maximum allowed array size. | |
* They will not change when the array is reduced by a size signal value less than N(d). | |
* However, the "removed" array elements must not be considered. | |
* For row-oriented CN template storage, the elements would be stored in the record in following order:<br> | |
* a11, a12, a13, a21, a22, a23<br> | |
* Assume that the size of the second dimension is reduced from 3 to 2. Then the values of elements a13 and a23 | |
* will be undefined and should not be used. However, the other elements stay at the same position (Byte offset).<br> | |
* a11, a12, [a13], a21, a22, [a23] | |
* </p> | |
*/ | |
private long[] lnksDynamicSize; | |
/** | |
* Reference to channels for input quantity signal for each dimension (can be NIL). | |
* <p> | |
* Only present if "input quantity" flag (bit 1) is set. | |
* </p> | |
* <p> | |
* Reference to channels for input quantity signal for each dimension (can be NIL). | |
* Each reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and | |
* CNBLOCK for the channel (either all three links are assigned or NIL). Thus the links have the following order:<br> | |
* DGBLOCK for input quantity of dimension 1<br> | |
* CGBLOCK for input quantity of dimension 1<br> | |
* CNBLOCK for input quantity of dimension 1<br> | |
* …<br> | |
* DGBLOCK for input quantity of dimension D<br> | |
* CGBLOCK for input quantity of dimension D<br> | |
* CNBLOCK for input quantity of dimension D<br> | |
* </p> | |
* <p> | |
* Since the input quantity signal and the array signal must be synchronized, | |
* their channel groups must contain at least one common master channel type. | |
* </p> | |
* <p> | |
* The input quantity often is denoted as "working point" because it is used for look-up of a value in the array.<br> | |
* For array type "look-up", the value of the input quantity will be used for looking up a value in the | |
* scaling axis of the respective dimension (either axis channel or fixed axis values listed in ca_axis_value list).<br> | |
* For array type "scaling axis", the value of the input quantity will be used for looking up a value in the axis itself. | |
* The input quantity should have the same physical unit as the axis it is applied to. | |
* </p> | |
*/ | |
private long[] lnksInputQuantity; | |
/** | |
* Reference to channel for output quantity (can be NIL). | |
* <p> | |
* Only present if "output quantity" flag (bit 2) is set. | |
* </p> | |
* <p> | |
* The reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel | |
* (either all three links are assigned or NIL). Since the output quantity signal and the array signal must be synchronized, | |
* their channel groups must contain at least one common master channel type. | |
* For array type "look-up", the output quantity is the result of the complete look-up. | |
* The output quantity should have the same physical unit as the array elements of the array that references it. | |
* </p> | |
*/ | |
private long[] lnksOutputQuantity; | |
/** | |
* Reference to channel for comparison quantity (can be NIL). | |
* <p> | |
* Only present if "comparison quantity" flag (bit 3) is set. | |
* </p> | |
* <p> | |
* The reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel | |
* (either all three links are assigned or NIL). Since the comparison quantity signal and the array signal must be synchronized, | |
* their channel groups must contain at least one common master channel type. | |
* The comparison quantity should have the same physical unit as the array elements. | |
* </p> | |
*/ | |
private long[] lnksComparisonQuantity; | |
/** | |
* Pointer to a conversion rule (CCBLOCK) for the axis of each dimension. If a link NIL a 1:1 conversion must be used for this axis. | |
* <p> | |
* Only present if "axis" flag (bit 4) is set. | |
* </p> | |
* <p> | |
* If the "fixed axis" flag (Bit 5) is set, the conversion must be applied to the fixed axis values of the respective axis/dimension | |
* (ca_axis_value list stores the raw values as REAL). If the link to the CCBLOCK is NIL already the physical values are stored | |
* in the ca_axis_value list. If the "fixed axes" flag (Bit 5) is not set, the conversion must be applied to the raw values | |
* of the respective axis channel, i.e. it overrules the conversion specified for the axis channel, even if the ca_axis_conversion link is NIL!<br> | |
* </p> | |
* <p> | |
* Note: ca_axis_conversion may reference the same CCBLOCK as referenced by the respective axis channel ("sharing" of CCBLOCK). | |
* </p> | |
*/ | |
private long[] lnksConversionRule; | |
/** | |
* References to channels for axis of respective dimension (can be NIL). | |
* <p> | |
* Only present if "axis" flag (bit 4) is set and "fixed axes flag" (bit 5) is not set. | |
* </p> | |
* <p> | |
* Each reference is a link triple with pointer to parent DGBLOCK, parent CGBLOCK and CNBLOCK for the channel | |
* (either all three links are assigned or NIL). Thus the links have the following order:<br> | |
* DGBLOCK for axis of dimension 1<br> | |
* CGBLOCK for axis of dimension 1<br> | |
* CNBLOCK for axis of dimension 1<br> | |
* …<br> | |
* DGBLOCK for axis of dimension D<br> | |
* CGBLOCK for axis of dimension D<br> | |
* CNBLOCK for axis of dimension D<br> | |
* </p> | |
* <p> | |
* Each referenced channel must be an array of type "scaling axis" or "interval axis".<br> | |
* For a "scaling axis" the maximum number of elements (ca_dim_size[0] in axis) must not be less than the maximum number of elements | |
* of the respective dimension d in the array which references it (ca_dim_size[d-1]).<br> | |
* For an "interval axis" the number of elements must be exactly one more than respective dimension d | |
* in the "classification result" array (ca_dim_size[d-1]+1). | |
* </p> | |
* <p> | |
* If an axis signal must be synchronized with the array signal (e.g. for dynamic size axis), | |
* the channel groups of the axis and the array signal must contain at least one common master channel type. | |
* If a fixed axis is stored by an axis channel, its channel group should only contain one cycle. | |
* </p> | |
* <p> | |
* If a reference to an axis is NIL, there is no axis and a zero-based index should be used for axis values. | |
* </p> | |
*/ | |
private long[] lnksScalingAxis; | |
/** | |
* <b>Array type</b> (defines semantic of the array) | |
* <p>Attention: for some array types certain features are not allowed (see ca_flags)</p> | |
* <p><ul> | |
* <li>0 = Array<br> | |
* The array is a simple D-dimensional value array (value block) without axes and without input/output/comparison quantities. | |
* | |
* <li>1 = Scaling axis<br> | |
* The array is a scaling axis (1-dimensional vector), possibly referenced by one or more arrays. | |
* If referenced by an array of type "look-up", the axis itself may have a scaling axis (e.g. CURVE_AXIS) and an own input quantity. | |
* | |
* <li>2 = Look-up<br> | |
* The array is a D-dimensional array with axes. It can have input/output/comparison quantities. | |
* | |
* <li>3 = Interval axis<br> | |
* The array is an axis (1-dimensional vector) defining interval ranges as "axis points". | |
* It can be referenced by one or more arrays of type "classification result" (ca_type = 4). | |
* The interval axis must have at least two elements (ca_dim_size[0] = N(0) > 1) | |
* and the physical values of the elements must be strictly monotonous increasing over the element index, | |
* i.e. ai < ai+1 for 1 ≤ i < N(0)<br> | |
* In contrast to a scaling axis (ca_type = 1), an interval axis always has one element more than the number of elements | |
* for the respective dimension of the classification result array which references it. | |
* The elements of the class interval axis define the borders of interval ranges that are seen as axis points. | |
* Depending on the "left-open interval" flag (bit 7 in ca_flags), the intervals are defined as<br> | |
* ]ao,a1], ]a1,a2], …, ]aN(0)-1,aN(0)] (flag set)<br> | |
* [ao,a1[, [a1,a2[, …, [aN(0)-1,aN(0)[ (flag not set)<br> | |
* valid since MDF 4.1.0, should not occur for earlier versions | |
* | |
* <li>4 = Classification result<br> | |
* The array is a D-dimensional array containing classification results. | |
* It can have scaling axes (ca_type = 1) or interval axes (ca_type = 3), even mixed. | |
* Details about the classification method and parameters can be given as XML tags in cn_md_comment | |
* of the parent CN block and the CN blocks of the axes.<br> | |
* valid since MDF 4.1.0, should not occur for earlier versions | |
* </ul><p> | |
*/ | |
private byte arrayType; | |
public static final byte ARRAYTYPE_ARRAY = 1; | |
public static final byte ARRAYTYPE_SCALING_AXIS = 1 << 1; | |
public static final byte ARRAYTYPE_LOOKUP = 1 << 2; | |
public static final byte ARRAYTYPE_INTERVAL_AXIS = 1 << 3; | |
public static final byte ARRAYTYPE_CLASSIFICATION_RESULT = 1 << 4; | |
/** | |
* <b>Storage type</b (defines how the element values are stored) | |
* <p><ul> | |
* <li>0 = CN template<br> | |
* Values of all elements of the array are stored in the same record (i.e. all elements are measured together). | |
* The parent CNBLOCK defines the first element in the record (k = 0). | |
* All other elements are defined by the same CNBLOCK except that the values for cn_byte_offset | |
* and cn_inval_bit_pos change for each component. | |
* | |
* <li>1 = CG template<br> | |
* Value for each element of the array is stored in a separate record (i.e. elements are stored independently of each other). | |
* All records are stored in the same data block referenced by the parent DGBLOCK. | |
* As a consequence the data group (and thus the MDF file) is unsorted. | |
* All elements have exactly the same record layout specified by the parent CGBLOCK. | |
* However, each element uses a different cycle count (given by ca_cycle_count[k]) | |
* and a different record ID which must be calculated by "auto-increment" of the record ID of the parent CGBLOCK: | |
* cg_record_id + k.<br> Since ca_cycle_count[0] must be equal to cg_cycle_count of the parent CGBLOCK, | |
* the parent CNBLOCK of the CABLOCK automatically describes the first array element (k = 0). | |
* When sorting a data group, a CABLOCK with "CG template" storage will be converted to a CABLOCK with "DG template" storage. | |
* | |
* <li>2 = DG template<br> | |
* Similar to CG template, the value of each element of the array is stored in a separate record (i.e. elements are stored independently of each other). | |
* However, the records for each element are stored in separate data blocks referenced by the list of links in ca_data. | |
* Similar to "CG template" storage, all elements have exactly the same record layout (defined by the parent CGBLOCK) | |
* but a different cycle count (specified by ca_cycle_count[k]).<br> | |
* Since ca_cycle_count[0] must be equal to cg_cycle_count of the parent CGBLOCK, and ca_data[0] must be equal to | |
* dg_data of the parent DGBLOCK, the parent CNBLOCK of the CABLOCK automatically describes the first array element (k = 0). | |
* </ul></p> | |
*/ | |
private byte storageType; | |
public static final byte STORAGETYPE_CN_TEMPLATE = 1; | |
public static final byte STORAGETYPE_CG_TEMPLATE = 1 << 1; | |
public static final byte STORAGETYPE_DG_TEMPLATE = 1 << 2; | |
/** | |
* <b>Flags (0-based!)</b> | |
* <p> The value contains the following bit flags (Bit 0 = LSB): | |
* <ul> | |
* <li>Bit 0: dynamic size flag<br> | |
* If set, the number of scaling points for the array is not fixed but can vary over time. | |
* Can only be set for array types "look-up" and "scaling axis". | |
* | |
* <li>Bit 1: input quantity flag<br> | |
* If set, a channel for the input quantity is specified for each dimension by ca_input_quantity. | |
* Can only be set for array types "look-up" and "scaling axis". | |
* | |
* <li>Bit 2: output quantity flag<br> | |
* If set, a channel for the output quantity is specified by ca_output_quantity. Can only be set for array type "look-up". | |
* | |
* <li>Bit 3: comparison quantity flag<br> | |
* If set, a channel for the comparison quantity is specified by ca_comparison_quantity. Can only be set for array type "look-up". | |
* | |
* <li>Bit 4: axis flag<br> | |
* If set, a scaling axis is given for each dimension of the array, either as fixed or as dynamic axis, | |
* depending on "fixed axis" flag (bit 5). Can only be set for array types "look-up", "scaling axis" and "classification result". | |
* | |
* <li>Bit 5: fixed axis flag<br> | |
* If set, the scaling axis is fixed and the axis points are stored as raw values in ca_axis_value list. | |
* If not set, the scaling axis may vary over time and the axis points are stored as channel referenced in ca_axis for each dimension. | |
* Only relevant if "axis" flag (bit 4) is set. Can only not be set for array types "look-up" and "scaling axis". | |
* | |
* <li>Bit 6: inverse layout flag<br> | |
* If set, the record layout is "column oriented" instead of "row oriented". | |
* Only relevant for "CN template" storage type and for number of dimensions > 1. | |
* | |
* <li>Bit 7: left-open interval flag<br> | |
* If set, the interval ranges for the class interval axes are left-open and right-closed, i.e. ]a,b] = {x | a < x ≤ b}.<br> | |
* If not set, the interval ranges for the class interval axes are left-closed and right-open, i.e. [a,b[ = {x | a ≤ x < b}.<br> | |
* Note that opening or closing is irrelevant for infinite endpoints (there can only be -INF for the left border of the | |
* very first interval, or +INF for right border of the very last interval). | |
* Only relevant for array type "interval axes".<br> | |
* valid since MDF 4.1.0, should not be set for earlier versions | |
* </ul></p> | |
*/ | |
private long flags; | |
public static final byte FLAG_DYNAMIC_SIZE = 1; | |
public static final byte FLAG_INPUT_QUANTITY_DEFINED = 1 << 1; | |
public static final byte FLAG_OUTPUT_QUANTITY_DEFINED = 1 << 2; | |
public static final byte FLAG_COMPARISON_QUANTITY_DEFINED = 1 << 3; | |
public static final byte FLAG_SCALING_AXIS_DEFINED = 1 << 4; | |
public static final byte FLAG_FIXED_AXES = 1 << 5; | |
public static final byte FLAG_INVERSE_LAYOUT = 1 << 6; | |
public static final byte FLAG_LEFT_OPEN_INTERVALS = -128; | |
/** | |
* Base factor for calculation of Byte offsets for "CN template" storage type. | |
* <p>The absolute value of ca_byte_offset_base should be larger than or equal to the size of Bytes required | |
* to store a component channel value in the record (all must have the same size). | |
* If the values are equal, then the component values are stored contiguously, i.e.next to each other without gaps. | |
* If ca_byte_offset_base is negative, the component values are stored with decreasing index.</p> | |
*/ | |
private long byteOffsetBase; | |
/** | |
* Base factor for calculation of invalidation bit positions for CN template storage type. | |
* <p>For a simple array which is not part of a nested composition, | |
* ca_inval_bit_pos_base = 1 means that the invalidation bits for the component channels are stored without gaps and | |
* ca_inval_bit_pos_base = 0 means that all component channels use the same invalidation bit in the record. | |
*/ | |
private long invalBitPosBase; | |
/** | |
* Maximum number of elements for each dimension N(d). | |
* <p>N(d) > 0 for all d. <br>For array type "interval axis", there must be at least two elements, i.e. N(0) > 1.</p> | |
*/ | |
private long[] dimSizes; | |
/** | |
* Number of dimensions D > 0<br> | |
* For array type "scaling axis" or "interval axis", D must be 1. | |
*/ | |
private int nrOfDimensions; | |
/** | |
* List of raw values for (fixed) axis points of each axis. | |
* <p>Only present if "fixed axes" flag (bit 5) is set!</p> | |
* <p> | |
* List of raw values for (fixed) axis points of each axis. The axis points are stored in a linear sequence for each dimension:<br> | |
* A1(1), A1(2), ..., A1(N(1)),<br> | |
* A2(1), A2(2), ..., A2(N(2)),<br> | |
* ...<br> | |
* AD(1), AD(2), ..., AD(N(D))<br> | |
* where Ad(j) is axis point j of dimension d and N(d) is the number of elements for dimension d.<br> | |
* Example for D = 2 dimensions (as explained later Y axis for A1 and X axis for A2):<br> | |
* Y(1), Y(2), ..., Y(N(1)),<br> | |
* X(1), X(2), ..., X(N(2))<br> | |
* The size of the list must be equal to Σ N(d) = the sum of the number of elements per dimension N(d) over all dimensions D. | |
* To convert the raw axis values to physical values, the conversion rule of the respective dimension must be applied | |
* (CCBLOCK referenced by ca_cc_axis_conversion[i]). If the CCBLOCK link of a dimension is NIL, | |
* the raw values are equal to the physical values (1:1 conversion). | |
* </p> | |
*/ | |
private double[] axisValues; | |
/** | |
* List of cycle counts for each element in case of "CG/DG template" storage. | |
* <p>Only present for storage types "CG/DG template"!</p> | |
* <p> | |
* List of cycle counts for each element in case of "CG/DG template" storage. The offsets are stored line-oriented, | |
* i.e. element k uses ca_cycle_count[k]<br> | |
* The size of the list must be equal to Π N(d) = the product of the number of elements per dimension N(d) over all dimensions D.<br> | |
* Note: ca_cycle_count[0] must be equal to cg_cycle_count of parent CGBLOCK! | |
* </p> | |
*/ | |
private long[] cycleCounts; | |
private CABLOCK(SeekableByteChannel sbc, long pos) | |
{ | |
super(sbc, pos); | |
} | |
/** | |
* Reads a CABLOCK from the channel starting at current channel position. | |
* | |
* @param channel | |
* The channel to read from. | |
* @param pos | |
* The position | |
* @return The block data. | |
* @throws IOException | |
* The exception. | |
*/ | |
public static CABLOCK read(SeekableByteChannel channel, long pos) throws IOException { | |
CABLOCK block = new CABLOCK(channel, pos); | |
// read block header | |
ByteBuffer bb = ByteBuffer.allocate(24); | |
bb.order(ByteOrder.LITTLE_ENDIAN); | |
channel.position(pos); | |
channel.read(bb); | |
bb.rewind(); | |
// CHAR 4: Block type identifier | |
block.setId(MDF4Util.readCharsISO8859(bb, 4)); | |
if (!block.getId().equals(BLOCK_ID)) { | |
throw new IOException("Wrong block type - expected '" + BLOCK_ID + "', found '" + block.getId() + "'"); | |
} | |
// BYTE 4: Reserved used for 8-Byte alignment | |
bb.get(new byte[4]); | |
// UINT64: Length of block | |
block.setLength(MDF4Util.readUInt64(bb)); | |
// UINT64: Number of links | |
block.setLinkCount(MDF4Util.readUInt64(bb)); | |
// read block data | |
bb = ByteBuffer.allocate((int) block.getLength() - 24); | |
bb.order(ByteOrder.LITTLE_ENDIAN); | |
channel.position(pos + 24); | |
channel.read(bb); | |
bb.rewind(); | |
// read links | |
long[] lnks = new long[(int) block.getLinkCount()]; | |
for (int i = 0; i < lnks.length; i++) { | |
lnks[i] = MDF4Util.readLink(bb); | |
} | |
// read data | |
// UINT8: Array type (ca_type) | |
byte arrayType = MDF4Util.readUInt8(bb); | |
block.setArrayType(arrayType); | |
// UINT8: Storage type (ca_storage) | |
byte storageTyp = MDF4Util.readUInt8(bb); | |
block.setStorageType(storageTyp); | |
// UINT16: Number of dimensions (ca_ndim) | |
int nrOfDims = MDF4Util.readUInt16(bb); | |
block.setNrOfDimensions(nrOfDims); | |
// UINT32: Flags (ca_flags) | |
long readFlags = MDF4Util.readUInt32(bb); | |
block.setFlags(readFlags); | |
// INT32: Byte offset base (ca_byte_offset_base) | |
block.setByteOffsetBase(MDF4Util.readInt32(bb)); | |
// UINT32: Invalidation bit position base (ca_inval_bit_pos_base) | |
block.setInvalidationBitPositionBase(MDF4Util.readUInt32(bb)); | |
// UINT64: Maximum size of each dimension (ca_dim_size) | |
List<Long> dimSizesList = new ArrayList<>(); | |
for (int i = 0; i < nrOfDims; i++) { | |
dimSizesList.add(MDF4Util.readUInt64(bb)); | |
} | |
block.setDimSizes(dimSizesList); | |
long sumNumberOfValuesPerDimension = dimSizesList.stream().mapToLong(Long::longValue).sum(); | |
long productNumberOfValuesPerDimension = dimSizesList.stream().mapToLong(Long::longValue).reduce(1, (a, b) -> a * b); | |
// REAL: Axis value for each dimension's number of values (ca_axis_value) | |
if (isBitSet(readFlags, FLAG_FIXED_AXES)) { | |
List<Double> axisValuesList = new ArrayList<>(); | |
for (long i = 0; i < sumNumberOfValuesPerDimension; i++) { | |
axisValuesList.add(MDF4Util.readReal(bb)); | |
} | |
block.setAxisValues(axisValuesList); | |
} | |
// UINT64: Cycle counts (ca_cycle_count) | |
if (isBitSet(storageTyp, STORAGETYPE_CG_TEMPLATE) || isBitSet(storageTyp, STORAGETYPE_DG_TEMPLATE)) { | |
List<Long> cycleCountsList = new ArrayList<>(); | |
for (long i = 0; i < productNumberOfValuesPerDimension; i++) { | |
cycleCountsList.add(MDF4Util.readUInt64(bb)); | |
} | |
block.setCycleCounts(cycleCountsList); | |
} | |
// extract links after reading data | |
int currentLinkIndex = 0; | |
// ca_composition | |
long lnkNestedComposition = lnks[currentLinkIndex++]; | |
block.setLnkComposition(lnkNestedComposition); | |
// ca_data | |
if (isBitSet(storageTyp, STORAGETYPE_DG_TEMPLATE)) { | |
List<Long> lnkDataList = new ArrayList<>(); | |
for (long i = 0; i < productNumberOfValuesPerDimension; i++) { | |
lnkDataList.add(lnks[currentLinkIndex++]); | |
} | |
block.setLnksData(lnkDataList); | |
} | |
// ca_dynamic_size | |
if (isBitSet(readFlags, FLAG_DYNAMIC_SIZE)) { | |
List<Long> lnkDynamicSizeList = new ArrayList<>(); | |
for (long i = 0; i < nrOfDims * 3; i++) { | |
lnkDynamicSizeList.add(lnks[currentLinkIndex++]); | |
} | |
block.setLnksDynamicSize(lnkDynamicSizeList); | |
} | |
// ca_input_quantity | |
if (isBitSet(readFlags, FLAG_INPUT_QUANTITY_DEFINED)) { | |
List<Long> lnkInputQuantityList = new ArrayList<>(); | |
for (long i = 0; i < nrOfDims * 3; i++) { | |
lnkInputQuantityList.add(lnks[currentLinkIndex++]); | |
} | |
block.setLnksInputQuantities(lnkInputQuantityList); | |
} | |
// ca_output_quantity | |
if (isBitSet(readFlags, FLAG_OUTPUT_QUANTITY_DEFINED)) { | |
List<Long> lnkOutputQuantityList = new ArrayList<>(); | |
for (long i = 0; i < 3; i++) { | |
lnkOutputQuantityList.add(lnks[currentLinkIndex++]); | |
} | |
block.setLnksOutputQuantity(lnkOutputQuantityList); | |
} | |
// ca_comparison_quantity | |
if (isBitSet(readFlags, FLAG_COMPARISON_QUANTITY_DEFINED)) { | |
List<Long> lnkComparisonQuantityList = new ArrayList<>(); | |
for (long i = 0; i < 3; i++) { | |
lnkComparisonQuantityList.add(lnks[currentLinkIndex++]); | |
} | |
block.setLnksComparisonQuantity(lnkComparisonQuantityList); | |
} | |
// ca_cc_axis_conversion | |
if (isBitSet(readFlags, FLAG_SCALING_AXIS_DEFINED)) { | |
List<Long> lnkConversionRuleList = new ArrayList<>(); | |
for (long i = 0; i < nrOfDims; i++) { | |
lnkConversionRuleList.add(lnks[currentLinkIndex++]); | |
} | |
block.setLnksConversionRule(lnkConversionRuleList); | |
} | |
// ca_axis | |
if (isBitSet(readFlags, FLAG_SCALING_AXIS_DEFINED) && !isBitSet(readFlags, FLAG_FIXED_AXES)) { | |
List<Long> lnkScalingAxisList = new ArrayList<>(); | |
for (long i = 0; i < nrOfDims * 3; i++) { | |
lnkScalingAxisList.add(lnks[currentLinkIndex++]); | |
} | |
block.setLnksScalingAxis(lnkScalingAxisList); | |
} | |
// throw exception if found unsupported features | |
if (lnkNestedComposition > 0) { | |
throw new IOException("Nested composition is not yet supported! Found at CABlock: [" + block + "]"); | |
} | |
if (isBitSet(arrayType, ARRAYTYPE_INTERVAL_AXIS)) { | |
throw new IOException("Array type 'Interval Axis' is not yet supported! Found at CABlock: [" + block + "]"); | |
} | |
else if (isBitSet(arrayType, ARRAYTYPE_CLASSIFICATION_RESULT)) { | |
throw new IOException("Array type 'Classification Result' is not yet supported! Found at CABlock: [" + block + "]"); | |
} | |
if (isBitSet(storageTyp, STORAGETYPE_CG_TEMPLATE)) { | |
throw new IOException("Storage type 'CG Template' is not yet supported! Found at CABlock: [" + block + "]"); | |
} | |
else if (isBitSet(storageTyp, STORAGETYPE_DG_TEMPLATE)) { | |
throw new IOException("Storage type 'DG Template' is not yet supported! Found at CABlock: [" + block + "]"); | |
} | |
return block; | |
} | |
private void setArrayType(byte arrayType) { | |
this.arrayType = arrayType; | |
} | |
private void setStorageType(byte storageType) { | |
this.storageType = storageType; | |
} | |
private void setNrOfDimensions(int nrOfDimensions) { | |
this.nrOfDimensions = nrOfDimensions; | |
} | |
private void setFlags(long flags) { | |
this.flags = flags; | |
} | |
private void setByteOffsetBase(long byteOffsetBase) { | |
this.byteOffsetBase = byteOffsetBase; | |
} | |
private void setInvalidationBitPositionBase(long invalBitPosBase) { | |
this.invalBitPosBase = invalBitPosBase; | |
} | |
private void setDimSizes(List<Long> dimSizesList) { | |
this.dimSizes = dimSizesList.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setAxisValues(List<Double> axisValues) { | |
this.axisValues = axisValues.stream().mapToDouble(i -> i).toArray(); | |
} | |
private void setCycleCounts(List<Long> cycleCounts) { | |
this.cycleCounts = cycleCounts.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setLnkComposition(long lnkComposition) { | |
this.lnkComposition = lnkComposition; | |
} | |
private void setLnksData(List<Long> lnksData) { | |
this.lnksData = lnksData.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setLnksDynamicSize(List<Long> lnksDynamicSize) { | |
this.lnksDynamicSize = lnksDynamicSize.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setLnksInputQuantities(List<Long> lnksInputQuantities) { | |
this.lnksInputQuantity = lnksInputQuantities.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setLnksOutputQuantity(List<Long> lnksOutputQuantity) { | |
this.lnksOutputQuantity = lnksOutputQuantity.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setLnksComparisonQuantity(List<Long> lnksComparisonQuantity) { | |
this.lnksComparisonQuantity = lnksComparisonQuantity.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setLnksConversionRule(List<Long> lnksConversionRule) { | |
this.lnksConversionRule = lnksConversionRule.stream().mapToLong(i -> i).toArray(); | |
} | |
private void setLnksScalingAxis(List<Long> lnksScalingAxis) { | |
this.lnksScalingAxis = lnksScalingAxis.stream().mapToLong(i -> i).toArray(); | |
} | |
/** | |
* @return the arrayType | |
*/ | |
public byte getArrayType() | |
{ | |
return arrayType; | |
} | |
/** | |
* @return the storageType | |
*/ | |
public byte getStorageType() | |
{ | |
return storageType; | |
} | |
/** | |
* @return the flags | |
*/ | |
public long getFlags() | |
{ | |
return flags; | |
} | |
/** | |
* @return the byteOffsetBase | |
*/ | |
public long getByteOffsetBase() | |
{ | |
return byteOffsetBase; | |
} | |
/** | |
* @return the invalBitPosBase | |
*/ | |
public long getInvalBitPosBase() | |
{ | |
return invalBitPosBase; | |
} | |
/** | |
* @return the dimSize for given dimension index | |
*/ | |
public long getDimSize(int dimIndex) | |
{ | |
return dimSizes[dimIndex]; | |
} | |
/** | |
* @return all value sizes of dimensions | |
*/ | |
public long[] getDimSizes() | |
{ | |
return dimSizes; | |
} | |
/** | |
* @return the nrOfDimensions | |
*/ | |
public int getNrOfDimensions() | |
{ | |
return nrOfDimensions; | |
} | |
/** | |
* @return the axisValues | |
*/ | |
public double[] getAxisValues() | |
{ | |
return axisValues; | |
} | |
/** | |
* @return the cycleCounts | |
*/ | |
public long[] getCycleCounts() | |
{ | |
return cycleCounts; | |
} | |
public BLOCK getCompositionBlock() throws IOException | |
{ | |
if (lnkComposition > 0) { | |
String blockType = getBlockType(sbc, lnkComposition); | |
BLOCK compositionBlock = null; | |
// link points to a CNBLOCK | |
if (blockType.equals(CNBLOCK.BLOCK_ID)) { | |
compositionBlock = CNBLOCK.read(sbc, lnkComposition); | |
} | |
// link points to CABLOCK | |
else if (blockType.equals(CABLOCK.BLOCK_ID)) { | |
compositionBlock = CABLOCK.read(sbc, lnkComposition); | |
} | |
// unknown | |
else { | |
throw new IOException("Unsupported block type for Composition: " + blockType); | |
} | |
throw new IOException("Composition of CABLOCKs is not yet supported! Found the following block: " + compositionBlock); | |
} | |
return null; | |
} | |
/** | |
* Checks if the given bitConstant is set in the given bitfield. | |
* | |
* @param bits | |
* @param bitConstant | |
* @return | |
*/ | |
private static boolean isBitSet(long bits, byte bitConstant) { | |
return (bits & bitConstant) != 0; | |
} | |
/** | |
* Returns the requested flag value. | |
* | |
* @param flagConstant one of the flag constants given in this class | |
* @return | |
*/ | |
public boolean isFlagSet(byte flagConstant) { | |
return (flags & flagConstant) != 0; | |
} | |
/** | |
* This method should only be called if the flag FLAG_SCALING_AXIS_DEFINED is | |
* set. If this is true and null is returned here, it | |
* | |
* @param dimIndex | |
* @return | |
*/ | |
public long getConversionRuleOffsetForDimension(int dimIndex) | |
{ | |
if (lnksConversionRule != null && dimIndex < nrOfDimensions && lnksConversionRule.length == 3 * nrOfDimensions) | |
{ | |
return lnksConversionRule[nrOfDimensions * 3 - 1]; | |
} | |
return -1; | |
} | |
/** | |
* This method should only be called if the flag FLAG_SCALING_AXIS_DEFINED is | |
* set and FLAG_FIXED_AXIS is not set. | |
* | |
* @param dimIndex | |
* the index of the dimension to get the scaling axis offsets for | |
* @return a {@link BlockReferenceTriple} containing the offsets to read the | |
* CNBLOCK defining the scaling axis for the dimension with the | |
* given index or null if none defined | |
*/ | |
public BlockReferenceTriple getScalingAxisOffsetsForDimension(int dimIndex) | |
{ | |
return createReferenceTriple(dimIndex, lnksScalingAxis); | |
} | |
/** | |
* This method should only be called if the flag FLAG_INPUT_QUANTITY_DEFINED | |
* is set. | |
* | |
* @param dimIndex | |
* the index of the dimension to get the input quantity offsets for | |
* @return a {@link BlockReferenceTriple} containing the offsets to read the | |
* CNBLOCK defining the input quantity for the dimension with the | |
* given index or null if none defined | |
*/ | |
public BlockReferenceTriple getInputQuantityOffsetsForDimension(int dimIndex) | |
{ | |
return createReferenceTriple(dimIndex, lnksInputQuantity); | |
} | |
/** | |
* This method should only be called if the flag FLAG_OUTPUR_QUANTITY_DEFINED | |
* is set. | |
* | |
* @param dimIndex | |
* the index of the dimension to get the output quantity offsets for | |
* @return a {@link BlockReferenceTriple} containing the offsets to read the | |
* CNBLOCK defining the output quantity for the dimension with the | |
* given index or null if none defined | |
*/ | |
public BlockReferenceTriple getOutputQuantityOffsetsForDimension(int dimIndex) | |
{ | |
return createReferenceTriple(dimIndex, lnksOutputQuantity); | |
} | |
/** | |
* This method should only be called if the flag | |
* FLAG_COMPARISON_QUANTITY_DEFINED is set. | |
* | |
* @param dimIndex | |
* the index of the dimension to get the comparison quantity offsets | |
* for | |
* @return a {@link BlockReferenceTriple} containing the offsets to read the | |
* CNBLOCK defining the comparison quantity for the dimension with the | |
* given index or null if none defined | |
*/ | |
public BlockReferenceTriple getComparisonQuantityOffsetsForDimension(int dimIndex) | |
{ | |
return createReferenceTriple(dimIndex, lnksComparisonQuantity); | |
} | |
/** | |
* This method should only be called if the flag FLAG_DYNAMIC_SIZE is set. | |
* | |
* @param dimIndex | |
* the index of the dimension to get the dynamic size signal offsets | |
* for | |
* @return a {@link BlockReferenceTriple} containing the offsets to read the | |
* CNBLOCK defining the dynamic size signal for the dimension with the | |
* given index or null if none defined | |
*/ | |
public BlockReferenceTriple getSizeSignalOffsetsForDimension(int dimIndex) | |
{ | |
return createReferenceTriple(dimIndex, lnksDynamicSize); | |
} | |
/** | |
* Creates a {@link BlockReferenceTriple} from the given offsets for the given | |
* dimension index. | |
* | |
* @param dimIndex | |
* the index of the dimension to get the offset triple for | |
* @param offsets | |
* the offset structure to read from | |
* @return a {@link BlockReferenceTriple} containing the requested offsets or | |
* null if none defined | |
*/ | |
private BlockReferenceTriple createReferenceTriple(int dimIndex, long[] offsets) | |
{ | |
if (offsets != null && dimIndex < nrOfDimensions && offsets.length == 3 * nrOfDimensions) | |
{ | |
return new BlockReferenceTriple(offsets[dimIndex * 3 + 0], offsets[dimIndex * 3 + 1], offsets[dimIndex * 3 + 2]); | |
} | |
return null; | |
} | |
/** | |
* @see java.lang.Object#toString() | |
* | |
* @return | |
*/ | |
@Override | |
public String toString() | |
{ | |
return "CABLOCK [lnkComposition=" + lnkComposition + ", lnksData=" + Arrays.toString(lnksData) | |
+ ", lnksDynamicSize=" + Arrays.toString(lnksDynamicSize) + ", lnksInputQuantities=" | |
+ Arrays.toString(lnksInputQuantity) + ", lnksOutputQuantity=" + Arrays.toString(lnksOutputQuantity) | |
+ ", lnksComparisonQuantity=" + Arrays.toString(lnksComparisonQuantity) + ", lnksScalingAxis=" | |
+ Arrays.toString(lnksConversionRule) + ", lnksAxis=" + Arrays.toString(lnksScalingAxis) + ", arrayType=" + arrayType | |
+ ", storageType=" + storageType + ", flags=" + flags + ", byteOffsetBase=" + byteOffsetBase | |
+ ", invalBitPosBase=" + invalBitPosBase + ", dimSizes=" + Arrays.toString(dimSizes) + ", nrOfDimensions=" | |
+ nrOfDimensions + ", axisValues=" + Arrays.toString(axisValues) + ", cycleCounts=" | |
+ Arrays.toString(cycleCounts) + "]"; | |
} | |
} |