All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almasb.fxgl.physics.box2d.collision.shapes.CircleShape Maven / Gradle / Ivy

There is a newer version: 21.1
Show newest version
/*
 * FXGL - JavaFX Game Library. The MIT License (MIT).
 * Copyright (c) AlmasB ([email protected]).
 * See LICENSE for details.
 */

package com.almasb.fxgl.physics.box2d.collision.shapes;

import com.almasb.fxgl.core.math.Vec2;
import com.almasb.fxgl.physics.box2d.collision.AABB;
import com.almasb.fxgl.physics.box2d.collision.RayCastInput;
import com.almasb.fxgl.physics.box2d.collision.RayCastOutput;
import com.almasb.fxgl.physics.box2d.common.JBoxSettings;
import com.almasb.fxgl.physics.box2d.common.JBoxUtils;
import com.almasb.fxgl.physics.box2d.common.Rotation;
import com.almasb.fxgl.physics.box2d.common.Transform;

/**
 * A circle shape.
 */
public final class CircleShape extends Shape {

    public final Vec2 center = new Vec2();

    public CircleShape() {
        super(ShapeType.CIRCLE, 0);
    }

    @Override
    public Shape clone() {
        CircleShape shape = new CircleShape();
        shape.center.x = center.x;
        shape.center.y = center.y;
        shape.setRadius(this.getRadius());
        return shape;
    }

    @Override
    public int getChildCount() {
        return 1;
    }

    @Override
    public boolean testPoint(final Transform transform, final Vec2 p) {
        // Rot.mulToOutUnsafe(transform.q, m_p, center);
        // center.addLocal(transform.p);
        //
        // final Vec2 d = center.subLocal(p).negateLocal();
        // return Vec2.dot(d, d) <= radius * radius;
        final Rotation q = transform.q;
        final Vec2 tp = transform.p;
        float centerx = -(q.c * center.x - q.s * center.y + tp.x - p.x);
        float centery = -(q.s * center.x + q.c * center.y + tp.y - p.y);

        return centerx * centerx + centery * centery <= getRadius() * getRadius();
    }

    @Override
    public float computeDistanceToOut(Transform xf, Vec2 p, int childIndex, Vec2 normalOut) {
        final Rotation xfq = xf.q;
        float centerx = xfq.c * center.x - xfq.s * center.y + xf.p.x;
        float centery = xfq.s * center.x + xfq.c * center.y + xf.p.y;
        float dx = p.x - centerx;
        float dy = p.y - centery;
        float d1 = JBoxUtils.sqrt(dx * dx + dy * dy);
        normalOut.x = dx * 1 / d1;
        normalOut.y = dy * 1 / d1;
        return d1 - getRadius();
    }

    // Collision Detection in Interactive 3D Environments by Gino van den Bergen
    // From Section 3.1.2
    // x = s + a * r
    // norm(x) = radius
    @Override
    public boolean raycast(RayCastOutput output, RayCastInput input, Transform transform,
                                 int childIndex) {

        final Vec2 inputp1 = input.p1;
        final Vec2 inputp2 = input.p2;
        final Rotation tq = transform.q;
        final Vec2 tp = transform.p;

        // Rot.mulToOutUnsafe(transform.q, m_p, position);
        // position.addLocal(transform.p);
        final float positionx = tq.c * center.x - tq.s * center.y + tp.x;
        final float positiony = tq.s * center.x + tq.c * center.y + tp.y;

        final float sx = inputp1.x - positionx;
        final float sy = inputp1.y - positiony;
        // final float b = Vec2.dot(s, s) - radius * radius;
        final float b = sx * sx + sy * sy - getRadius() * getRadius();

        // Solve quadratic equation.
        final float rx = inputp2.x - inputp1.x;
        final float ry = inputp2.y - inputp1.y;
        // final float c = Vec2.dot(s, r);
        // final float rr = Vec2.dot(r, r);
        final float c = sx * rx + sy * ry;
        final float rr = rx * rx + ry * ry;
        final float sigma = c * c - rr * b;

        // Check for negative discriminant and short segment.
        if (sigma < 0.0f || rr < JBoxSettings.EPSILON) {
            return false;
        }

        // Find the point of intersection of the line with the circle.
        float a = -(c + JBoxUtils.sqrt(sigma));

        // Is the intersection point on the segment?
        if (0.0f <= a && a <= input.maxFraction * rr) {
            a /= rr;
            output.fraction = a;
            output.normal.x = rx * a + sx;
            output.normal.y = ry * a + sy;
            output.normal.getLengthAndNormalize();
            return true;
        }

        return false;
    }

    @Override
    public void computeAABB(final AABB aabb, final Transform transform, int childIndex) {
        final Rotation tq = transform.q;
        final Vec2 tp = transform.p;
        final float px = tq.c * center.x - tq.s * center.y + tp.x;
        final float py = tq.s * center.x + tq.c * center.y + tp.y;

        aabb.lowerBound.x = px - getRadius();
        aabb.lowerBound.y = py - getRadius();
        aabb.upperBound.x = px + getRadius();
        aabb.upperBound.y = py + getRadius();
    }

    @Override
    public void computeMass(final MassData massData, final float density) {
        massData.mass = density * JBoxSettings.PI * getRadius() * getRadius();
        massData.center.x = center.x;
        massData.center.y = center.y;

        // inertia about the local origin
        // massData.I = massData.mass * (0.5f * radius * radius + Vec2.dot(m_p, m_p));
        massData.I = massData.mass * (0.5f * getRadius() * getRadius() + (center.x * center.x + center.y * center.y));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy