Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 4.3 #4

Merged
merged 5 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ repositories {

```groovy
dependencies {
implementation 'org.dcm4che:dcm4che-typeddicom:0.4.2'
implementation 'org.dcm4che:dcm4che-typeddicom:0.4.3'
}
```

Expand All @@ -35,7 +35,7 @@ repositories {

```kotlin
dependencies {
implementation("org.dcm4che:dcm4che-typeddicom:0.4.2")
implementation("org.dcm4che:dcm4che-typeddicom:0.4.3")
}
```

Expand All @@ -54,7 +54,7 @@ dependencies {
<dependency>
<groupId>org.dcm4che</groupId>
<artifactId>dcm4che-typeddicom</artifactId>
<version>0.4.2</version>
<version>0.4.3</version>
</dependency>
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
import org.xml.sax.SAXException;

import java.util.*;
import java.util.stream.Collectors;

/**
* This class parses the 3th part of the DICOM Standard XML
* (http://dicom.nema.org/medical/dicom/current/source/docbook/part03/part03.xml)
*/
public class DicomPart03Handler extends MemorizeTablesDicomPartHandler {
private static final String FUNCTIONAL_GROUP_MACRO_REFERENCE = "FUNCTIONAL GROUP MACRO";
private final Set<ModuleMetaInfo> modules;
private final Map<String, Set<DataElementMetaInfo>> dataElementMetaInfos;
private final Set<InformationObjectDefinitionMetaInfo> iods;
Expand Down Expand Up @@ -211,10 +213,11 @@ private void handleEndOfAttributesTableRow() {
int currentSequenceDepth = sequenceDepth(name);
name = name.substring(currentSequenceDepth).trim();
TableEntry currentTableEntry;
boolean validInclude = name.startsWith("Include") &&
boolean validStandardInclude = name.startsWith("Include") &&
lastReferenceInFirstColumn != null &&
lastReferenceInFirstColumn.startsWith("table_");
boolean validAttribute = columns.size() > 1 && columns.get(1).matches("\\([0-9A-F]{2}[0-9A-Fx]{2},[0-9A-F]{2}[0-9A-Fx]{2}\\)");
boolean validFunctionalGroupMacroInclude = name.startsWith("Include one or more Functional Group Macros");
if (columns.size() == 3 && validAttribute) {
currentTableEntry = new AttributeTableEntry(tableEntryHref, name, columns.get(1), columns.get(2));
} else if (columns.size() == 4 && validAttribute) {
Expand All @@ -225,10 +228,12 @@ private void handleEndOfAttributesTableRow() {
columns.get(2),
columns.get(3)
);
} else if (columns.size() == 2 && validInclude) {
} else if (columns.size() == 2 && validStandardInclude) {
currentTableEntry = new MacroTableEntry(tableEntryHref, lastReferenceInFirstColumn, columns.get(1));
} else if (columns.size() == 1 && validInclude) {
} else if (columns.size() == 1 && validStandardInclude) {
currentTableEntry = new MacroTableEntry(tableEntryHref, lastReferenceInFirstColumn);
} else if (validFunctionalGroupMacroInclude) {
currentTableEntry = new MacroTableEntry(tableEntryHref, FUNCTIONAL_GROUP_MACRO_REFERENCE);
} else {
System.out.println("Invalid Row: " + Arrays.toString(columns.toArray()));
return;
Expand All @@ -243,31 +248,32 @@ private String extractModuleReference(String html) {
if (html == null) {
return null;
}
String moduleRef = html.replaceAll("(?s).*?<a href=\"http://dicom.nema.org/medical/dicom/current/output/html/part03.html#([^\"]*)\">.*$", "$1");
return moduleRef;
return html.replaceAll("(?s).*?<a href=\"http://dicom.nema.org/medical/dicom/current/output/html/part03.html#([^\"]*)\">.*$", "$1");
}

private Iterable<DataElementMetaInfo> resolveMacrosRecursively(TableEntry tableEntry, Context context) {
if (tableEntry instanceof MacroTableEntry macroTableEntry) {
String tableId = macroTableEntry.getTableId();
MacroTable macroTable = macroTables.get(tableId);
if (macroTable == null) {
Set<MacroTable> matchingMacroTables = getMatchingMacroTables(tableId);
if (matchingMacroTables.isEmpty()) {
System.out.println("Invalid macro key: " + tableId);
return Collections.emptyList();
}
MacroMetaInfo macroMetaInfo = macros.get(tableId);
if (macroMetaInfo == null) {
macroMetaInfo = new MacroMetaInfo(macroTable.getTableId());
macroMetaInfo = new MacroMetaInfo(tableId);
macros.put(macroMetaInfo.getTableId(), macroMetaInfo);
}
for (TableEntry macroSubEntry : macroTable.getTableEntries()) {
ContextEntry newContextEntry = new ContextEntry(macroTable.getName(), macroTable.getHref());
// Stop at recursive macros
if (!context.getContext().contains(newContextEntry)) {
macroMetaInfo.addDataElementMetaInfo(resolveMacrosRecursively(
macroSubEntry,
new Context(newContextEntry)
));
for (MacroTable macroTable : matchingMacroTables) {
for (TableEntry macroSubEntry : macroTable.getTableEntries()) {
ContextEntry newContextEntry = new ContextEntry(macroTable.getName(), macroTable.getHref());
// Stop at recursive macros
if (!context.getContext().contains(newContextEntry)) {
macroMetaInfo.addDataElementMetaInfo(resolveMacrosRecursively(
macroSubEntry,
new Context(newContextEntry)
));
}
}
}
return macroMetaInfo.getSubDataElementMetaInfos();
Expand Down Expand Up @@ -303,6 +309,25 @@ private Iterable<DataElementMetaInfo> resolveMacrosRecursively(TableEntry tableE
}
return Collections.emptyList();
}

// Usually only one macro matches, but there is also the Functional Groups Macros which get combined to one special macro
private Set<MacroTable> getMatchingMacroTables(String tableId) {
Set<MacroTable> matchingMacroTables;
if (FUNCTIONAL_GROUP_MACRO_REFERENCE.equals(tableId)) {
matchingMacroTables = macroTables.entrySet().stream()
.filter(entry -> entry.getKey().startsWith("table_C.7.6.16"))
.map(Map.Entry::getValue)
.collect(Collectors.toSet());
} else {
MacroTable matchingMacroTable = macroTables.get(tableId);
if (matchingMacroTable == null) {
matchingMacroTables = Collections.emptySet();
} else {
matchingMacroTables = Collections.singleton(matchingMacroTable);
}
}
return matchingMacroTables;
}

private void removeHTMLTagsFromColumn(Integer i) {
if (i == null || i >= this.columns.size()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ default SELF setSequence(String privateCreator, int tag, Builder<?, ?>... itemBu
}
return (SELF) this;
}

default <B extends Builder> B as(Class<B> builderClass) {
return AttributesWrapper.wrap(this.getAttributes(), builderClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,18 @@ public interface DataElementWrapper extends AttributesWrapper {
*/
VR getValueRepresentation();

/**
* @return The <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.8.html">DICOM
* Private Creator</a> of the wrapped DICOM attributes. null if not private
*/
String getPrivateCreator();

/**
* @return The <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part06/chapter_6.html">DICOM
* Tag</a> of the wrapped DICOM attributes.
*/
int getTag();

/**
* @return The <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.8.html">DICOM
* Private Creator</a> of the wrapped DICOM attributes.
*/
default String getPrivateCreator() {
return null;
}

Object getValue();

boolean exists();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ public VR getValueRepresentation() {
return VALUE_REPRESENTATION;
}

/**
* @return The <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.8.html">DICOM
* Private Creator</a> of the wrapped DICOM attributes. null if not private
*/
public abstract String getPrivateCreator();

/**
* @return The <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part06/chapter_6.html">DICOM
* Tag</a> of the wrapped DICOM sequence.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import java.util.Arrays;
@Deprecated
{{/retired}}
public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{keyword}}.Item>{{/sequence}}{{^sequence}}AbstractDataElementWrapper implements {{valueRepresentationWrapper}}{{/sequence}} {
/**
* The <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.8.html">Private Creator</a>
* associated with this class.
*/
public static final String PRIVATE_CREATOR = null;
/**
* The <a href="https://dicom.nema.org/medical/dicom/current/output/chtml/part06/chapter_6.html">DICOM Tag</a>
* associated with this class.
Expand Down Expand Up @@ -70,6 +75,11 @@ public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{key
}
{{/sequence}}

@Override
public String getPrivateCreator() {
return PRIVATE_CREATOR;
}

@Override
public int getTag() {
return TAG;
Expand Down Expand Up @@ -150,7 +160,7 @@ public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{key
/**
* @return a {@link Builder} to create {{name}} Items with a fluent API.
*/
public static Builder builder() {
static Builder builder() {
return new Builder();
}

Expand All @@ -159,7 +169,7 @@ public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{key
*
* @return a {@link Builder} to create {{name}} Items with a fluent API. Instead of creating new Attributes it wraps the provided Attributes.
*/
public static Builder builder(Attributes attributes) {
static Builder builder(Attributes attributes) {
return new Builder(attributes);
}

Expand All @@ -168,7 +178,7 @@ public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{key
*/
default {{keyword}} get{{keyword}}() {
{{#sequence}}
Sequence sequence = getAttributes().getSequence(TAG);
Sequence sequence = getAttributes().getSequence(PRIVATE_CREATOR, TAG);
if (sequence == null) {
return null;
}
Expand All @@ -186,7 +196,7 @@ public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{key
* @param initialCapacity the initial capacity for the new {{name}}
*/
default {{keyword}} new{{keyword}}(int initialCapacity) {
return new {{keyword}}(getAttributes().newSequence(TAG, initialCapacity));
return new {{keyword}}(getAttributes().newSequence(PRIVATE_CREATOR, TAG, initialCapacity));
}

/**
Expand All @@ -199,7 +209,7 @@ public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{key
* <code>initialCapacity</code>.
*/
default {{keyword}} ensure{{keyword}}(int initialCapacity) {
return new {{keyword}}(getAttributes().ensureSequence(TAG, initialCapacity));
return new {{keyword}}(getAttributes().ensureSequence(PRIVATE_CREATOR, TAG, initialCapacity));
}

/**
Expand All @@ -217,14 +227,14 @@ public class {{keyword}} extends {{#sequence}}SequenceWrapper<{{keyword}}, {{key
* @return Whether it contains the {{name}} (see {@link {{keyword}}})
*/
default boolean contains{{keyword}}() {
return getAttributes().contains(TAG);
return getAttributes().contains(PRIVATE_CREATOR, TAG);
}

/**
* Removes the {{name}} (see {@link {{keyword}}}
*/
default void remove{{keyword}}() {
getAttributes().remove(TAG);
getAttributes().remove(PRIVATE_CREATOR, TAG);
}

class Builder extends AbstractAttributesWrapper implements org.dcm4che.typeddicom.Builder<Builder, SimpleHolder>, {{keyword}}.Builder<Builder, SimpleHolder> {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
version=0.4.2
version=0.4.3
org.gradle.jvmargs=-Xmx4096m
org.gradle.caching=true