package info.u250.c2d.box2deditor.gdx.support;
import info.u250.c2d.box2d.Box2dObject;
import info.u250.c2d.box2d.model.b2BodyDefModel;
import info.u250.c2d.box2d.model.b2JointDefModel;
import info.u250.c2d.box2d.model.fixture.b2CircleFixtureDefModel;
import info.u250.c2d.box2d.model.fixture.b2RectangleFixtureDefModel;
import info.u250.c2d.box2d.model.joint.b2DistanceJointDefModel;
import info.u250.c2d.box2d.model.joint.b2GearJointDefModel;
import info.u250.c2d.box2d.model.joint.b2PulleyJointDefModel;
import info.u250.c2d.box2d.model.joint.b2RopeJointDefModel;
import info.u250.c2d.box2deditor.adapter.DistanceJointDefModel;
import info.u250.c2d.box2deditor.adapter.FrictionJointDefModel;
import info.u250.c2d.box2deditor.adapter.PolygonFixtureDefModel;
import info.u250.c2d.box2deditor.adapter.PrismaticJointDefModel;
import info.u250.c2d.box2deditor.adapter.PulleyJointDefModel;
import info.u250.c2d.box2deditor.adapter.RevoluteJointDefModel;
import info.u250.c2d.box2deditor.adapter.RopeJointDefModel;
import info.u250.c2d.box2deditor.adapter.WeldJointDefModel;
import info.u250.c2d.box2deditor.adapter.WheelJointDefModel;
import info.u250.c2d.engine.Engine;
import info.u250.c2d.utils.Mathutils;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.EarClippingTriangulator;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.ShortArray;
public class Geometry {
public static final Color COLOR_DistanceJoint = new Color(Color.RED);
public static final Color COLOR_PrismaticJoint = new Color(Color.GREEN);
public static final Color COLOR_RevoluteJoint = new Color(Color.MAGENTA);
public static final Color COLOR_RopeJoint = new Color(Color.ORANGE);
public static final Color COLOR_WeldJoint = new Color(Color.YELLOW);
public static final Color COLOR_WheelJoint = new Color(Color.WHITE);
public static final Color COLOR_PulleyJoint = new Color(Color.CYAN);
public static final Color COLOR_FrictionJoint = new Color(Color.GRAY);
private static final Color CIRCLE = new Color(1, 0.5f, 1, 0.4f);
private static final Color CIRCLE_BORDER = new Color(1, 0.5f, 1, 0.8f);
private static final Color LINE = new Color(1f, 0.5f, 1f, 1f);
private static final Color BOX = new Color(0.5f, 1, 1f, 0.4f);
private static final Color BOX_BORDER = new Color(0.1f, 0.8f, 1f, 0.9f);
private static final Color POLYGON = new Color(0f, 1, 0.1f, 0.2f);
private static final Color POLYGON_BORDER = new Color(0f, 0f, 0f, 1f);
private static final Color FocusColor = new Color(0,0,1f,0.3f);
private static final Color FocusColor_BORDER = new Color(0,0,1,0.8f);
private static final EarClippingTriangulator earClippingTriangulator = new EarClippingTriangulator();
public static void renderPolygon(PolygonFixtureDefModel polygon,Vector2 position,float angle,boolean focus){
ShapeRenderer render = Engine.getShapeRenderer();
//rotate
final float cos = MathUtils.cosDeg(angle);
final float sin = MathUtils.sinDeg(angle);
final FloatArray vertices = new FloatArray();
// rotate if needed
for(Vector2 v:polygon.polygon){
if (angle != 0) {
vertices.add(cos * v.x - sin * v.y + position.x);
vertices.add(sin * v.x + cos * v.y + position.y);
}else{
vertices.add(v.x + position.x);
vertices.add(v.y + position.y);
}
}
ShortArray temp = earClippingTriangulator.computeTriangles(vertices);
for(int i=0;i<temp.size;i+=3){
render.setColor(focus?FocusColor:POLYGON);
render.begin(ShapeType.Filled);
render.triangle(vertices.get(2*temp.get(i)), vertices.get(2*temp.get(i)+1), vertices.get(2*temp.get(i+1)), vertices.get(2*temp.get(i+1)+1),vertices.get(2*temp.get(i+2)), vertices.get(2*temp.get(i+2)+1));
render.end();
render.setColor(Color.CYAN);
render.begin(ShapeType.Line);
render.triangle(vertices.get(2*temp.get(i)), vertices.get(2*temp.get(i)+1), vertices.get(2*temp.get(i+1)), vertices.get(2*temp.get(i+1)+1),vertices.get(2*temp.get(i+2)), vertices.get(2*temp.get(i+2)+1));
render.end();
}
render.setColor(focus?FocusColor_BORDER:POLYGON_BORDER);
render.begin(ShapeType.Line);
float sx = 0; float sy = 0;
float fx = 0; float fy = 0;
int vertexCount = vertices.size/2;
for (int i = 0; i < vertexCount; i++) {
float x = vertices.get(2*i) ;
float y = vertices.get(2*i+1);
if (i == 0) {
sx = fx = x ;
sy = fy = y ;
continue;
}
render.line(sx, sy, x, y);
sx = x;
sy = y;
}
render.line(fx, fy, sx, sy);
render.end();
}
public static void renderBox(b2RectangleFixtureDefModel box,Vector2 position,float angle,boolean focus){
ShapeRenderer render = Engine.getShapeRenderer();
float rect_angle = new Vector2(box.width,box.height).angle();
float half_diagonal = (float)Math.sqrt(box.width*box.width+box.height*box.height)/2;
render.setColor(focus?FocusColor:BOX);
render.begin(ShapeType.Filled);
render.triangle(
position.x+MathUtils.cosDeg(180+rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(180+rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(-rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(-rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(rect_angle+angle)*half_diagonal);
render.triangle(
position.x+MathUtils.cosDeg(180-rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(180-rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(180+rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(180+rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(rect_angle+angle)*half_diagonal);
render.end();
render.setColor(focus?FocusColor_BORDER:BOX_BORDER);
render.begin(ShapeType.Line);
render.triangle(
position.x+MathUtils.cosDeg(180+rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(180+rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(-rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(-rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(rect_angle+angle)*half_diagonal);
render.triangle(
position.x+MathUtils.cosDeg(180-rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(180-rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(180+rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(180+rect_angle+angle)*half_diagonal,
position.x+MathUtils.cosDeg(rect_angle+angle)*half_diagonal,
position.y+MathUtils.sinDeg(rect_angle+angle)*half_diagonal);
render.end();
}
public static void renderCircle(b2CircleFixtureDefModel circle,Vector2 position,float angle,boolean focus){
ShapeRenderer render = Engine.getShapeRenderer();
render.setColor(focus?FocusColor:CIRCLE);
render.begin(ShapeType.Filled);
render.circle(position.x, position.y, circle.radius);
render.end();
render.setColor(focus?FocusColor_BORDER:CIRCLE_BORDER);
render.begin(ShapeType.Line);
render.circle(position.x, position.y, circle.radius);
render.end();
render.setColor(LINE);
render.begin(ShapeType.Line);
render.line(
position.x, position.y,
position.x+circle.radius*MathUtils.cosDeg(angle),
position.y+circle.radius*MathUtils.sinDeg(angle));
render.end();
}
public static void ajustJoint(b2JointDefModel object){
try{
if(object instanceof WeldJointDefModel){
WeldJointDefModel model = WeldJointDefModel.class.cast(object);
model.localAnchorA.set(model.bodyA.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.localAnchorB.set(model.bodyB.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.referenceDegrees = model.bodyB.degrees - model.bodyA.degrees;
}else if(object instanceof RevoluteJointDefModel){
RevoluteJointDefModel model = RevoluteJointDefModel.class.cast(object);
if(model.useBodyACenter){
model.anchor.set(model.bodyA.position);
}else{
if(model.useBodyBCenter){
model.anchor.set(model.bodyB.position);
}
}
model.localAnchorA.set(model.bodyA.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.localAnchorB.set(model.bodyB.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.referenceDegrees = model.bodyB.degrees - model.bodyA.degrees;
}else if(object instanceof PrismaticJointDefModel){
PrismaticJointDefModel model = PrismaticJointDefModel.class.cast(object);
if(model.useBodyACenter){
model.anchor.set(model.bodyA.position);
}else{
if(model.useBodyBCenter){
model.anchor.set(model.bodyB.position);
}
}
if(model.useABCenterLine){
model.localAxisA.set(model.bodyB.position).sub(model.bodyA.position);
model.localAxisA.scl(1f/model.localAxisA.len());
}
model.localAnchorA.set(model.bodyA.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.localAnchorB.set(model.bodyB.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.referenceDegrees = model.bodyB.degrees - model.bodyA.degrees;
}else if(object instanceof FrictionJointDefModel){
FrictionJointDefModel model = FrictionJointDefModel.class.cast(object);
if(model.useBodyACenter){
model.anchor.set(model.bodyA.position);
}else{
if(model.useBodyBCenter){
model.anchor.set(model.bodyB.position);
}
}
model.localAnchorA.set(model.bodyA.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.localAnchorB.set(model.bodyB.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
}else if(object instanceof WheelJointDefModel){
WheelJointDefModel model = WheelJointDefModel.class.cast(object);
if(model.useBodyACenter){
model.anchor.set(model.bodyA.position);
}else{
if(model.useBodyBCenter){
model.anchor.set(model.bodyB.position);
}
}
if(model.useABCenterLine){
model.localAxisA.set(model.bodyB.position).sub(model.bodyA.position);
}
model.localAxisA.scl(1f/model.localAxisA.len());
model.localAnchorA.set(model.bodyA.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
model.localAnchorB.set(model.bodyB.body.getLocalPoint(model.anchor.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO));
}else if(object instanceof PulleyJointDefModel){
PulleyJointDefModel model = PulleyJointDefModel.class.cast(object);
if(model.setBodyAZero){
model.localAnchorA.set(0, 0);
}
if(model.setBodyBZero){
model.localAnchorB.set(0, 0);
}
final Vector2 worldA = model.bodyA.body.getWorldPoint(model.localAnchorA.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO);
final Vector2 worldB = model.bodyB.body.getWorldPoint(model.localAnchorB.cpy().scl(1f/Box2dObject.RADIO)).scl(Box2dObject.RADIO);
if(model.groundAAlignAnchorA){
model.groundAnchorA.x = worldA.x ;
}
if(model.groundBAlignAnchorB){
model.groundAnchorB.x = worldB.x ;
}
model.lengthA = worldA.dst(model.groundAnchorA);
model.lengthB = worldB.dst(model.groundAnchorB);
}else if(object instanceof RopeJointDefModel){
RopeJointDefModel model = RopeJointDefModel.class.cast(object);
if(model.setBodyAZero){
model.localAnchorA.set(0, 0);
}
if(model.setBodyBZero){
model.localAnchorB.set(0, 0);
}
if(model.autoCalculateLength){
model.maxLength =
model.bodyA.body.getWorldPoint(model.localAnchorA.cpy().scl(1f/Box2dObject.RADIO)).sub(
model.bodyB.body.getWorldPoint(model.localAnchorB.cpy().scl(1f/Box2dObject.RADIO))
).scl(Box2dObject.RADIO).len();
}
}else if(object instanceof DistanceJointDefModel){
DistanceJointDefModel model = DistanceJointDefModel.class.cast(object);
if(model.setBodyAZero){
model.localAnchorA.set(0, 0);
}
if(model.setBodyBZero){
model.localAnchorB.set(0, 0);
}
if(model.autoCalculateLength){
model.length =
model.bodyA.body.getWorldPoint(model.localAnchorA.cpy().scl(1f/Box2dObject.RADIO)).sub(
model.bodyB.body.getWorldPoint(model.localAnchorB.cpy().scl(1f/Box2dObject.RADIO))
).scl(Box2dObject.RADIO).len();
}
}
}catch(Exception ex){
ex.printStackTrace();
}
}
public static void splitPolygon(PolygonFixtureDefModel object){
object.vertices.clear();
final FloatArray vertices = new FloatArray();
for(Vector2 v:object.polygon){
vertices.add(v.x);
vertices.add(v.y);
}
ShortArray temp = earClippingTriangulator.computeTriangles(vertices);
for(int i=0;i<temp.size;i+=3){
Vector2[] vv = new Vector2[3];
vv[0] = new Vector2(vertices.get(2*temp.get(i)),vertices.get(2*temp.get(i)+1));
vv[1] = new Vector2(vertices.get(2*temp.get(i+1)),vertices.get(2*temp.get(i+1)+1));
vv[2] = new Vector2(vertices.get(2*temp.get(i+2)),vertices.get(2*temp.get(i+2)+1));
if (Mathutils.isClockwise(vv[0], vv[1], vv[2])) {
Vector2 vt = vv[0];
vv[0] = vv[2];
vv[2] = vt;
}
object.vertices.add(vv);
}
}
public static void renderJoint(b2JointDefModel b2Joint){
if(b2Joint.bodyA==null || b2Joint.bodyB==null)return;
if(b2Joint.bodyA.body==null || b2Joint.bodyB.body==null)return;
ShapeRenderer render = Engine.getShapeRenderer();
if(b2Joint instanceof b2DistanceJointDefModel){
final b2DistanceJointDefModel obj = b2DistanceJointDefModel.class.cast(b2Joint);
final Vector2 p1 = worldPoint(obj.bodyA,obj.localAnchorA);
final Vector2 p2 = worldPoint(obj.bodyB,obj.localAnchorB);
render.begin(ShapeType.Line);
render.line(p1.x, p1.y, p2.x, p2.y);
render.end();
}else if(b2Joint instanceof b2PulleyJointDefModel){
final b2PulleyJointDefModel obj = b2PulleyJointDefModel.class.cast(b2Joint);
Vector2 s1 = obj.groundAnchorA;
Vector2 s2 = obj.groundAnchorB;
final Vector2 p1 = worldPoint(obj.bodyA,obj.localAnchorA);
final Vector2 p2 = worldPoint(obj.bodyB,obj.localAnchorB);
render.begin(ShapeType.Line);
render.line(s1.x, s1.y, p1.x, p1.y);
render.line(s2.x, s2.y, p2.x, p2.y);
render.line(s1.x, s1.y, s2.x, s2.y);
render.end();
}else if(b2Joint instanceof PrismaticJointDefModel){
final PrismaticJointDefModel obj = PrismaticJointDefModel.class.cast(b2Joint);
Vector2 x1 = obj.bodyA.position;
Vector2 x2 = obj.bodyB.position;
Vector2 anchor = obj.anchor;
render.begin(ShapeType.Line);
render.line(x1.x, x1.y, anchor.x, anchor.y);
render.line(x2.x, x2.y, anchor.x, anchor.y);
render.end();
}else if(b2Joint instanceof RevoluteJointDefModel){
final RevoluteJointDefModel obj = RevoluteJointDefModel.class.cast(b2Joint);
Vector2 x1 = obj.bodyA.position;
Vector2 x2 = obj.bodyB.position;
Vector2 anchor = obj.anchor;
render.begin(ShapeType.Line);
render.line(x1.x, x1.y, anchor.x, anchor.y);
render.line(x2.x, x2.y, anchor.x, anchor.y);
render.end();
}else if(b2Joint instanceof b2RopeJointDefModel){
final b2RopeJointDefModel obj = b2RopeJointDefModel.class.cast(b2Joint);
Vector2 x1 = obj.bodyA.position;
Vector2 x2 = obj.bodyB.position;
final Vector2 p1 = worldPoint(obj.bodyA,obj.localAnchorA);
final Vector2 p2 = worldPoint(obj.bodyB,obj.localAnchorB);
render.begin(ShapeType.Line);
render.line(x1.x, x1.y, p1.x, p1.y);
render.line(p1.x, p1.y, p2.x, p2.y);
render.line(x2.x, x2.y, p2.x, p2.y);
render.end();
}else if(b2Joint instanceof WeldJointDefModel){
final WeldJointDefModel obj = WeldJointDefModel.class.cast(b2Joint);
Vector2 x1 = obj.bodyA.position;
Vector2 x2 = obj.bodyB.position;
Vector2 anchor = obj.anchor;
render.begin(ShapeType.Line);
render.line(x1.x, x1.y, anchor.x, anchor.y);
render.line(x2.x, x2.y, anchor.x, anchor.y);
render.end();
}else if(b2Joint instanceof WheelJointDefModel){
final WheelJointDefModel obj = WheelJointDefModel.class.cast(b2Joint);
Vector2 x1 = obj.bodyA.position;
Vector2 x2 = obj.bodyB.position;
Vector2 anchor = obj.anchor;
render.begin(ShapeType.Line);
render.line(x1.x, x1.y, anchor.x, anchor.y);
render.line(x2.x, x2.y, anchor.x, anchor.y);
render.end();
}else if(b2Joint instanceof FrictionJointDefModel){
final FrictionJointDefModel obj = FrictionJointDefModel.class.cast(b2Joint);
Vector2 x1 = obj.bodyA.position;
Vector2 x2 = obj.bodyB.position;
Vector2 anchor = obj.anchor;
render.begin(ShapeType.Line);
render.line(x1.x, x1.y, anchor.x, anchor.y);
render.line(x2.x, x2.y, anchor.x, anchor.y);
render.end();
}else if(b2Joint instanceof b2GearJointDefModel){
//TODO
}
}
static Vector2 worldPoint(b2BodyDefModel b2,Vector2 localVector){
Vector2 tmp = new Vector2();
try{
tmp.set(b2.body.getWorldPoint(localVector.cpy().scl(1f/Box2dObject.RADIO))).scl(Box2dObject.RADIO);
}catch(Exception ex){
//
}
return tmp;
}
}