/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2013 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.List;
import com.jaamsim.Graphics.Arrow;
import com.jaamsim.Graphics.PolylineInfo;
import com.jaamsim.basicsim.Entity;
import com.jaamsim.input.Keyword;
import com.jaamsim.input.Vec3dInput;
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.PolygonProxy;
import com.jaamsim.render.RenderProxy;
import com.jaamsim.units.DistanceUnit;
public class ArrowModel extends PolylineModel {
@Keyword(description = "A set of { x, y, z } numbers that define the size of the arrowhead " +
"in those directions at the end of the connector.",
example = "Arrow1 ArrowSize { 0.165 0.130 0.0 m }")
private final Vec3dInput arrowHeadSize;
private static List<Vec4d> arrowHeadVerts;
static {
arrowHeadVerts = new ArrayList<>(3);
arrowHeadVerts.add(new Vec4d(0.0, 0.0, 0.0, 1.0d));
arrowHeadVerts.add(new Vec4d(1.0, -0.5, 0.0, 1.0d));
arrowHeadVerts.add(new Vec4d(1.0, 0.5, 0.0, 1.0d));
}
{
arrowHeadSize = new Vec3dInput("ArrowSize", "Key Inputs", new Vec3d(0.1d, 0.1d, 0.0d));
arrowHeadSize.setUnitType(DistanceUnit.class);
this.addInput(arrowHeadSize);
arrowHeadSize.setHidden(true);
}
@Override
public DisplayModelBinding getBinding(Entity ent) {
return new Binding(ent, this);
}
private class Binding extends PolylineModel.Binding {
private Arrow arrowObservee;
private ArrayList<Vec4d> headPoints = null;
private RenderProxy cachedProxy = null;
private Vec3d startCache;
private Vec3d fromCache;
private Color4d colorCache;
private Vec3d arrowSizeCache;
public Binding(Entity ent, DisplayModel dm) {
super(ent, dm);
if (observee instanceof Arrow)
arrowObservee = (Arrow)observee;
}
private void updateHead(double simTime) {
PolylineInfo[] pointInfos = displayObservee.getScreenPoints(simTime);
if (pointInfos == null || pointInfos.length == 0)
return;
ArrayList<Vec3d> curvePoints = pointInfos[0].getCurvePoints();
Vec3d startPoint = curvePoints.get(curvePoints.size() - 1);
Vec3d fromPoint = curvePoints.get(curvePoints.size() - 2);
Color4d color = pointInfos[0].getColor();
boolean dirty = false;
Vec3d arrowSize;
if (arrowObservee != null)
arrowSize = arrowObservee.getArrowHeadSize();
else
arrowSize = arrowHeadSize.getValue();
dirty = dirty || dirty_vec3d(startCache, startPoint);
dirty = dirty || dirty_vec3d(fromCache, fromPoint);
dirty = dirty || dirty_col4d(colorCache, color);
dirty = dirty || dirty_vec3d(arrowSizeCache, arrowSize);
startCache = startPoint;
fromCache = fromPoint;
colorCache = color;
arrowSizeCache = arrowSize;
if (cachedProxy != null && !dirty) {
// up to date
return;
}
// Draw an arrow head at the last two points
if (selectionPoints.size() < 2) {
return;
}
// Calculate a z-rotation in the XY-plane
Vec3d zRot = new Vec3d();
zRot.sub3(fromPoint, startPoint);
zRot.set3(0.0d, 0.0d, Math.atan2(zRot.y, zRot.x));
Mat4d trans = new Mat4d();
trans.setEuler3(zRot);
trans.scaleCols3(arrowSize);
trans.setTranslate3(startPoint);
headPoints = new ArrayList<>(arrowHeadVerts.size());
for (Vec4d v : arrowHeadVerts) {
Vec4d tmp = new Vec4d();
tmp.mult4(trans, v);
headPoints.add(tmp);
}
cachedProxy = new PolygonProxy(headPoints, Transform.ident, DisplayModel.ONES, color,
false, 1, getVisibilityInfo(), observee.getEntityNumber());
}
@Override
public void collectProxies(double simTime, ArrayList<RenderProxy> out) {
if (displayObservee == null || !displayObservee.getShow()) {
return;
}
updateProxies(simTime);
updateHead(simTime);
super.collectProxies(simTime, out);
out.add(cachedProxy);
}
}
}