All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nih.ncats.molwitch.renderer.RendererOptions Maven / Gradle / Ivy

There is a newer version: 1.0.17
Show newest version
/*
 * NCATS-MOLWITCH-RENDERER
 *
 * Copyright 2019 NIH/NCATS
 *
 *    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 gov.nih.ncats.molwitch.renderer;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import gov.nih.ncats.molwitch.Chemical;

public class RendererOptions {

	public enum DrawOptions{
		DRAW_BONDS(true, "PROP_KEY_DRAW_BONDS"),
		DRAW_SYMBOLS(true, "PROP_KEY_DRAW_SYMBOLS"),
		DRAW_CARBON(false, "PROP_KEY_DRAW_CARBON"),
		DRAW_IMPLICIT_HYDROGEN(true, "PROP_KEY_DRAW_IMPLICIT_HYDROGEN"),
		DRAW_TERMINAL_CARBON(true, "PROP_KEY_DRAW_TERMINAL_CARBON"),
		DRAW_STEREO_BONDS(true, "PROP_KEY_DRAW_STEREO_BONDS"),
		DRAW_PROPORTIONAL_ATOM_RADIUS(false, "PROP_KEY_DRAW_PROPORTIONAL_ATOM_RADIUS"),
		DRAW_PROPORTION_AVERAGE_BOND_LENGTH(true, "PROP_KEY_DRAW_PROPORTION_AVERAGE_BOND_LENGTH"),
		DRAW_CENTER_ALL_DOUBLE_BONDS(false, "PROP_KEY_DRAW_CENTER_ALL_DOUBLE_BONDS"),
		DRAW_ATOM_COLOR_ON_BONDS(true, "PROP_KEY_DRAW_ATOM_COLOR_ON_BONDS"),
		DRAW_CONSTANT_DASH_WIDTH(true, "PROP_KEY_DRAW_CONSTANT_DASH_WIDTH"),
		DRAW_STEREO_DASH_AS_WEDGE(true, "PROP_KEY_DRAW_STEREO_DASH_AS_WEDGE"),
		/**
		 *  Show wedge bonds as originating from a small circle (of bond length)
		 *  instead of a point (which is the default).
		 *  Allowing this makes wedges more visible in some cases.
		 */
		DRAW_WEDGE_AS_POINT(true, "PROP_KEY_DRAW_WEDGE_AS_POINT"),
		/**
		 * Should renderer join wedges/single bonds into an extended stylistic form,
		 * which is often less jarring than the sudden sharp corners from bridgehead/chain wedges in other styles.
		 *
		 * 

when set to {@code false} (default):

* * *

when set to {@code true} :

* * */ DRAW_STEREO_WEDGE_JOIN(false, "PROP_KEY_DRAW_STEREO_WEDGE_JOIN"), /** * Show the final dash line on dash-wedges when not connecting to a symbol. */ DRAW_STEREO_LAST_DASH_ON_NON_SYMBOLS(true, "PROP_KEY_DRAW_STEREO_LAST_DASH_ON_NON_SYMBOLS"), DRAW_CENTER_NONRING_DOUBLE_BONDS(false, "PROP_KEY_DRAW_CENTER_NONRING_DOUBLE_BONDS"), DRAW_GREYSCALE(false, "PROP_KEY_DRAW_GREYSCALE"), DRAW_STEREO_LABELS(false, "PROP_KEY_DRAW_STEREO_LABELS"), DRAW_STEREO_GIVEN_BY_MAP(false, "PROP_KEY_DRAW_STEREO_GIVEN_BY_MAP"), DRAW_HIGHLIGHT_MAPPED(false, "PROP_KEY_DRAW_HIGHLIGHT_MAPPED"), DRAW_HIGHLIGHT_WITH_HALO(false, "PROP_KEY_DRAW_HIGHLIGHT_WITH_HALO"), DRAW_HIGHLIGHT_MONOCHROMATIC(true, "PROP_KEY_DRAW_HIGHLIGHT_MONOCHROMATIC"), DRAW_HIGHLIGHT_SHOW_ATOM(false, "PROP_KEY_DRAW_HIGHLIGHT_SHOW_ATOM"), DRAW_SHOW_MAPPED(false, "PROP_KEY_DRAW_SHOW_MAPPED"), DRAW_STEREO_LABELS_AS_ATOMS(false, "PROP_KEY_DRAW_STEREO_LABELS_AS_ATOMS"), DRAW_STEREO_LABELS_AS_RELATIVE(false, "PROP_KEY_DRAW_STEREO_LABELS_AS_RELATIVE"), DRAW_STEREO_LABELS_AS_STARRED(false, "PROP_KEY_DRAW_STEREO_LABELS_AS_STARRED"), DRAW_STEREO_LABELS_PARENTHESES(false, "PROP_KEY_DRAW_STEREO_LABELS_PARENTHESES"), DRAW_STEREO_FORCE_MONOCHROMATIC(false, "PROP_KEY_DRAW_STEREO_FORCE_MONOCHROMATIC"), DRAW_SUPERATOMS_AS_LABELS(true, "PROP_KEY_DRAW_SUPERATOMS_AS_LABELS") ; private final boolean defaultValue; /** * This is the name from the old NChemicalRenderer DisplayParams * that is sometimes used in legacy NCATS API calls * to override rendering options. This is used * only in {@link #safeValueOf(String)} * to maintain backwards compatibility. */ private final String legacyName; private static final Map nameMap; static { nameMap = new HashMap<>(); for(DrawOptions opt : values()) { nameMap.put(opt.name(), opt); nameMap.put(opt.legacyName, opt); } } DrawOptions(boolean dv, String legacyName){ defaultValue= dv; this.legacyName = legacyName; } /** * This is a version of {@link #valueOf(String)} * but if the given String input is not an enum value * then it will return null instead of throwing an exception. * * @param name the value to parse the Draw option name of. * @return the {@link DrawOptions} for this name or {@code null}. */ public static DrawOptions safeValueOf(String name) { return nameMap.get(name); } public boolean defaultValue() { return defaultValue; } } public enum DrawProperties{ ATOM_LABEL_FONT_FRACTION(2/3D, "DEF_FONT_PERCENT"), ATOM_LABEL_BOND_GAP_FRACTION(1, "DEF_FONT_GAP_PERCENT"), BOND_EXPECTED_LENGTH(1, "DEF_BOND_AVG"), BOND_STROKE_WIDTH_FRACTION(.095D, "DEF_STROKE_PERCENT"), BOND_DOUBLE_GAP_FRACTION(.30D, "DEF_DBL_BOND_GAP"), BOND_DOUBLE_LENGTH_FRACTION(2/3D, "DEF_DBL_BOND_DISTANCE"), BOND_STEREO_WEDGE_ANGLE( Math.PI/12, "DEF_WEDGE_ANG"), BOND_OVERLAP_SPACING_FRACTION(1.75D, "DEF_SPLIT_RATIO"), BOND_STEREO_DASH_NUMBER(6, "DEF_NUM_DASH"), SUBSCRIPT_Y_DISPLACEMENT_FRACTION(0.2f, "SUBSCRIPT_Y_DISPLACEMENT_FRACTION"); private final double defaultValue; /** * This is the name from the old NChemicalRenderer DisplayParams * that is sometimes used in legacy NCATS API calls * to override renderering options. This is used * only in {@link #safeValueOf(String)} * to maintain backwards compatibility. */ private final String legacyName; private static final Map nameMap; static { nameMap = new HashMap<>(); for(DrawProperties opt : values()) { nameMap.put(opt.name(), opt); nameMap.put(opt.legacyName, opt); } } DrawProperties(double dv, String legacyName){ defaultValue = dv; this.legacyName = legacyName; } /** * This is a version of {@link #valueOf(String)} * but if the given String input is not an enum value * then it will return null instead of throwing an exception. * *@param name the value to parse the draw property name of. *@return the {@link DrawProperties} for this name or {@code null}. */ public static DrawProperties safeValueOf(String name) { return nameMap.get(name); } public double defaultValue() { return defaultValue; } } private final EnumMap drawOptions = new EnumMap<>(DrawOptions.class); private final EnumMap drawProps = new EnumMap<>(DrawProperties.class); private ColorPalette colorPalette = new ColorPalette(); private Function bottomCaptionFunction=null; private Function topCaptionFunction=null; private List changeListeners = new ArrayList<>(); public RendererOptions() { _useDefauls(); } public RendererOptions copy(){ RendererOptions copy = RendererOptions.createFromMap(asNonDefaultMap()); return copy; } @JsonCreator public static RendererOptions createFromMap(Map map){ RendererOptions opts = new RendererOptions(); opts.changeSettings(map); return opts; } @JsonValue public Map asNonDefaultMap(){ Map map = new HashMap<>(); for(Entry entry: drawProps.entrySet()){ if(!Objects.equals(entry.getValue(), entry.getKey().defaultValue)) { map.put(entry.getKey().legacyName, entry.getValue()); } } for(Entry entry: drawOptions.entrySet()){ if(entry.getKey().defaultValue != entry.getValue().booleanValue()) { map.put(entry.getKey().legacyName, entry.getValue()); } } Map paletteMap = colorPalette.asNonDefaultMap(); if(!paletteMap.isEmpty()){ map.put("colorPalette", paletteMap); } return map; } public Map asMap(){ Map map = new HashMap<>(); for(Entry entry: drawProps.entrySet()){ map.put(entry.getKey().legacyName, entry.getValue()); } for(Entry entry: drawOptions.entrySet()){ map.put(entry.getKey().legacyName, entry.getValue()); } return map; } public void addChangeListener(RendererOptionChangeListener listener){ changeListeners.add(Objects.requireNonNull(listener)); } public ColorPalette getColorPalette(){ return colorPalette; } private void fireChangeListeners(){ changeListeners.forEach(l->l.optionChanged(null)); } public boolean getDrawOption(DrawOptions o) { return drawOptions.get(o); } public RendererOptions setDrawOption(DrawOptions option, boolean value) { drawOptions.put(option, value); fireChangeListeners(); return this; } public double getDrawPropertyValue(DrawProperties p) { return drawProps.get(p); } public RendererOptions captionBottom(Function captionFunction) { this.bottomCaptionFunction = captionFunction; fireChangeListeners(); return this; } public RendererOptions captionTop(Function captionFunction) { this.topCaptionFunction = captionFunction; fireChangeListeners(); return this; } public RendererOptions setDrawPropertyValue(DrawProperties p, double value) { drawProps.put(p, value); fireChangeListeners(); return this; } public RendererOptions withSubstructureHighlight() { drawOptions.put(DrawOptions.DRAW_HIGHLIGHT_MAPPED, true); drawOptions.put(DrawOptions.DRAW_HIGHLIGHT_WITH_HALO, true); drawOptions.put(DrawOptions.DRAW_HIGHLIGHT_MONOCHROMATIC, true); fireChangeListeners(); return this; } Optional captionBottom(Chemical c){ if(bottomCaptionFunction!=null) { return Optional.ofNullable(bottomCaptionFunction.apply(c)); } return Optional.empty(); } Optional captionTop(Chemical c){ if(topCaptionFunction!=null) { return Optional.ofNullable(topCaptionFunction.apply(c)); } return Optional.empty(); } public static RendererOptions createDefault() { return new RendererOptions(); } public static RendererOptions createBallAndStick() { RendererOptions opts =new RendererOptions(); opts.setDrawOption(DrawOptions.DRAW_BONDS, true); opts.setDrawOption(DrawOptions.DRAW_SYMBOLS, false); opts.setDrawOption(DrawOptions.DRAW_CARBON, true); opts.setDrawOption(DrawOptions.DRAW_CENTER_ALL_DOUBLE_BONDS, true); opts.setDrawOption(DrawOptions.DRAW_STEREO_BONDS, false); return opts; } public static RendererOptions createINNLike() { RendererOptions opts =new RendererOptions(); opts.setDrawOption(DrawOptions.DRAW_GREYSCALE, true); opts.setDrawOption(DrawOptions.DRAW_STEREO_DASH_AS_WEDGE, false); opts.setDrawPropertyValue(DrawProperties.BOND_STEREO_WEDGE_ANGLE, Math.PI/12); opts.setDrawPropertyValue(DrawProperties.BOND_STROKE_WIDTH_FRACTION, 0.050D); opts.setDrawPropertyValue(DrawProperties.BOND_DOUBLE_GAP_FRACTION, .15D); opts.setDrawPropertyValue(DrawProperties.ATOM_LABEL_FONT_FRACTION,0.5D); return opts; } public static RendererOptions createUSPLike() { RendererOptions opts = new RendererOptions(); opts.setDrawOption(DrawOptions.DRAW_GREYSCALE, true); opts.setDrawPropertyValue(DrawProperties.ATOM_LABEL_FONT_FRACTION,0.494D*0.97); opts.setDrawPropertyValue(DrawProperties.ATOM_LABEL_BOND_GAP_FRACTION,1.02D); opts.setDrawPropertyValue(DrawProperties.BOND_STROKE_WIDTH_FRACTION,0.04D*0.8); opts.setDrawPropertyValue(DrawProperties.BOND_DOUBLE_GAP_FRACTION,0.21D*0.95); opts.setDrawPropertyValue(DrawProperties.BOND_STEREO_WEDGE_ANGLE, Math.PI/25*0.92); opts.setDrawPropertyValue(DrawProperties.BOND_STEREO_DASH_NUMBER, 8); opts.setDrawPropertyValue(DrawProperties.SUBSCRIPT_Y_DISPLACEMENT_FRACTION, 0.17); opts.setDrawOption(DrawOptions.DRAW_WEDGE_AS_POINT, false); opts.setDrawOption(DrawOptions.DRAW_STEREO_WEDGE_JOIN, true); opts.setDrawOption(DrawOptions.DRAW_STEREO_LAST_DASH_ON_NON_SYMBOLS, false); return opts; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((drawOptions == null) ? 0 : drawOptions.hashCode()); result = prime * result + ((drawProps == null) ? 0 : drawProps.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof RendererOptions)) { return false; } RendererOptions other = (RendererOptions) obj; if (drawOptions == null) { if (other.drawOptions != null) { return false; } } else if (!drawOptions.equals(other.drawOptions)) { return false; } if (drawProps == null) { if (other.drawProps != null) { return false; } } else if (!drawProps.equals(other.drawProps)) { return false; } return true; } private void _useDefauls() { for(DrawOptions o : DrawOptions.values()) { drawOptions.put(o, o.defaultValue()); } for(DrawProperties o : DrawProperties.values()) { drawProps.put(o, o.defaultValue()); } colorPalette = new ColorPalette(); } public RendererOptions resetToDefaults() { _useDefauls(); fireChangeListeners(); return this; } public RendererOptions turnOffStereo() { setDrawOption(DrawOptions.DRAW_STEREO_LABELS, false); setDrawOption(DrawOptions.DRAW_STEREO_LABELS_PARENTHESES, false); fireChangeListeners(); return this; } public RendererOptions turnOnStereo() { setDrawOption(DrawOptions.DRAW_STEREO_LABELS, true); setDrawOption(DrawOptions.DRAW_STEREO_LABELS_PARENTHESES, true); fireChangeListeners(); return this; } public RendererOptions changeSettings(Map map) { for(Entry entry: map.entrySet()) { if("colorPalette".equals(entry.getKey())){ this.colorPalette = ColorPalette.createFromMap((Map)entry.getValue()); continue; } DrawOptions opts = DrawOptions.safeValueOf(entry.getKey()); if(opts ==null) { DrawProperties props = DrawProperties.safeValueOf(entry.getKey()); if(props !=null) { if(Number.class.isAssignableFrom(entry.getValue().getClass())){ setDrawPropertyValue(props,((Number)entry.getValue()).doubleValue()); }else if(String.class.isAssignableFrom(entry.getValue().getClass())){ setDrawPropertyValue(props,Double.parseDouble((String)entry.getValue())); } } }else { if(Boolean.class.isAssignableFrom(entry.getValue().getClass())){ setDrawOption(opts, ((Boolean) entry.getValue()).booleanValue()); }else if(String.class.isAssignableFrom(entry.getValue().getClass())){ setDrawOption(opts,Boolean.parseBoolean((String)entry.getValue())); } } } return this; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy