Home | History | Annotate | Download | only in dynamics
      1 /*******************************************************************************
      2  * Copyright (c) 2013, Daniel Murphy
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without modification,
      6  * are permitted provided that the following conditions are met:
      7  * 	* Redistributions of source code must retain the above copyright notice,
      8  * 	  this list of conditions and the following disclaimer.
      9  * 	* Redistributions in binary form must reproduce the above copyright notice,
     10  * 	  this list of conditions and the following disclaimer in the documentation
     11  * 	  and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     16  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     17  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     19  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     20  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     21  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     22  * POSSIBILITY OF SUCH DAMAGE.
     23  ******************************************************************************/
     24 package org.jbox2d.dynamics;
     25 
     26 import org.jbox2d.collision.AABB;
     27 import org.jbox2d.collision.RayCastInput;
     28 import org.jbox2d.collision.RayCastOutput;
     29 import org.jbox2d.collision.broadphase.BroadPhase;
     30 import org.jbox2d.collision.shapes.MassData;
     31 import org.jbox2d.collision.shapes.Shape;
     32 import org.jbox2d.collision.shapes.ShapeType;
     33 import org.jbox2d.common.MathUtils;
     34 import org.jbox2d.common.Transform;
     35 import org.jbox2d.common.Vec2;
     36 import org.jbox2d.dynamics.contacts.Contact;
     37 import org.jbox2d.dynamics.contacts.ContactEdge;
     38 
     39 /**
     40  * A fixture is used to attach a shape to a body for collision detection. A fixture inherits its
     41  * transform from its parent. Fixtures hold additional non-geometric data such as friction,
     42  * collision filters, etc. Fixtures are created via Body::CreateFixture.
     43  *
     44  * @warning you cannot reuse fixtures.
     45  *
     46  * @author daniel
     47  */
     48 public class Fixture {
     49 
     50   public float m_density;
     51 
     52   public Fixture m_next;
     53   public Body m_body;
     54 
     55   public Shape m_shape;
     56 
     57   public float m_friction;
     58   public float m_restitution;
     59 
     60   public FixtureProxy[] m_proxies;
     61   public int m_proxyCount;
     62 
     63   public final Filter m_filter;
     64 
     65   public boolean m_isSensor;
     66 
     67   public Object m_userData;
     68 
     69   public Fixture() {
     70     m_userData = null;
     71     m_body = null;
     72     m_next = null;
     73     m_proxies = null;
     74     m_proxyCount = 0;
     75     m_shape = null;
     76     m_filter = new Filter();
     77   }
     78 
     79   /**
     80    * Get the type of the child shape. You can use this to down cast to the concrete shape.
     81    *
     82    * @return the shape type.
     83    */
     84   public ShapeType getType() {
     85     return m_shape.getType();
     86   }
     87 
     88   /**
     89    * Get the child shape. You can modify the child shape, however you should not change the number
     90    * of vertices because this will crash some collision caching mechanisms.
     91    *
     92    * @return
     93    */
     94   public Shape getShape() {
     95     return m_shape;
     96   }
     97 
     98   /**
     99    * Is this fixture a sensor (non-solid)?
    100    *
    101    * @return the true if the shape is a sensor.
    102    * @return
    103    */
    104   public boolean isSensor() {
    105     return m_isSensor;
    106   }
    107 
    108   /**
    109    * Set if this fixture is a sensor.
    110    *
    111    * @param sensor
    112    */
    113   public void setSensor(boolean sensor) {
    114     if (sensor != m_isSensor) {
    115       m_body.setAwake(true);
    116       m_isSensor = sensor;
    117     }
    118   }
    119 
    120   /**
    121    * Set the contact filtering data. This is an expensive operation and should not be called
    122    * frequently. This will not update contacts until the next time step when either parent body is
    123    * awake. This automatically calls refilter.
    124    *
    125    * @param filter
    126    */
    127   public void setFilterData(final Filter filter) {
    128     m_filter.set(filter);
    129 
    130     refilter();
    131   }
    132 
    133   /**
    134    * Get the contact filtering data.
    135    *
    136    * @return
    137    */
    138   public Filter getFilterData() {
    139     return m_filter;
    140   }
    141 
    142   /**
    143    * Call this if you want to establish collision that was previously disabled by
    144    * ContactFilter::ShouldCollide.
    145    */
    146   public void refilter() {
    147     if (m_body == null) {
    148       return;
    149     }
    150 
    151     // Flag associated contacts for filtering.
    152     ContactEdge edge = m_body.getContactList();
    153     while (edge != null) {
    154       Contact contact = edge.contact;
    155       Fixture fixtureA = contact.getFixtureA();
    156       Fixture fixtureB = contact.getFixtureB();
    157       if (fixtureA == this || fixtureB == this) {
    158         contact.flagForFiltering();
    159       }
    160       edge = edge.next;
    161     }
    162 
    163     World world = m_body.getWorld();
    164 
    165     if (world == null) {
    166       return;
    167     }
    168 
    169     // Touch each proxy so that new pairs may be created
    170     BroadPhase broadPhase = world.m_contactManager.m_broadPhase;
    171     for (int i = 0; i < m_proxyCount; ++i) {
    172       broadPhase.touchProxy(m_proxies[i].proxyId);
    173     }
    174   }
    175 
    176   /**
    177    * Get the parent body of this fixture. This is NULL if the fixture is not attached.
    178    *
    179    * @return the parent body.
    180    * @return
    181    */
    182   public Body getBody() {
    183     return m_body;
    184   }
    185 
    186   /**
    187    * Get the next fixture in the parent body's fixture list.
    188    *
    189    * @return the next shape.
    190    * @return
    191    */
    192   public Fixture getNext() {
    193     return m_next;
    194   }
    195 
    196   public void setDensity(float density) {
    197     assert (density >= 0f);
    198     m_density = density;
    199   }
    200 
    201   public float getDensity() {
    202     return m_density;
    203   }
    204 
    205   /**
    206    * Get the user data that was assigned in the fixture definition. Use this to store your
    207    * application specific data.
    208    *
    209    * @return
    210    */
    211   public Object getUserData() {
    212     return m_userData;
    213   }
    214 
    215   /**
    216    * Set the user data. Use this to store your application specific data.
    217    *
    218    * @param data
    219    */
    220   public void setUserData(Object data) {
    221     m_userData = data;
    222   }
    223 
    224   /**
    225    * Test a point for containment in this fixture. This only works for convex shapes.
    226    *
    227    * @param p a point in world coordinates.
    228    * @return
    229    */
    230   public boolean testPoint(final Vec2 p) {
    231     return m_shape.testPoint(m_body.m_xf, p);
    232   }
    233 
    234   /**
    235    * Cast a ray against this shape.
    236    *
    237    * @param output the ray-cast results.
    238    * @param input the ray-cast input parameters.
    239    * @param output
    240    * @param input
    241    */
    242   public boolean raycast(RayCastOutput output, RayCastInput input, int childIndex) {
    243     return m_shape.raycast(output, input, m_body.m_xf, childIndex);
    244   }
    245 
    246   /**
    247    * Get the mass data for this fixture. The mass data is based on the density and the shape. The
    248    * rotational inertia is about the shape's origin.
    249    *
    250    * @return
    251    */
    252   public void getMassData(MassData massData) {
    253     m_shape.computeMass(massData, m_density);
    254   }
    255 
    256   /**
    257    * Get the coefficient of friction.
    258    *
    259    * @return
    260    */
    261   public float getFriction() {
    262     return m_friction;
    263   }
    264 
    265   /**
    266    * Set the coefficient of friction. This will _not_ change the friction of existing contacts.
    267    *
    268    * @param friction
    269    */
    270   public void setFriction(float friction) {
    271     m_friction = friction;
    272   }
    273 
    274   /**
    275    * Get the coefficient of restitution.
    276    *
    277    * @return
    278    */
    279   public float getRestitution() {
    280     return m_restitution;
    281   }
    282 
    283   /**
    284    * Set the coefficient of restitution. This will _not_ change the restitution of existing
    285    * contacts.
    286    *
    287    * @param restitution
    288    */
    289   public void setRestitution(float restitution) {
    290     m_restitution = restitution;
    291   }
    292 
    293   /**
    294    * Get the fixture's AABB. This AABB may be enlarge and/or stale. If you need a more accurate
    295    * AABB, compute it using the shape and the body transform.
    296    *
    297    * @return
    298    */
    299   public AABB getAABB(int childIndex) {
    300     assert (childIndex >= 0 && childIndex < m_proxyCount);
    301     return m_proxies[childIndex].aabb;
    302   }
    303 
    304   /**
    305    * Compute the distance from this fixture.
    306    *
    307    * @param p a point in world coordinates.
    308    * @return distance
    309    */
    310   public float computeDistance(Vec2 p, int childIndex, Vec2 normalOut) {
    311     return m_shape.computeDistanceToOut(m_body.getTransform(), p, childIndex, normalOut);
    312   }
    313 
    314   // We need separation create/destroy functions from the constructor/destructor because
    315   // the destructor cannot access the allocator (no destructor arguments allowed by C++).
    316 
    317   public void create(Body body, FixtureDef def) {
    318     m_userData = def.userData;
    319     m_friction = def.friction;
    320     m_restitution = def.restitution;
    321 
    322     m_body = body;
    323     m_next = null;
    324 
    325 
    326     m_filter.set(def.filter);
    327 
    328     m_isSensor = def.isSensor;
    329 
    330     m_shape = def.shape.clone();
    331 
    332     // Reserve proxy space
    333     int childCount = m_shape.getChildCount();
    334     if (m_proxies == null) {
    335       m_proxies = new FixtureProxy[childCount];
    336       for (int i = 0; i < childCount; i++) {
    337         m_proxies[i] = new FixtureProxy();
    338         m_proxies[i].fixture = null;
    339         m_proxies[i].proxyId = BroadPhase.NULL_PROXY;
    340       }
    341     }
    342 
    343     if (m_proxies.length < childCount) {
    344       FixtureProxy[] old = m_proxies;
    345       int newLen = MathUtils.max(old.length * 2, childCount);
    346       m_proxies = new FixtureProxy[newLen];
    347       System.arraycopy(old, 0, m_proxies, 0, old.length);
    348       for (int i = 0; i < newLen; i++) {
    349         if (i >= old.length) {
    350           m_proxies[i] = new FixtureProxy();
    351         }
    352         m_proxies[i].fixture = null;
    353         m_proxies[i].proxyId = BroadPhase.NULL_PROXY;
    354       }
    355     }
    356     m_proxyCount = 0;
    357 
    358     m_density = def.density;
    359   }
    360 
    361   public void destroy() {
    362     // The proxies must be destroyed before calling this.
    363     assert (m_proxyCount == 0);
    364 
    365     // Free the child shape.
    366     m_shape = null;
    367     m_proxies = null;
    368     m_next = null;
    369 
    370     // TODO pool shapes
    371     // TODO pool fixtures
    372   }
    373 
    374   // These support body activation/deactivation.
    375   public void createProxies(BroadPhase broadPhase, final Transform xf) {
    376     assert (m_proxyCount == 0);
    377 
    378     // Create proxies in the broad-phase.
    379     m_proxyCount = m_shape.getChildCount();
    380 
    381     for (int i = 0; i < m_proxyCount; ++i) {
    382       FixtureProxy proxy = m_proxies[i];
    383       m_shape.computeAABB(proxy.aabb, xf, i);
    384       proxy.proxyId = broadPhase.createProxy(proxy.aabb, proxy);
    385       proxy.fixture = this;
    386       proxy.childIndex = i;
    387     }
    388   }
    389 
    390   /**
    391    * Internal method
    392    *
    393    * @param broadPhase
    394    */
    395   public void destroyProxies(BroadPhase broadPhase) {
    396     // Destroy proxies in the broad-phase.
    397     for (int i = 0; i < m_proxyCount; ++i) {
    398       FixtureProxy proxy = m_proxies[i];
    399       broadPhase.destroyProxy(proxy.proxyId);
    400       proxy.proxyId = BroadPhase.NULL_PROXY;
    401     }
    402 
    403     m_proxyCount = 0;
    404   }
    405 
    406   private final AABB pool1 = new AABB();
    407   private final AABB pool2 = new AABB();
    408   private final Vec2 displacement = new Vec2();
    409 
    410   /**
    411    * Internal method
    412    *
    413    * @param broadPhase
    414    * @param xf1
    415    * @param xf2
    416    */
    417   protected void synchronize(BroadPhase broadPhase, final Transform transform1,
    418       final Transform transform2) {
    419     if (m_proxyCount == 0) {
    420       return;
    421     }
    422 
    423     for (int i = 0; i < m_proxyCount; ++i) {
    424       FixtureProxy proxy = m_proxies[i];
    425 
    426       // Compute an AABB that covers the swept shape (may miss some rotation effect).
    427       final AABB aabb1 = pool1;
    428       final AABB aab = pool2;
    429       m_shape.computeAABB(aabb1, transform1, proxy.childIndex);
    430       m_shape.computeAABB(aab, transform2, proxy.childIndex);
    431 
    432       proxy.aabb.lowerBound.x =
    433           aabb1.lowerBound.x < aab.lowerBound.x ? aabb1.lowerBound.x : aab.lowerBound.x;
    434       proxy.aabb.lowerBound.y =
    435           aabb1.lowerBound.y < aab.lowerBound.y ? aabb1.lowerBound.y : aab.lowerBound.y;
    436       proxy.aabb.upperBound.x =
    437           aabb1.upperBound.x > aab.upperBound.x ? aabb1.upperBound.x : aab.upperBound.x;
    438       proxy.aabb.upperBound.y =
    439           aabb1.upperBound.y > aab.upperBound.y ? aabb1.upperBound.y : aab.upperBound.y;
    440       displacement.x = transform2.p.x - transform1.p.x;
    441       displacement.y = transform2.p.y - transform1.p.y;
    442 
    443       broadPhase.moveProxy(proxy.proxyId, proxy.aabb, displacement);
    444     }
    445   }
    446 }
    447