/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2011 Ausenco Engineering Canada Inc.
*
* 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 com.jaamsim.DisplayModels;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import com.jaamsim.Graphics.DisplayEntity;
import com.jaamsim.Graphics.Tag;
import com.jaamsim.basicsim.Entity;
import com.jaamsim.input.BooleanInput;
import com.jaamsim.input.ColourInput;
import com.jaamsim.input.EnumInput;
import com.jaamsim.input.Keyword;
import com.jaamsim.math.Color4d;
import com.jaamsim.math.Mat4d;
import com.jaamsim.math.Transform;
import com.jaamsim.math.Vec3d;
import com.jaamsim.math.Vec4d;
import com.jaamsim.render.DisplayModelBinding;
import com.jaamsim.render.LineProxy;
import com.jaamsim.render.PolygonProxy;
import com.jaamsim.render.RenderProxy;
import com.jaamsim.render.RenderUtils;
import com.jaamsim.render.VisibilityInfo;
public class ShapeModel extends DisplayModel {
public static final String TAG_CONTENTS = "CONTENTS";
public static final String TAG_CONTENTS2 = "CONTENTS2";
public static final String TAG_CAPACITY = "CAPACITY";
public static final String TAG_OUTLINES = "OUTLINES";
public static final String TAG_TRACKFILL = "TRACKFILL";
public static final String TAG_BODY = "BODY";
public static final String TAG_SERVICE = "SERVICE";
public static final String TAG_LINES = "LINES";
public static final String TAG_SECONDARY_LINES = "SECONDARY_LINES";
public static final String TAG_ARROW_DOWN = "ARROWS_DOWN";
public static final String TAG_ARROW_UP = "ARROWS_UP";
enum ValidShapes {
PIXELS,
TRUCK2D,
SHIP2D,
RECTANGLE,
STACKER2D,
RECLAIMER2D,
BRIDGE2D,
CRUSHER2D,
GANTRY2D,
DOZER2D,
CRUSHER2ND2D,
SLAVESTACKER2D,
DUALQUADRANT2D,
SINGLEQUADRANT2D,
LINEAR2D,
TRAVELLING2D,
CIRCLE,
ARROW2D,
TRIANGLE,
CONTENTSPIXELS,
CRUSHINGPLANT2D,
BARGAUGE2D,
MINISHIP2D,
GRINDINGROLL2D,
SCREEN2D,
SAGMILL2D,
RECTANGLEWITHARROWS,
}
@Keyword(description = "The shape of a display model determines the appearance of the display model.",
exampleList = { "CIRCLE" })
private final EnumInput<ValidShapes> shape;
@Keyword(description = "The colour for the filled part of the display model.",
exampleList = { "red" })
private final ColourInput fillColour;
@Keyword(description = "The colour for the outline part of the display model.",
exampleList = { "magenta" })
private final ColourInput outlineColour;
@Keyword(description = "If the value is true, then the display model will have a solid fill. Otherwise, the display model " +
"will appear as hollow.",
exampleList = { "FALSE" })
private final BooleanInput filled;
@Keyword(description = "If the value is true, then the display model outline will be a bold line. Otherwise the outline " +
"will be one pixel wide line.",
exampleList = { "TRUE" })
private final BooleanInput bold;
{
shape = new EnumInput<>(ValidShapes.class, "Shape", "Key Inputs", ValidShapes.CIRCLE);
this.addInput(shape);
fillColour = new ColourInput("FillColour", "Key Inputs", ColourInput.MED_GREY);
this.addInput(fillColour);
this.addSynonym(fillColour, "FillColor");
outlineColour = new ColourInput("OutlineColour", "Key Inputs", ColourInput.BLACK);
this.addInput(outlineColour);
this.addSynonym(outlineColour, "OutlineColor");
filled = new BooleanInput("Filled", "Key Inputs", true);
this.addInput(filled);
bold = new BooleanInput("Bold", "Key Inputs", false);
this.addInput(bold);
}
public ShapeModel() {}
public String getShapeName() {
return shape.getValue().name();
}
@Override
public boolean canDisplayEntity(Entity ent) {
return (ent instanceof DisplayEntity);
}
@Override
public DisplayModelBinding getBinding(Entity ent) {
return new Binding(ent, this);
}
private class Binding extends DisplayModelBinding {
private ArrayList<RenderProxy> cachedProxies;
private DisplayEntity dispEnt;
private Transform transCache;
private Vec3d scaleCache;
private HashMap<String, Tag> tagsCache = emptyTagSet;
private ValidShapes shapeCache;
private VisibilityInfo viCache;
private Color4d fillColourCache;
private Color4d outlineColourCache;
private boolean filledCache;
private boolean boldCache;
public Binding(Entity ent, DisplayModel dm) {
super(ent, dm);
dispEnt = (DisplayEntity)ent;
if (dispEnt != null) {
}
}
private void updateCache(double simTime) {
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
HashMap<String, Tag> tags = getTags();
VisibilityInfo vi = getVisibilityInfo();
ValidShapes sc = shape.getValue();
Color4d fc = fillColour.getValue();
Color4d oc = outlineColour.getValue();
boolean fill = filled.getValue();
boolean bld = bold.getValue();
boolean dirty = false;
dirty = dirty || !compare(transCache, trans);
dirty = dirty || dirty_vec3d(scaleCache, scale);
dirty = dirty || dirty_tags(tagsCache, tags);
dirty = dirty || !compare(shapeCache, sc);
dirty = dirty || !compare(viCache, vi);
dirty = dirty || fillColourCache != fc;
dirty = dirty || outlineColourCache != oc;
dirty = dirty || filledCache != fill;
dirty = dirty || boldCache != bld;
transCache = trans;
scaleCache = scale;
tagsCache = new HashMap<>(tags);
shapeCache = sc;
viCache = vi;
fillColourCache = fc;
outlineColourCache = oc;
filledCache = fill;
boldCache = bld;
if (cachedProxies != null && !dirty) {
// Nothing changed
registerCacheHit("DisplayModelCompat");
return;
}
registerCacheMiss("DisplayModelCompat");
cachedProxies = new ArrayList<>();
List<Vec4d> points = null;
switch (shapeCache) {
case SHIP2D:
addShipProxies(simTime);
return;
case TRUCK2D:
addTruckProxies(simTime);
return;
case BARGAUGE2D:
addBarGaugeProxies(simTime);
return;
case CRUSHINGPLANT2D:
addCrushingPlantProxies(simTime);
return;
case ARROW2D:
addArrowProxies(simTime);
return;
case SINGLEQUADRANT2D:
addSingleQuadProxies(simTime);
return;
case DUALQUADRANT2D:
addDualQuadProxies(simTime);
return;
case TRAVELLING2D:
addTravellingProxies(simTime);
return;
case STACKER2D:
case RECLAIMER2D:
addStackerProxies(simTime);
return;
case CRUSHER2D:
addCrusher2DProxies(simTime);
return;
case CIRCLE:
points = RenderUtils.CIRCLE_POINTS;
break;
case RECTANGLE:
points = RenderUtils.RECT_POINTS;
break;
case TRIANGLE:
points = RenderUtils.TRIANGLE_POINTS;
break;
case BRIDGE2D:
case CONTENTSPIXELS:
case CRUSHER2ND2D:
case DOZER2D:
case GANTRY2D:
case GRINDINGROLL2D:
case LINEAR2D:
case MINISHIP2D:
case PIXELS:
case RECTANGLEWITHARROWS:
case SAGMILL2D:
case SCREEN2D:
case SLAVESTACKER2D:
// these are currently not implemented
return;
}
// Gather some inputs
if (isTagVisible(ShapeModel.TAG_OUTLINES))
{
Color4d colour = getTagColor(ShapeModel.TAG_OUTLINES, outlineColourCache);
cachedProxies.add(new PolygonProxy(points, trans, scale, colour, true, (boldCache ? 2 : 1), getVisibilityInfo(), pickingID));
}
if (filledCache && isTagVisible(ShapeModel.TAG_CONTENTS))
{
Color4d colour = getTagColor(ShapeModel.TAG_CONTENTS, fillColourCache);
cachedProxies.add(new PolygonProxy(points, trans, scale, colour, false, 1, getVisibilityInfo(), pickingID));
}
}
private boolean isTagVisible(String name) {
Tag t = tagsCache.get(name);
if (t == null) return true;
return t.visible;
}
private Color4d getTagColor(String name, Color4d def) {
Tag t = tagsCache.get(name);
if (t == null || t.colors == null || t.colors.length == 0) return def;
return t.colors[0];
}
@Override
public void collectProxies(double simTime, ArrayList<RenderProxy> out) {
// This is slightly quirky behaviour, as a null entity will be shown because we use that for previews
if (dispEnt == null || !dispEnt.getShow()) {
return;
}
updateCache(simTime);
out.addAll(cachedProxies);
}
private Transform getTransform(double simTime) {
if (dispEnt == null) {
return Transform.ident;
}
return dispEnt.getGlobalTrans();
}
private Vec3d getScale() {
if (dispEnt == null) {
return DisplayModel.ONES;
}
Vec3d size = dispEnt.getSize();
size.mul3(getModelScale());
return size;
}
private long getPickingID() {
if (dispEnt == null) {
return 0;
}
return dispEnt.getEntityNumber();
}
private HashMap<String, Tag> getTags() {
if (dispEnt == null) {
return emptyTagSet;
}
return dispEnt.getTagSet();
}
private void addArrowProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
Color4d fillColour = getTagColor(ShapeModel.TAG_CONTENTS, ColourInput.BLACK);
cachedProxies.add(new PolygonProxy(arrowHeadVerts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(arrowTailVerts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
Color4d outlineColour= getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
cachedProxies.add(new PolygonProxy(arrowOutlineVerts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
}
private void addShipProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
// Now this is very 'shippy' behaviour and basically hand copied from the old DisplayModels (and supporting cast)
// Hull
Color4d hullColour = getTagColor(ShapeModel.TAG_BODY, ColourInput.LIGHT_GREY);
cachedProxies.add(new PolygonProxy(hullVerts, trans, scale, hullColour, false, 1, getVisibilityInfo(), pickingID));
// Outline
Color4d outlineColour= getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
cachedProxies.add(new PolygonProxy(hullVerts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
Transform cabinTrans = new Transform(trans);
cabinTrans.getTransRef().z += scale.y * 0.01; // Bump the cabin up a touch to prevent Z fighting
// Cabin
cachedProxies.add(new PolygonProxy(shipCabinVerts, cabinTrans, scale, ColourInput.BLACK, false, 1, getVisibilityInfo(), pickingID));
// Add the contents parcels
Tag t = tagsCache.get(ShapeModel.TAG_CONTENTS);
double[] sizes = null;
Color4d[] colours = null;
if (t != null) {
sizes = t.sizes;
colours = t.colors;
}
Tag t2 = tagsCache.get(ShapeModel.TAG_OUTLINES);
double[] outlineSizes = null;
if(t2 != null ) {
outlineSizes = t2.sizes;
}
cachedProxies.addAll(buildContents(sizes, colours, outlineSizes, shipContentsTrans, trans, scale, pickingID));
}
private void addTruckProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
// Add a yellow rectangle for the cab
cachedProxies.add(new PolygonProxy(truckCabVerts, trans, scale, ColourInput.YELLOW, false, 1, getVisibilityInfo(), pickingID));
Tag t = tagsCache.get(ShapeModel.TAG_CONTENTS);
double[] sizes = null;
Color4d[] colours = null;
if (t != null) {
sizes = t.sizes;
colours = t.colors;
}
cachedProxies.addAll(buildContents(sizes, colours, null, truckContentsTrans, trans, scale, pickingID));
}
private void addBarGaugeProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
Tag tag_contents = tagsCache.get(ShapeModel.TAG_CONTENTS);
if (tag_contents == null || tag_contents.sizes == null || tag_contents.colors == null ||
tag_contents.colors.length < tag_contents.sizes.length) {
// Bail out, not properly initialized
return;
}
double[] sizes = tag_contents.sizes;
Tag tag_contents2 = tagsCache.get(ShapeModel.TAG_CONTENTS2);
double[] rescapacities = null;
Color4d[] rescolours = null;
if (tag_contents2 != null) {
rescapacities = tag_contents2.sizes;
rescolours = tag_contents2.colors;
}
Color4d outlineColour = getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
Color4d backgroundColour = getTagColor(ShapeModel.TAG_BODY, ColourInput.WHITE);
Tag tag_cap = tagsCache.get(ShapeModel.TAG_CAPACITY);
double[] capacities;
if (tag_cap == null || tag_cap.sizes == null || tag_cap.sizes.length != sizes.length) {
capacities = new double[sizes.length];
for (int i = 0; i < sizes.length; ++i) {
capacities[i] = 1.0d;
}
}
else {
capacities = tag_cap.sizes;
}
double totalCap = 0;
for (int i = 0; i < capacities.length; ++i) {
totalCap += capacities[i];
}
if (totalCap == 0) totalCap = 1; // Guard against div by 0
// Add the background and outline
cachedProxies.add(new PolygonProxy(RenderUtils.RECT_POINTS, trans, scale, backgroundColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(RenderUtils.RECT_POINTS, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
double accumWidth = 0;
for (int i = 0; i < sizes.length; ++i) {
// Add a rectangle for each size
double size = sizes[i];
double width = capacities[i]/totalCap;
double startX = accumWidth - 0.5;
double endX = accumWidth + width - 0.5;
accumWidth += width;
double startY = -0.5;
double endY = size - 0.5;
List<Vec4d> contentsPoints = new ArrayList<>();
contentsPoints.add(new Vec4d( endX, startY, 0, 1.0d));
contentsPoints.add(new Vec4d( endX, endY, 0, 1.0d));
contentsPoints.add(new Vec4d(startX, endY, 0, 1.0d));
contentsPoints.add(new Vec4d(startX, startY, 0, 1.0d));
cachedProxies.add(new PolygonProxy(contentsPoints, trans, scale, tag_contents.colors[i], false, 1, getVisibilityInfo(), pickingID));
if (rescapacities != null) {
double startResY = endY;
double endResY = startResY + rescapacities[i];
List<Vec4d> rescontentsPoints = new ArrayList<>();
rescontentsPoints.add(new Vec4d( endX, startResY, 0, 1.0d));
rescontentsPoints.add(new Vec4d( endX, endResY, 0, 1.0d));
rescontentsPoints.add(new Vec4d(startX, endResY, 0, 1.0d));
rescontentsPoints.add(new Vec4d(startX, startResY, 0, 1.0d));
cachedProxies.add(new PolygonProxy(rescontentsPoints, trans, scale, rescolours[i], false, 1, getVisibilityInfo(), pickingID));
}
}
}
private void addCrushingPlantProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
Color4d outlineColour = getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
Color4d fillColour = getTagColor(ShapeModel.TAG_CONTENTS, ColourInput.MED_GREY);
// Top
cachedProxies.add(new PolygonProxy(crushingPlantTopVerts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(crushingPlantTopVerts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
// Bottom
cachedProxies.add(new PolygonProxy(crushingPlantBotVerts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(crushingPlantBotVerts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
}
private void addSingleQuadProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
// Add the lines
Mat4d lineTrans = new Mat4d();
trans.getMat4d(lineTrans);
lineTrans.scaleCols3(scale);
List<Vec4d> points = RenderUtils.transformPoints(lineTrans, singleQuadLinePoints, 0);
cachedProxies.add(new LineProxy(points, ColourInput.BLACK, 1, getVisibilityInfo(), pickingID));
Color4d outlineColour = getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
Color4d fillColour = getTagColor(ShapeModel.TAG_CONTENTS, ColourInput.MED_GREY);
cachedProxies.add(new PolygonProxy(singleQuadRectVerts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(singleQuadRectVerts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
}
private void addDualQuadProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
// Add the lines
Mat4d lineTrans = new Mat4d();
trans.getMat4d(lineTrans);
lineTrans.scaleCols3(scale);
List<Vec4d> points = RenderUtils.transformPoints(lineTrans, dualQuadLinePoints, 0);
cachedProxies.add(new LineProxy(points, ColourInput.BLACK, 1, getVisibilityInfo(), pickingID));
Color4d outlineColour = getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
Color4d fillColour = getTagColor(ShapeModel.TAG_CONTENTS, ColourInput.MED_GREY);
cachedProxies.add(new PolygonProxy(dualQuadRect0Verts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(dualQuadRect1Verts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(dualQuadRect2Verts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(dualQuadOutlineVerts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
}
private void addTravellingProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
Color4d outlineColour = getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
Color4d fillColour = getTagColor(ShapeModel.TAG_CONTENTS, ColourInput.MED_GREY);
Color4d trackColour = getTagColor(ShapeModel.TAG_TRACKFILL, ColourInput.MED_GREY);
cachedProxies.add(new PolygonProxy(travellingRect1Verts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(travellingRect1Verts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(travellingRect3Verts, trans, scale, fillColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(travellingRect3Verts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(travellingRect2Verts, trans, scale, trackColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(travellingRect2Verts, trans, scale, trackColour, true, 1, getVisibilityInfo(), pickingID));
}
private void addStackerProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
Transform contentsTrans = new Transform(trans);
contentsTrans.getTransRef().z += scale.y * 0.001;
Color4d outlineColour = getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
Color4d contentsColour = getTagColor(ShapeModel.TAG_CONTENTS, ColourInput.MED_GREY);
Color4d trackColour = ColourInput.MED_GREY;
// This is gross, but until we have proper draw ordering it's the kind of thing we have to do to keep the
// Stacker-reclaimer appearing above the stock piles reliably
Vec3d fixedScale = new Vec3d(scale);
fixedScale.z = 0.1;
cachedProxies.add(new PolygonProxy(stackerRect1Verts, trans, fixedScale, trackColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(stackerRect1Verts, trans, fixedScale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(stackerRect2Verts, contentsTrans, fixedScale, contentsColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(stackerRect2Verts, contentsTrans, fixedScale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
}
private void addCrusher2DProxies(double simTime) {
// Gather some inputs
Transform trans = getTransform(simTime);
Vec3d scale = getScale();
long pickingID = getPickingID();
Color4d outlineColour = getTagColor(ShapeModel.TAG_OUTLINES, ColourInput.BLACK);
Color4d contentsColour = getTagColor(ShapeModel.TAG_CONTENTS, ColourInput.MED_GREY);
cachedProxies.add(new PolygonProxy(RenderUtils.RECT_POINTS, trans, scale, contentsColour, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(RenderUtils.RECT_POINTS, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(crusher2DVerts, trans, scale, ColourInput.LIGHT_GREY, false, 1, getVisibilityInfo(), pickingID));
cachedProxies.add(new PolygonProxy(crusher2DVerts, trans, scale, outlineColour, true, 1, getVisibilityInfo(), pickingID));
// Add the lines
Mat4d lineTrans = new Mat4d();
trans.getMat4d(lineTrans);
lineTrans.scaleCols3(scale);
List<Vec4d> points = RenderUtils.transformPoints(lineTrans, crusher2DLines, 0);
cachedProxies.add(new LineProxy(points, ColourInput.BLACK, 1, getVisibilityInfo(), pickingID));
}
// A disturbingly deep helper to allow trucks and ships to share contents building code
// This class needs to either die or get refactored
private List<RenderProxy> buildContents(double[] sizes, Color4d[] colours, double[] outlineSizes, Mat4d subTrans,
Transform trans, Vec3d scale, long pickingID) {
List<RenderProxy> ret = new ArrayList<>();
if (sizes == null || colours == null || sizes.length != colours.length) {
// We are either out of sync or this is a ShipType, either way draw an empty cargo hold
// Add a single grey rectangle
List<Vec4d> contentsPoints = new ArrayList<>();
contentsPoints.add(new Vec4d( 1, -0.5, 0.001, 1.0d));
contentsPoints.add(new Vec4d( 1, 0.5, 0.001, 1.0d));
contentsPoints.add(new Vec4d( 0, 0.5, 0.001, 1.0d));
contentsPoints.add(new Vec4d( 0, -0.5, 0.001, 1.0d));
for (int i = 0; i < contentsPoints.size(); ++i) {
contentsPoints.get(i).mult4(subTrans, contentsPoints.get(i));
}
ret.add(new PolygonProxy(contentsPoints, trans, scale, ColourInput.LIGHT_GREY, false, 1, getVisibilityInfo(), pickingID));
return ret;
}
double totalSize = 0.0d;
for (int i = 0; i < sizes.length; ++i) {
totalSize += sizes[i];
}
double sizeOffset = 0;
double totalOutlineSize = 0.0d;
int indexOfNextHold = 0;
// The following properties are expressed as a fraction of total cargo
double endOfNextHold = 1.0;
double gapBetweenHolds = 0.0075;
if( outlineSizes != null ) {
for (int i = 0; i < outlineSizes.length; i++) {
totalOutlineSize += outlineSizes[i];
}
// Determine the end of the next hold
if( outlineSizes.length > 0 )
endOfNextHold = outlineSizes[0] / totalOutlineSize;
}
for (int i = 0; i < sizes.length; ++i) {
// Add a rectangle for each parcel
double size = sizes[i];
double start = sizeOffset / totalSize;
double end = (sizeOffset + size) / totalSize;
List<Vec4d> contentsPoints = new ArrayList<>();
contentsPoints.add(new Vec4d( end, -0.5, 0.001, 1.0d));
contentsPoints.add(new Vec4d( end, 0.5, 0.001, 1.0d));
contentsPoints.add(new Vec4d(start, 0.5, 0.001, 1.0d));
contentsPoints.add(new Vec4d(start, -0.5, 0.001, 1.0d));
sizeOffset += size;
// Is this parcel the end of the hold?
if( Math.abs( end - endOfNextHold ) < 1.0E-9 ) {
sizeOffset += (gapBetweenHolds * totalSize);
// Update the end of the next hold
indexOfNextHold++;
if( outlineSizes != null ) {
if( indexOfNextHold < outlineSizes.length )
endOfNextHold += gapBetweenHolds + (outlineSizes[indexOfNextHold] / totalOutlineSize);
}
}
for (int j = 0; j < contentsPoints.size(); ++j) {
contentsPoints.get(j).mult4(subTrans, contentsPoints.get(j));
}
ret.add(new PolygonProxy(contentsPoints, trans, scale, colours[i], false, 1, getVisibilityInfo(), pickingID));
}
if( outlineSizes != null ) {
double outlineSizeOffset = 0;
for (int i = 0; i < outlineSizes.length; i++) {
// Add a rectangle for each hold
double outlineSize = outlineSizes[i];
double start = outlineSizeOffset / totalOutlineSize;
double end = (outlineSizeOffset + outlineSize) / totalOutlineSize;
List<Vec4d> outlinePoints = new ArrayList<>();
outlinePoints.add(new Vec4d( end, -0.5, 0.001, 1.0d));
outlinePoints.add(new Vec4d( end, 0.5, 0.001, 1.0d));
outlinePoints.add(new Vec4d(start, 0.5, 0.001, 1.0d));
outlinePoints.add(new Vec4d(start, -0.5, 0.001, 1.0d));
outlineSizeOffset += outlineSize + ( gapBetweenHolds * totalOutlineSize );
for (int j = 0; j < outlinePoints.size(); ++j) {
outlinePoints.get(j).mult4(subTrans, outlinePoints.get(j));
}
ret.add(new PolygonProxy(outlinePoints, trans, scale, ColourInput.BLACK, true, 1, getVisibilityInfo(), pickingID));
}
}
return ret;
}
}
private static final HashMap<String, Tag> emptyTagSet = new HashMap<>(0);
// Begin static data
// Since Arrows aren't convex, we need some more convoluted vertices
private static List<Vec4d> arrowHeadVerts;
private static List<Vec4d> arrowTailVerts;
private static List<Vec4d> arrowOutlineVerts;
private static List<Vec4d> truckCabVerts;
private static List<Vec4d> crushingPlantTopVerts;
private static List<Vec4d> crushingPlantBotVerts;
private static List<Vec4d> singleQuadLinePoints;
private static List<Vec4d> singleQuadRectVerts;
private static List<Vec4d> dualQuadLinePoints;
private static List<Vec4d> dualQuadOutlineVerts;
private static List<Vec4d> dualQuadRect0Verts;
private static List<Vec4d> dualQuadRect1Verts;
private static List<Vec4d> dualQuadRect2Verts;
private static List<Vec4d> travellingRect1Verts;
private static List<Vec4d> travellingRect2Verts;
private static List<Vec4d> travellingRect3Verts;
private static List<Vec4d> stackerRect1Verts;
private static List<Vec4d> stackerRect2Verts;
private static List<Vec4d> crusher2DVerts;
private static List<Vec4d> crusher2DLines;
private static List<Vec4d> hullVerts;
private static List<Vec4d> shipCabinVerts;
private static Mat4d shipContentsTrans;
private static Mat4d truckContentsTrans;
static {
hullVerts = new ArrayList<>(20);
hullVerts.add(new Vec4d(-0.35625d, -0.5d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.35d, -0.5d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.40625d, -0.42d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.459375d, -0.3d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.484375d, -0.21d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.5d, -0.05d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.5d, 0.05d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.484375d, 0.21d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.459375d, 0.3d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.40625d, 0.42d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(0.35d, 0.5d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.35625d, 0.5d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.4109375d, 0.45d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.4515625d, 0.36d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.5d, 0.23d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.5d, -0.23d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.4515625d, -0.36d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.4109375d, -0.45d, 0.0d, 1.0d));
hullVerts.add(new Vec4d(-0.35625d, -0.5d, 0.0d, 1.0d));
Mat4d shipCabinTrans = new Mat4d();
shipCabinTrans.setTranslate3(new Vec3d(-0.325, 0, 0));
shipCabinTrans.scaleCols3(new Vec3d(0.125, 0.7, 0));
shipCabinVerts = RenderUtils.transformPoints(shipCabinTrans, RenderUtils.RECT_POINTS, 0);
shipContentsTrans = new Mat4d();
shipContentsTrans.setTranslate3(new Vec3d(-0.25, 0.0, 0.0));
shipContentsTrans.scaleCols3(new Vec3d(0.65, 0.6, 1));
truckContentsTrans = new Mat4d();
truckContentsTrans.setTranslate3(new Vec3d(-0.5, 0.0, 0.0));
truckContentsTrans.scaleCols3(new Vec3d(0.75, 1, 1));
arrowHeadVerts = new ArrayList<>(3);
arrowHeadVerts.add(new Vec4d(-0.5, 0.0, 0.0, 1.0d));
arrowHeadVerts.add(new Vec4d(-0.1, -0.5, 0.0, 1.0d));
arrowHeadVerts.add(new Vec4d(-0.1, 0.5, 0.0, 1.0d));
arrowTailVerts = new ArrayList<>(4);
arrowTailVerts.add(new Vec4d(-0.1, -0.2, 0.0, 1.0d));
arrowTailVerts.add(new Vec4d( 0.5, -0.2, 0.0, 1.0d));
arrowTailVerts.add(new Vec4d( 0.5, 0.2, 0.0, 1.0d));
arrowTailVerts.add(new Vec4d(-0.1, 0.2, 0.0, 1.0d));
arrowOutlineVerts = new ArrayList<>(7);
arrowOutlineVerts.add(new Vec4d(-0.5, 0.0, 0.0, 1.0d));
arrowOutlineVerts.add(new Vec4d(-0.1, -0.5, 0.0, 1.0d));
arrowOutlineVerts.add(new Vec4d(-0.1, -0.2, 0.0, 1.0d));
arrowOutlineVerts.add(new Vec4d( 0.5, -0.2, 0.0, 1.0d));
arrowOutlineVerts.add(new Vec4d( 0.5, 0.2, 0.0, 1.0d));
arrowOutlineVerts.add(new Vec4d(-0.1, 0.2, 0.0, 1.0d));
arrowOutlineVerts.add(new Vec4d(-0.1, 0.5, 0.0, 1.0d));
truckCabVerts = new ArrayList<>(4);
truckCabVerts.add(new Vec4d( 0.5, 0.5, 0.0, 1.0d));
truckCabVerts.add(new Vec4d(0.25, 0.5, 0.0, 1.0d));
truckCabVerts.add(new Vec4d(0.25, -0.5, 0.0, 1.0d));
truckCabVerts.add(new Vec4d( 0.5, -0.5, 0.0, 1.0d));
crushingPlantBotVerts = new ArrayList<>(4);
crushingPlantBotVerts.add(new Vec4d( -0.17659f, -0.5f, 0.0f, 1.0d ));
crushingPlantBotVerts.add(new Vec4d( 0.15675f, -0.5f, 0.0f, 1.0d ));
crushingPlantBotVerts.add(new Vec4d( 0.15675f, -0.1f, 0.0f, 1.0d ));
crushingPlantBotVerts.add(new Vec4d( -0.17659f, -0.1f, 0.0f, 1.0d ));
crushingPlantTopVerts = new ArrayList<>(4);
crushingPlantTopVerts.add(new Vec4d( -0.17659f, 0f, 0.0f, 1.0d ));
crushingPlantTopVerts.add(new Vec4d( 0.15675f, 0f, 0.0f, 1.0d ));
crushingPlantTopVerts.add(new Vec4d( 0.49008f, 0.5f, 0.0f, 1.0d ));
crushingPlantTopVerts.add(new Vec4d( -0.50992f, 0.5f, 0.0f, 1.0d ));
singleQuadLinePoints = new ArrayList<>();
singleQuadLinePoints.add(new Vec4d( 0.4, 0.5, 0.0, 1.0d));
singleQuadLinePoints.add(new Vec4d(-0.4, 0.0, 0.0, 1.0d));
singleQuadLinePoints.add(new Vec4d(-0.4, 0.0, 0.0, 1.0d));
singleQuadLinePoints.add(new Vec4d( 0.4, -0.5, 0.0, 1.0d));
// Also add the arc lines
List<Vec4d> singleArcPoints = RenderUtils.getArcPoints(0.6, new Vec4d(-0.3, 0, 0, 1.0d),
Math.PI * 0.25,
Math.PI * 0.75, 10);
singleQuadLinePoints.addAll(singleArcPoints);
singleQuadRectVerts = new ArrayList<>();
singleQuadRectVerts.add(new Vec4d( 0.5, -0.0833333, 0.0, 1.0d));
singleQuadRectVerts.add(new Vec4d( 0.5, 0.0833333, 0.0, 1.0d));
singleQuadRectVerts.add(new Vec4d(-0.5, 0.0833333, 0.0, 1.0d));
singleQuadRectVerts.add(new Vec4d(-0.5, -0.0833333, 0.0, 1.0d));
dualQuadLinePoints = new ArrayList<>();
dualQuadLinePoints.add(new Vec4d(0.4, 0.045454545, 0.0, 1.0d));
dualQuadLinePoints.add(new Vec4d(-0.4, -0.227272727, 0.0, 1.0d));
dualQuadLinePoints.add(new Vec4d(-0.4, -0.227272727, 0.0, 1.0d));
dualQuadLinePoints.add(new Vec4d(0.4, -0.5, 0.0, 1.0d));
dualQuadLinePoints.add(new Vec4d( 0.4, 0.5, 0.0, 1.0d));
dualQuadLinePoints.add(new Vec4d( -0.4, 0.227272727, 0.0, 1.0d));
dualQuadLinePoints.add(new Vec4d( -0.4, 0.227272727, 0.0, 1.0d));
dualQuadLinePoints.add(new Vec4d( 0.4, -0.045454545, 0.0, 1.0d));
List<Vec4d> dualArcPoints = RenderUtils.getArcPoints(0.6, new Vec4d(-0.3, -0.227272727, 0, 1.0d),
Math.PI * 0.25,
Math.PI * 0.75, 10);
dualQuadLinePoints.addAll(dualArcPoints);
dualArcPoints = RenderUtils.getArcPoints(0.6, new Vec4d(-0.3, 0.227272727, 0, 1.0d),
Math.PI * 0.25,
Math.PI * 0.75, 10);
dualQuadLinePoints.addAll(dualArcPoints);
dualQuadOutlineVerts = new ArrayList<>();
dualQuadOutlineVerts.add(new Vec4d(-0.5, -0.272727273, 0.0, 1.0d));
dualQuadOutlineVerts.add(new Vec4d(-0.5, 0.272727273, 0.0, 1.0d));
dualQuadOutlineVerts.add(new Vec4d(0.5, 0.272727273, 0.0, 1.0d));
dualQuadOutlineVerts.add(new Vec4d(0.5, 0.181818182, 0.0, 1.0d));
dualQuadOutlineVerts.add(new Vec4d(-0.3, 0.181818182, 0.0, 1.0d));
dualQuadOutlineVerts.add(new Vec4d(-0.3, -0.181818182, 0.0, 1.0d));
dualQuadOutlineVerts.add(new Vec4d(0.5, -0.181818182, 0.0, 1.0d));
dualQuadOutlineVerts.add(new Vec4d(0.5, -0.272727273, 0.0, 1.0d));
dualQuadRect0Verts = new ArrayList<>();
dualQuadRect0Verts.add(new Vec4d(-0.5, -0.272727273, 0.0, 1.0d));
dualQuadRect0Verts.add(new Vec4d(0.5, -0.272727273, 0.0, 1.0d));
dualQuadRect0Verts.add(new Vec4d(0.5, -0.181818182, 0.0, 1.0d));
dualQuadRect0Verts.add(new Vec4d(-0.5, -0.181818182, 0.0, 1.0d));
dualQuadRect1Verts = new ArrayList<>();
dualQuadRect1Verts.add(new Vec4d(-0.5, -0.181818182, 0.0, 1.0d));
dualQuadRect1Verts.add(new Vec4d(-0.3, -0.181818182, 0.0, 1.0d));
dualQuadRect1Verts.add(new Vec4d(-0.3, 0.181818182, 0.0, 1.0d));
dualQuadRect1Verts.add(new Vec4d(-0.5, 0.181818182, 0.0, 1.0d));
dualQuadRect2Verts = new ArrayList<>();
dualQuadRect2Verts.add(new Vec4d(-0.5, 0.181818182, 0.0, 1.0d));
dualQuadRect2Verts.add(new Vec4d(0.5, 0.181818182, 0.0, 1.0d));
dualQuadRect2Verts.add(new Vec4d(0.5, 0.272727273, 0.0, 1.0d));
dualQuadRect2Verts.add(new Vec4d(-0.5, 0.272727273, 0.0, 1.0d));
travellingRect1Verts = new ArrayList<>();
travellingRect1Verts.add(new Vec4d(-0.2, -0.3, 0, 1.0d));
travellingRect1Verts.add(new Vec4d( 0.2, -0.3, 0, 1.0d));
travellingRect1Verts.add(new Vec4d( 0.2, 0.1, 0, 1.0d));
travellingRect1Verts.add(new Vec4d(-0.2, 0.1, 0, 1.0d));
travellingRect2Verts = new ArrayList<>();
travellingRect2Verts.add(new Vec4d(-0.5, -0.1, 0, 1.0d));
travellingRect2Verts.add(new Vec4d( 0.5, -0.1, 0, 1.0d));
travellingRect2Verts.add(new Vec4d( 0.5, 0.1, 0, 1.0d));
travellingRect2Verts.add(new Vec4d(-0.5, 0.1, 0, 1.0d));
travellingRect3Verts = new ArrayList<>();
travellingRect3Verts.add(new Vec4d(-0.1, -0.5, 0, 1.0d));
travellingRect3Verts.add(new Vec4d( 0.1, -0.5, 0, 1.0d));
travellingRect3Verts.add(new Vec4d( 0.1, 0.1, 0, 1.0d));
travellingRect3Verts.add(new Vec4d(-0.1, 0.1, 0, 1.0d));
stackerRect1Verts = new ArrayList<>();
stackerRect1Verts.add(new Vec4d( 0.3, -0.3, 0.1, 1.0d));
stackerRect1Verts.add(new Vec4d( 0.3, 0.3, 0.1, 1.0d));
stackerRect1Verts.add(new Vec4d(-0.3, 0.3, 0.1, 1.0d));
stackerRect1Verts.add(new Vec4d(-0.3, -0.3, 0.1, 1.0d));
stackerRect2Verts = new ArrayList<>();
stackerRect2Verts.add(new Vec4d(-0.1, 0.0, 0.1, 1.0d));
stackerRect2Verts.add(new Vec4d(-0.1, -0.5, 0.1, 1.0d));
stackerRect2Verts.add(new Vec4d( 0.1, -0.5, 0.1, 1.0d));
stackerRect2Verts.add(new Vec4d( 0.1, 0.0, 0.1, 1.0d));
crusher2DVerts = new ArrayList<>();
crusher2DVerts.add(new Vec4d( 0.45, -0.45, 0.0, 1.0));
crusher2DVerts.add(new Vec4d( 0.0, 0.25, 0.0, 1.0));
crusher2DVerts.add(new Vec4d(-0.45, -0.45, 0.0, 1.0));
crusher2DLines = new ArrayList<>();
crusher2DLines.add(new Vec4d(-0.45, -0.30, 0.0, 1.0));
crusher2DLines.add(new Vec4d(-0.10, 0.25, 0.0, 1.0));
crusher2DLines.add(new Vec4d(-0.10, 0.25, 0.0, 1.0));
crusher2DLines.add(new Vec4d(-0.45, 0.45, 0.0, 1.0));
crusher2DLines.add(new Vec4d( 0.45, -0.30, 0.0, 1.0));
crusher2DLines.add(new Vec4d( 0.10, 0.25, 0.0, 1.0));
crusher2DLines.add(new Vec4d( 0.10, 0.25, 0.0, 1.0));
crusher2DLines.add(new Vec4d( 0.45, 0.45, 0.0, 1.0));
}
}