eu.tomylobo.routes.infrastructure.Route.java Source code

Java tutorial

Introduction

Here is the source code for eu.tomylobo.routes.infrastructure.Route.java

Source

/*
 * Copyright (C) 2012 TomyLobo
 *
 * This file is part of Routes.
 *
 * Routes is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
 */

package eu.tomylobo.routes.infrastructure;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Multimap;

import eu.tomylobo.abstraction.World;
import eu.tomylobo.abstraction.entity.Player;
import eu.tomylobo.math.Location;
import eu.tomylobo.math.Vector;
import eu.tomylobo.routes.Routes;
import eu.tomylobo.routes.commands.system.PermissionDeniedException;
import eu.tomylobo.routes.infrastructure.editor.VisualizedRoute;
import eu.tomylobo.routes.infrastructure.interpolation.Interpolation;
import eu.tomylobo.routes.infrastructure.interpolation.KochanekBartelsInterpolation;
import eu.tomylobo.routes.infrastructure.interpolation.ReparametrisingInterpolation;
import eu.tomylobo.routes.infrastructure.nodefilter.IdentityNodeFilter;
import eu.tomylobo.routes.infrastructure.nodefilter.NodeFilter;
import eu.tomylobo.routes.util.Ini;
import eu.tomylobo.routes.util.ScheduledTask;

/**
 * Represents a route from one point to another, consisting of multiple nodes.
 *
 * @author TomyLobo
 *
 */
public final class Route extends AbstractDirtyable {
    private final String name;
    private World world;

    private final List<Node> nodes = new ArrayList<Node>();
    private List<Node> filteredNodes = new ArrayList<Node>();

    //private Interpolation interpolation = new LinearInterpolation();
    private Interpolation interpolation = new ReparametrisingInterpolation(new KochanekBartelsInterpolation());
    private NodeFilter nodeFilter = IdentityNodeFilter.getInstance();

    private ScheduledTask task = new ScheduledTask(Routes.getInstance()) {
        @Override
        public void run() {
            clearVisualization();
        }
    };

    private VisualizedRoute visualizedRoute;

    public Route(String name) {
        this.name = name;

        addDirtyClient(Routes.getInstance().transportSystem);
    }

    public List<Node> getNodes() {
        return nodes;
    }

    public List<Node> getFilteredNodes() {
        if (filteredNodes == null)
            filteredNodes = nodeFilter.filter(world, nodes);

        return filteredNodes;
    }

    public void addNodes(Location... locations) {
        addNodes(-1, locations);
    }

    public void addNodes(int index, Location... locations) {
        Node[] nodes = new Node[locations.length];
        for (int i = 0; i < locations.length; ++i) {
            Location location = locations[i];
            World world = location.getWorld();
            if (this.world == null) {
                this.world = world;
            } else if (!this.world.equals(world)) {
                throw new IllegalArgumentException("New node must be in the same world.");
            }

            nodes[i] = new Node(location.getPosition());
        }
        addNodes(index, nodes);
    }

    public void addNodes(Node... nodes) {
        addNodes(-1, nodes);
    }

    public void addNodes(int index, Node... nodes) {
        if (index == -1) {
            index = this.nodes.size();
        }
        this.nodes.addAll(index, Arrays.asList(nodes));
        for (Node node : nodes) {
            node.addDirtyClient(this);
        }
        setDirty();
    }

    public Location getLocation(double position) {
        ensureClean();

        final Vector vec = interpolation.getPosition(position);
        if (vec == null)
            return null;

        return Location.fromEye(world, vec, interpolation.get1stDerivative(position));
    }

    public Vector getVelocity(double position) {
        ensureClean();

        return interpolation.get1stDerivative(position);
    }

    public void visualize(double pointsPerMeter, long ticks) {
        clearVisualization();

        visualizedRoute = new VisualizedRoute(this, pointsPerMeter);

        task.scheduleSyncDelayed(ticks);
    }

    public void save(Multimap<String, Multimap<String, String>> sections) {
        final String routeSectionName = "route " + name;
        final Multimap<String, String> routeSection = LinkedListMultimap.create();

        Ini.saveWorld(routeSection, "%s", world);
        routeSection.put("nodes", String.valueOf(nodes.size()));

        sections.put(routeSectionName, routeSection);

        for (int i = 0; i < nodes.size(); ++i) {
            final Node node = nodes.get(i);

            final String nodeName = name + "-" + i;
            node.save(sections, nodeName);
        }
    }

    public void load(Multimap<String, Multimap<String, String>> sections) {
        final String routeSectionName = "route " + name;
        final Multimap<String, String> routeSection = Ini.getOnlyValue(sections.get(routeSectionName));

        world = Ini.loadWorld(routeSection, "%s");
        int nNodes = Ini.getOnlyInt(routeSection.get("nodes"));

        nodes.clear();
        ((ArrayList<Node>) nodes).ensureCapacity(nNodes);
        for (int i = 0; i < nNodes; ++i) {
            final String nodeName = name + "-" + i;

            addNodes(new Node(sections, nodeName));
        }
        setDirty();
    }

    public double length() {
        ensureClean();

        return interpolation.arcLength(0, 1);
    }

    private void clearVisualization() {
        task.cancel();
        if (visualizedRoute != null) {
            visualizedRoute.removeEntities();
        }
    }

    public double getArcLength(double positionA, double positionB) {
        return interpolation.arcLength(positionA, positionB);
    }

    public World getWorld() {
        return world;
    }

    public int getSegment(double position) {
        return interpolation.getSegment(position);
    }

    public void checkPermission(Player player, String command) {
        if (!hasPermission(player, command))
            throw new PermissionDeniedException();
    }

    public boolean hasPermission(Player player, String command) {
        return player.hasPermission("routes." + command + "." + name);
    }

    public String getName() {
        return name;
    }

    public void removeNode(int index) {
        nodes.remove(index);
        setDirty();
    }

    public NodeFilter getFilter() {
        return nodeFilter;
    }

    public void setFilter(NodeFilter nodeFilter) {
        this.nodeFilter = nodeFilter;
        filteredNodes = null;
    }

    @Override
    public void ensureClean() {
        if (isDirty()) {
            filteredNodes = null;
            interpolation.setNodes(getFilteredNodes());
        }
        super.ensureClean();
    }
}