Package org.locationtech.udig.project.internal.render.impl

Source Code of org.locationtech.udig.project.internal.render.impl.RenderMetricsSorter

/*
*    uDig - User Friendly Desktop Internet GIS client
*    http://udig.refractions.net
*    (C) 2012, Refractions Research Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html), and the Refractions BSD
* License v1.0 (http://udig.refractions.net/files/bsd3-v10.html).
*/
package org.locationtech.udig.project.internal.render.impl;

import java.io.Serializable;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import org.locationtech.udig.project.IBlackboard;
import org.locationtech.udig.project.ILayer;
import org.locationtech.udig.project.IStyleBlackboard;
import org.locationtech.udig.project.internal.Layer;
import org.locationtech.udig.project.internal.ProjectPlugin;
import org.locationtech.udig.project.internal.render.MultiLayerRenderer;
import org.locationtech.udig.project.internal.render.impl.InternalRenderMetricsFactory.InternalRenderMetrics;

import org.geotools.util.Range;

/**
* Sorts RenderMetrics objects based on how well the renderer suits the Layer and the resource
*
* @author Jesse
* @since 1.1.0
*/
public class RenderMetricsSorter implements Comparator<InternalRenderMetrics>, Serializable {

    /** long serialVersionUID field */
    private static final long serialVersionUID = 1L;

    private final List<Layer> layersCopy;

    /**
     * Create new instance
     *
     * @param layers the layers to sort
     */
    public RenderMetricsSorter( List<Layer> layers ) {
        super();
        this.layersCopy = layers;
    }

    public List<Layer> getLayers() {
        return layersCopy;
    }
    /**
     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
     */
    public int compare( InternalRenderMetrics o1, InternalRenderMetrics o2 ) {
        if( !canRender(o1) ){
            if( !canRender(o2) )
                return 0;
            return 1;
        }
           
        if( !canRender(o2) ){
            return -1;
        }

        return compareMetrics(o1, o2);
    }

    private boolean canRender( InternalRenderMetrics o1 ) {
        try {
            if (o1.getRenderMetricsFactory() == null) {
                ProjectPlugin.log(o1
                        + " is not implemented correctly.  getRenderMetricsFactory returns null.  " + //$NON-NLS-1$
                        "Consider extending AbstractRenderMetrics"); //$NON-NLS-1$
                return false;
            }

            if (!o1.getRenderMetricsFactory().canRender(o1.getRenderContext()))
                return false;
        } catch (Throwable e) {
            ProjectPlugin.log("Error while calling CanRender() on " + o1.getId(), e); //$NON-NLS-1$
            return false;
        }   
        return true;
    }

    /**
     * Compares two metrics return a value of 0 (same), -1 (o1 preferred), 1 (02 preferred)
     *
     * @param o1
     * @param o2
     * @return
     */
    private int compareMetrics ( InternalRenderMetrics o1, InternalRenderMetrics o2 ){
        int first = -1;
        int last = 1;
       
        // check the layer/map blackboard for a preferred or non-preferred renderer
        int perferredMapRenderer = rateUsingBlackboardSettings(o1, o1.getRenderContext().getMap().getBlackboard());
        if (perferredMapRenderer > 0){
            return first;
        }
        if (perferredMapRenderer < 0){
            return last;
        }
       
        double r1 = rate(o1);
        double r2 = rate(o2);
       
        //lower rating better
        if (r1 > r2) return last;
        if (r1 < r2) return first;
       
        return 0;
    }
   
    /*
     * Weighting to apply to metrics when computing a rating for a given metrics factory.
     */
    protected final double WEIGHT_RENDER_APPEARANCE_METRIC = 0.2;
    protected final double WEIGHT_USER_APPEARANCE_METRIC = 0.25;
    protected final double WEIGHT_SCALERANGE_METRIC = 0.15;
    protected final double WEIGHT_LATENCY_METRIC = 0.1;
    protected final double WEIGHT_DRAWING_TIME_METRIC = 0.1;
    protected final double WEIGHT_RESOLUTION_METRIC = 0.1;
    protected final double WEIGHT_MULTILAYER_METRIC = 0.1;

    protected final long MAXIMUM_LATENCY =  120000 //2 minutes
    protected final long MAXIMUM_DRAWINGTIME = 120000; //2 minutes
   
    /**
     * Computes a rating for the metric.  The rating for the metric is based on the
     * appearance metrics, speed metrics, resolution metrics. 
     * <p>
     * Each metric is converted to a percent between 0 & 1 and given a weighting depending
     * on how important the metric is.  Appearance metrics currently have higher weighting
     * that performance.
     * </p>
     *
     *
     * @param metrics
     * @return A rating for a given metric.  The lower the rating the better fit the metric is.
     */
    private double rate( InternalRenderMetrics metrics ) {
        ILayer layer = metrics.getRenderContext().getLayer();
        final IStyleBlackboard style = layer.getStyleBlackboard();
       
        //render metrics -
        //guarenteed to be between 0 & 1 - higher better so we subtract one to get make lower better
        double renderAppearanceMetric = 1 - metrics.getUserAppearanceMetric(style);
        double userAppearanceMetric = 1 - metrics.getRenderAppearanceMetric(style);
       
        double latencyMetric = metrics.getLatencyMetric();
        latencyMetric = latencyMetric / MAXIMUM_LATENCY;
       
        double drawingTimeMetric = metrics.getDrawingTimeMetric();
        drawingTimeMetric = drawingTimeMetric / MAXIMUM_DRAWINGTIME;
       
        // resolution metric - close to 1 the better
        //worst case is the screen size
        double width = metrics.getRenderContext().getMapDisplay().getWidth();
        double resolutionMetric = metrics.getResolutionMetric();
        double diff = Math.abs(resolutionMetric - 1);
        if (diff == 0){
            resolutionMetric = 0; //perfect match (lower is better)
        }else{
            resolutionMetric = (diff / width)//lower number
        }
       
        int multiLayerMetric = 1 - rateMultiLayerRenderer(metrics);
        double scaleRangeMetric = 1 - rateScaleRange(metrics);
       
        double rating = renderAppearanceMetric * WEIGHT_RENDER_APPEARANCE_METRIC;
        rating += userAppearanceMetric * WEIGHT_USER_APPEARANCE_METRIC;
        rating += latencyMetric * WEIGHT_LATENCY_METRIC;
        rating += drawingTimeMetric * WEIGHT_DRAWING_TIME_METRIC;
        rating += resolutionMetric * WEIGHT_RESOLUTION_METRIC;
        rating += multiLayerMetric * WEIGHT_MULTILAYER_METRIC;
        rating += scaleRangeMetric * WEIGHT_SCALERANGE_METRIC;
       
        return rating;
       
//        int rating = rateAppearance(metrics);
//        rating += ratePerformance(metrics);
//        rating += rateScaleRange(metrics);
//        rating = rateMultiLayerRenderer(metrics, rating);
//        rating = rateUsingBlackboardSettings(metrics, metrics.getRenderContext().getMap().getBlackboard(), 100,rating);
//        rating = rateUsingBlackboardSettings(metrics, metrics.getRenderContext().getLayer().getBlackboard(), 200,rating);
//        if (rating == 0)
//            return -1;
//        return rating;
    }

    /**
     * If the renderer can render at the current scale then 1 will be returned
     *
     * @param metrics
     * @return 1 if the renderer can render at the current scale.
     */
    private int rateScaleRange( InternalRenderMetrics metrics ) {
        Set<Range<Double>> scales = metrics.getValidScaleRanges();
        for( Range<Double> range : scales ) {
            if( range.contains(metrics.getRenderContext().getViewportModel().getScaleDenominator()) ){
                return 1;
            }
        }
        return 0;
    }

    /**
     * Looks if the renderer is set on the style blackboard as the preferred renderer.  If
     * so then the rating is inflated so that this renderer is always used.
     *
     * Can either add to the renderer score if it is a preferred renderer, or detract from
     * a renderer score if it is a last resort renderer.
     *
     * @param metrics metrics in question
     * @param blackboard the blackboard to search (map or layer)
     *
     * @return 1 if preferred renderer<br>0 neither preferred or last resort<br>-1 if last resort renderer
     */
    private int rateUsingBlackboardSettings( InternalRenderMetrics metrics, IBlackboard blackboard) {
        String rendererId = metrics.getId();
        if (rendererId == null)
            return 0;
        String preferredRenderer = blackboard.getString(RendererCreatorImpl.PREFERRED_RENDERER_ID);
        String lastResortRenderer = blackboard.getString(RendererCreatorImpl.LAST_RESORT_RENDERER_ID);
        if ( rendererId.equals(preferredRenderer)) {
            return 1;
        }
        if ( rendererId.equals(lastResortRenderer)) {
            return -1;
        }
        return 0;
    }

    /**
     * if it can render more than one layer in the list
     *
     * @return 0 - if cannot use multi layer renderer<br>1 - if multi layer render can be used.
     */
    private int rateMultiLayerRenderer( InternalRenderMetrics metrics ) {
        if (MultiLayerRenderer.class.isAssignableFrom(metrics.getRenderMetricsFactory()
                .getRendererType())) {
            int indexOf = getLayers().indexOf(metrics.getRenderContext().getLayer());
            if( indexOf>0 )
                if( metrics.canAddLayer(getLayers().get(indexOf-1)) )
                    return 1;
            if( indexOf<getLayers().size()-1 )
                if( metrics.canAddLayer(getLayers().get(indexOf+1)) )
                    return 1;
        }
        return 0;
    }

}
TOP

Related Classes of org.locationtech.udig.project.internal.render.impl.RenderMetricsSorter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.