org.kalypso.kalypsomodel1d2d.ui.chart.BuildingParameterPaintData.java Source code

Java tutorial

Introduction

Here is the source code for org.kalypso.kalypsomodel1d2d.ui.chart.BuildingParameterPaintData.java

Source

/** This file is part of Kalypso
 *
 *  Copyright (c) 2012 by
 *
 *  Bjrnsen Beratende Ingenieure GmbH, Koblenz, Germany (Bjoernsen Consulting Engineers), http://www.bjoernsen.de
 *  Technische Universitt Hamburg-Harburg, Institut fr Wasserbau, Hamburg, Germany
 *  (Technical University Hamburg-Harburg, Institute of River and Coastal Engineering), http://www.tu-harburg.de/wb/
 *
 *  Kalypso is free software: you can redistribute it and/or modify it under the terms  
 *  of the GNU Lesser General Public License (LGPL) as published by the Free Software 
 *  Foundation, either version 3 of the License, or (at your option) any later version.
 *
 *  Kalypso is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied 
 *  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with Kalypso.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.kalypso.kalypsomodel1d2d.ui.chart;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang3.ObjectUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.kalypso.kalypsomodel1d2d.ui.i18n.Messages;
import org.kalypso.observation.IObservation;
import org.kalypso.observation.result.ComponentUtilities;
import org.kalypso.observation.result.IComponent;
import org.kalypso.observation.result.IRecord;
import org.kalypso.observation.result.TupleResult;

import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;

import de.openali.odysseus.chart.ext.base.layer.HoverIndex;
import de.openali.odysseus.chart.ext.base.layer.TooltipFormatter;
import de.openali.odysseus.chart.framework.model.data.DataRange;
import de.openali.odysseus.chart.framework.model.data.IDataRange;
import de.openali.odysseus.chart.framework.model.figure.impl.PointFigure;
import de.openali.odysseus.chart.framework.model.figure.impl.PolylineFigure;
import de.openali.odysseus.chart.framework.model.layer.EditInfo;
import de.openali.odysseus.chart.framework.model.mapper.ICoordinateMapper;
import de.openali.odysseus.chart.framework.model.style.ILineStyle;
import de.openali.odysseus.chart.framework.model.style.IPointStyle;
import de.openali.odysseus.chart.framework.model.style.IStyleSet;

/**
 * @author Gernot
 */
class BuildingParameterPaintData {
    private final GeometryFactory m_jtsFactory = new GeometryFactory();

    private HoverIndex m_hoverIndex = new HoverIndex();

    private final Map<EditInfo, Coordinate> m_paintOkPoints = new HashMap<>();

    private final List<Coordinate> m_paintCrossPoints = new ArrayList<>();

    private final List<Coordinate[]> m_paintOkLines = new ArrayList<>();

    private final List<Coordinate[]> m_paintCrossLines = new ArrayList<>();

    private final PolylineFigure m_okLineFigure;

    private final PointFigure m_okPointFigure;

    private final PolylineFigure m_crossLineFigure;

    private final PointFigure m_crossPointFigure;

    private final IObservation<TupleResult> m_observation;

    private final String m_domainComponentID;

    private final String m_valueComponentID;

    private final String m_classComponentId;

    private final ICoordinateMapper m_mapper;

    private final BuildingParameterLayer m_layer;

    private IDataRange<Double> m_domainRange;

    private IDataRange<Double> m_targetRange;

    private final IPointStyle m_okHoverStyle;

    private final IPointStyle m_crossHoverStyle;

    public BuildingParameterPaintData(final BuildingParameterLayer layer, final IStyleSet styleSet,
            final IObservation<TupleResult> observation, final String domainComponentID,
            final String valueComponentID, final String classComponentId, final ICoordinateMapper mapper) {
        m_layer = layer;
        m_observation = observation;
        m_domainComponentID = domainComponentID;
        m_valueComponentID = valueComponentID;
        m_classComponentId = classComponentId;
        m_mapper = mapper;

        m_okLineFigure = new PolylineFigure();
        m_okLineFigure.setStyle(styleSet.getStyle("okLine", ILineStyle.class)); //$NON-NLS-1$

        m_okPointFigure = new PointFigure(styleSet.getStyle("okPoint", IPointStyle.class)); //$NON-NLS-1$
        m_okHoverStyle = styleSet.getStyle("okPointHover", IPointStyle.class); //$NON-NLS-1$

        m_crossLineFigure = new PolylineFigure();
        m_crossLineFigure.setStyle(styleSet.getStyle("crossLine", ILineStyle.class)); //$NON-NLS-1$

        m_crossPointFigure = new PointFigure(styleSet.getStyle("crossPoint", IPointStyle.class)); //$NON-NLS-1$
        m_crossHoverStyle = styleSet.getStyle("crossPointHover", IPointStyle.class); //$NON-NLS-1$

        updatePaintData();
    }

    private void updatePaintData() {
        final TupleResult result = m_observation.getResult();

        updateOkLines(result);
        updateIntersectionLines();
    }

    private void updateOkLines(final TupleResult result) {
        final int domainComponent = result.indexOfComponent(m_domainComponentID);
        final int valueComponent = result.indexOfComponent(m_valueComponentID);
        final int classComponent = result.indexOfComponent(m_classComponentId);

        Range<Double> domainRange = null;
        Range<Double> targetRange = null;

        // sort into coordinate arrays!
        BigDecimal lastClass = null;
        final List<Coordinate> crds = new ArrayList<>();

        for (final IRecord record : result) {
            final BigDecimal classValue = (BigDecimal) record.getValue(classComponent);
            final BigDecimal domainValue = (BigDecimal) record.getValue(domainComponent);
            final BigDecimal targetValue = (BigDecimal) record.getValue(valueComponent);

            if (domainValue == null || targetValue == null)
                continue;

            if (!ObjectUtils.equals(classValue, lastClass)) {
                m_paintOkLines.add(crds.toArray(new Coordinate[crds.size()]));
                crds.clear();
            }

            // add value to path
            final Coordinate currentCrd = new Coordinate(domainValue.doubleValue(), targetValue.doubleValue());

            final EditInfo info = buildOkPointInfo(record, domainValue, targetValue, classValue);

            m_paintOkPoints.put(info, currentCrd);
            crds.add(currentCrd);

            lastClass = classValue;

            /* update ranges */
            domainRange = updateRange(domainRange, domainValue);
            targetRange = updateRange(targetRange, targetValue);
        }

        // additionally add last line
        m_paintOkLines.add(crds.toArray(new Coordinate[crds.size()]));

        /* set ranges */
        if (domainRange != null)
            m_domainRange = new DataRange<>(domainRange.lowerEndpoint(), domainRange.upperEndpoint());
        if (targetRange != null)
            m_targetRange = new DataRange<>(targetRange.lowerEndpoint(), targetRange.upperEndpoint());
    }

    private Range<Double> updateRange(final Range<Double> range, final BigDecimal value) {
        if (value == null)
            return range;

        final Range<Double> valueRange = Ranges.singleton(value.doubleValue());
        if (range == null)
            return valueRange;

        return range.span(valueRange);
    }

    private EditInfo buildOkPointInfo(final IRecord record, final BigDecimal domainValue,
            final BigDecimal targetValue, final BigDecimal classValue) {
        final TupleResult result = record.getOwner();

        final int domainComponentIndex = result.indexOfComponent(m_domainComponentID);
        final int valueComponentIndex = result.indexOfComponent(m_valueComponentID);
        final int classComponentIndex = result.indexOfComponent(m_classComponentId);

        final IComponent domainComponent = result.getComponent(domainComponentIndex);
        final IComponent valueComponent = result.getComponent(valueComponentIndex);
        final IComponent classComponent = result.getComponent(classComponentIndex);

        final String domainLabel = ComponentUtilities.getComponentName(domainComponent);
        final String valueLabel = ComponentUtilities.getComponentName(valueComponent);
        final String classLabel = ComponentUtilities.getComponentName(classComponent);

        final String domainUnit = ComponentUtilities.getComponentUnitLabel(domainComponent);
        final String valueUnit = ComponentUtilities.getComponentUnitLabel(valueComponent);
        final String classUnit = ComponentUtilities.getComponentUnitLabel(classComponent);

        // Edit info
        final String[] formats = new String[] { "%s", "%.3f", "%s" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        final int[] alignments = new int[] { SWT.LEFT, SWT.RIGHT, SWT.LEFT };
        final TooltipFormatter formatter = new TooltipFormatter(null, formats, alignments);

        formatter.addLine(classLabel, classValue, classUnit);
        formatter.addLine(domainLabel, domainValue, domainUnit);
        formatter.addLine(valueLabel, targetValue, valueUnit);

        final String msg = formatter.format();

        return new EditInfo(m_layer, null, null, record, msg, null);
    }

    private void updateIntersectionLines() {
        // Determine intersections and intersecting lines
        // REMARK: brute force at the moment, we normally do not have too many lines. If performance problems occur, use
        // spatial-index for the lines
        final Set<Coordinate[]> crossLines = new HashSet<>();
        for (final Coordinate[] line1 : m_paintOkLines) {
            for (final Coordinate[] line2 : m_paintOkLines) {
                if (line1 == line2 || line1.length < 2 || line2.length < 2)
                    continue;

                final LineString ls1 = m_jtsFactory.createLineString(line1);
                final LineString ls2 = m_jtsFactory.createLineString(line2);
                if (ls1.intersects(ls2)) {
                    crossLines.add(line1);
                    crossLines.add(line2);

                    final Geometry intersection = ls1.intersection(ls2);
                    m_paintCrossPoints.addAll(Arrays.asList(intersection.getCoordinates()));
                }
            }
        }

        m_paintOkLines.removeAll(crossLines);
        m_paintCrossLines.addAll(crossLines);
    }

    public void paint(final GC gc) {
        m_hoverIndex = new HoverIndex();

        for (final Coordinate[] okLine : m_paintOkLines) {
            m_okLineFigure.setPoints(toPointArray(Arrays.asList(okLine)));
            m_okLineFigure.paint(gc);
        }

        for (final Coordinate[] crossLine : m_paintCrossLines) {
            m_crossLineFigure.setPoints(toPointArray(Arrays.asList(crossLine)));
            m_crossLineFigure.paint(gc);
        }

        final Point[] okPoints = toPointArray(m_paintOkPoints.values());
        m_okPointFigure.setCenterPoints(okPoints);
        m_okPointFigure.paint(gc);

        m_crossPointFigure.setCenterPoints(toPointArray(m_paintCrossPoints));
        m_crossPointFigure.paint(gc);

        /* update infos */
        updateOKEditInfos();
        updateCrossEditInfos();
    }

    private void updateOKEditInfos() {
        for (final Entry<EditInfo, Coordinate> entry : m_paintOkPoints.entrySet()) {
            final EditInfo info = entry.getKey();
            final Coordinate crd = entry.getValue();

            final Point pos = m_mapper.logicalToScreen(crd.x, crd.y);
            final Rectangle shape = new Rectangle(pos.x - 5, pos.y - 5, 10, 10);

            final PointFigure hoverPaintable = new PointFigure(m_okHoverStyle);
            hoverPaintable.setCenterPoint(pos);

            final EditInfo updatedInfo = new EditInfo(m_layer, hoverPaintable, null, info.getData(), info.getText(),
                    null);

            // update edit infos
            m_hoverIndex.addElement(shape, updatedInfo);
        }
    }

    private void updateCrossEditInfos() {
        for (final Coordinate crd : m_paintCrossPoints) {
            final Point pos = m_mapper.logicalToScreen(crd.x, crd.y);

            // Edit info
            final String msg = Messages.getString("org.kalypso.kalypsomodel1d2d.ui.chart.BuildingParameterLayer.5"); //$NON-NLS-1$
            final Rectangle shape = new Rectangle(pos.x - 5, pos.y - 5, 10, 10);

            final PointFigure hoverPaintable = new PointFigure(m_crossHoverStyle);
            hoverPaintable.setCenterPoint(pos);

            final EditInfo info = new EditInfo(m_layer, hoverPaintable, null, null, msg, pos);
            m_hoverIndex.addElement(shape, info);
        }
    }

    private Point[] toPointArray(final Collection<Coordinate> crds) {
        final Collection<Point> points = new ArrayList<>(crds.size());

        for (final Coordinate crd : crds)
            points.add(m_mapper.logicalToScreen(crd.x, crd.y));

        return points.toArray(new Point[points.size()]);
    }

    public IDataRange<Double> getDomainRange() {
        return m_domainRange;
    }

    public IDataRange<Double> getTargetRange() {
        return m_targetRange;
    }

    public IObservation<TupleResult> getObservation() {
        return m_observation;
    }

    public EditInfo getInfo(final Point p) {
        if (m_hoverIndex == null)
            return null;

        return m_hoverIndex.findElement(p);
    }
}