Esempio n. 1
0
        // http://astronomy.swin.edu.au/~pbourke/geometry/polyarea/
        vec2 barycenter(const Polygon2d& P) {
            gx_assert(P.size() > 0) ;

            double A = signed_area(P) ;

            if(::fabs(A) < 1e-30) {
                return P[0] ;
            }

            double x = 0.0 ;
            double y = 0.0 ;
            for(unsigned int i=0; i<P.size(); i++) {
                unsigned int j = (i+1) % P.size() ;
                const vec2& t1 = P[i] ;
                const vec2& t2 = P[j] ;
                double d = (t1.x * t2.y - t2.x * t1.y) ;
                x += (t1.x + t2.x) * d ;
                y += (t1.y + t2.y) * d ;
            }
        
            return vec2(
                x / (6.0 * A),
                y / (6.0 * A)
            ) ;
        }
Esempio n. 2
0
bool GD_EXTENSION_API SingleTileCollision(std::map<gd::String, std::vector<RuntimeObject*>*> tileMapList,
                         int layer,
                         int column,
                         int row,
                         std::map<gd::String, std::vector<RuntimeObject*>*> objectLists,
                         bool conditionInverted)
{
    return TwoObjectListsTest(tileMapList, objectLists, conditionInverted, [layer, column, row](RuntimeObject* tileMapObject_, RuntimeObject * object) {
        RuntimeTileMapObject *tileMapObject = dynamic_cast<RuntimeTileMapObject*>(tileMapObject_);
        if(!tileMapObject || tileMapObject->tileSet.Get().IsDirty())
            return false;

        //Get the tile hitbox
        int tileId = tileMapObject->tileMap.Get().GetTile(layer, column, row);
        if(tileId < 0 || tileId >= tileMapObject->tileSet.Get().GetTilesCount())
            return false;

        Polygon2d tileHitbox = tileMapObject->tileSet.Get().GetTileHitbox(tileId).hitbox;
        tileHitbox.Move(tileMapObject->GetX() + column * tileMapObject->tileSet.Get().tileSize.x,
                        tileMapObject->GetY() + row * tileMapObject->tileSet.Get().tileSize.y);

        //Get the object hitbox
        std::vector<Polygon2d> objectHitboxes = object->GetHitBoxes();

        for(std::vector<Polygon2d>::iterator hitboxIt = objectHitboxes.begin(); hitboxIt != objectHitboxes.end(); ++hitboxIt)
        {
            if(PolygonCollisionTest(tileHitbox, *hitboxIt).collision)
            {
                return true;
            }
        }

        return false;
    });
}
Esempio n. 3
0
std::vector<Polygon2d> GenerateHitboxes(TileSet &tileSet, TileMap &tileMap)
{
    std::vector<Polygon2d> hitboxes;
    const int tileWidth = tileSet.tileSize.x;
    const int tileHeight = tileSet.tileSize.y;

    if(tileSet.IsDirty())
        return hitboxes;

    for(int layer = 0; layer < 3; layer++)
    {
        for(int col = 0; col < tileMap.GetColumnsCount(); col++)
        {
            for(int row = 0; row < tileMap.GetRowsCount(); row++)
            {
                //Note : a hitbox is also added for empty/non-collidable tiles to ease the hitbox update when changing a tile
                Polygon2d newPolygon;

                if(tileMap.GetTile(layer, col, row) != -1 && tileSet.GetTileHitbox(tileMap.GetTile(layer, col, row)).collidable)
                {
                    newPolygon = tileSet.GetTileHitbox(tileMap.GetTile(layer, col, row)).hitbox;
                }

                newPolygon.Move(col * tileWidth, row * tileHeight);
                hitboxes.push_back(newPolygon);
            }
        }
    }

    return hitboxes;
}
Esempio n. 4
0
std::vector<Polygon2d> RuntimeObject::GetHitBoxes() const {
  std::vector<Polygon2d> mask;
  Polygon2d rectangle = Polygon2d::CreateRectangle(GetWidth(), GetHeight());
  rectangle.Rotate(GetAngle() / 180 * 3.14159);
  rectangle.Move(GetX() + GetCenterX(), GetY() + GetCenterY());

  mask.push_back(rectangle);
  return mask;
}
Esempio n. 5
0
        void minimum_area_enclosing_rectangle(
            const Polygon2d& PP, 
            vec2& S, vec2& T
        ) {

            // Note: this implementation has O(n2) complexity :-(
            // (where n is the number of vertices in the convex hull)
            // If this appears to be a bottleneck, use a smarter
            // implementation with better complexity.

            Polygon2d P ;
            convex_hull(PP, P) ;

            int N = P.size() ;
            
            // Add the first vertex at the end of P
            P.push_back(P[0]) ;

            double min_area = Numeric::big_double ;

            for(int i=1; i<=N; i++) {
                vec2 Si = P[i] - P[i-1] ;

                if( ( Si.length2() ) < 1e-20) {
                    continue ;
                }

                vec2 Ti(-Si.y, Si.x) ;
                normalize(Si) ;
                normalize(Ti) ;
                double s0 =  Numeric::big_double ;
                double s1 = -Numeric::big_double ;
                double t0 =  Numeric::big_double ;
                double t1 = -Numeric::big_double ; 
                for(int j=1; j<N; j++) {
                    vec2 D = P[j] - P[0] ;
                    double s = dot(Si, D) ;
                    s0 = gx_min(s0, s) ;
                    s1 = gx_max(s1, s) ;
                    double t = dot(Ti, D) ;
                    t0 = gx_min(t0, t) ;
                    t1 = gx_max(t1, t) ;
                }
                double area = (s1 - s0) * (t1 - t0) ;
                if(area < min_area) {
                    min_area = area ;
                    if((s1 - s0) < (t1 - t0)) {
                        S = Si ;
                        T = Ti ;
                    } else {
                        S = Ti ;
                        T = Si ;
                    }
                }
            }
        }
Esempio n. 6
0
        void convex_clip_segment(
            Segment2d& S, const Polygon2d& window
        ) {
	    gx_parano_assert(polygon_is_convex(window)) ;
            bool invert = (signed_area(window) < 0) ;
            for(unsigned int i=0; i<window.size(); i++) {
                unsigned int j = ((i+1) % window.size()) ;
                clip_segment_by_half_plane(S, window[i], window[j], invert) ;
            }
        }
Esempio n. 7
0
 // http://astronomy.swin.edu.au/~pbourke/geometry/polyarea/
 double signed_area(const Polygon2d& P) {
     double result = 0 ;
     for(unsigned int i=0; i<P.size(); i++) {
         unsigned int j = (i+1) % P.size() ;
         const vec2& t1 = P[i] ;
         const vec2& t2 = P[j] ;
         result += t1.x * t2.y - t2.x * t1.y ;
     }
     result /= 2.0 ;
     return result ;
 }
Esempio n. 8
0
 Polygon2d Polygon2d::scaleaboutcentroid(float scale) {
   Polygon2d n;
   V2d cen=centroid();
   for (int i=1;i<=vs.len;i++) {
     V2d x=vs.num(i);
     x=x-cen;
     x=x*scale;
     x=x+cen;
     n.add(x);
   }
   return n;
 }
Esempio n. 9
0
 void save_polygon(const Polygon2d& P, const std::string& file_name) {
     std::ofstream out(file_name.c_str()) ;
     {for(unsigned int i=0; i<P.size(); i++) {
         out << "v " << P[i].x << " " << P[i].y << std::endl ;
         out << "vt " << P[i].x << " " << P[i].y << std::endl ;
     }}
     out << "f " ;
     {for(unsigned int i=0; i<P.size(); i++) {
         out << i+1 << "/" << i+1 << " " ;
     }}
     out << std::endl ;
 }
Esempio n. 10
0
 vec2 vertices_barycenter(const Polygon2d& P) {
     gx_assert(P.size() != 0) ;
     double x = 0 ;
     double y = 0 ;
     for(unsigned int i=0; i<P.size(); i++) {
         x += P[i].x ;
         y += P[i].y ;
     }
     x /= double(P.size()) ;
     y /= double(P.size()) ;
     return vec2(x,y) ;
 }
Esempio n. 11
0
        void clip_polygon_by_half_plane(
            const Polygon2d& P, 
            const vec2& q1,
            const vec2& q2,
            Polygon2d& result,
            bool invert
        ) {
            result.clear() ;

            if(P.size() == 0) {
                return ;
            }

            if(P.size() == 1) {
                if(point_is_in_half_plane(P[0], q1, q2, invert)) {
                    result.push_back(P[0]) ;
                }
                return ;
            }

            vec2 prev_p = P[P.size() - 1] ;
            Sign prev_status = point_is_in_half_plane(
                prev_p, q1, q2, invert
            ) ;

            for(unsigned int i=0; i<P.size(); i++) {
                vec2 p = P[i] ;
                Sign status = point_is_in_half_plane(
                    p, q1, q2, invert
                ) ;
                if(
                    status != prev_status &&
                    status != ZERO &&
                    prev_status != ZERO
                ) {
                    vec2 intersect ;
                    if(intersect_segments(prev_p, p, q1, q2, intersect)) {
                        result.push_back(intersect) ;
                    } else {
                    }
                }

                switch(status) {
                case NEGATIVE:
                    break ;
                case ZERO:
                    result.push_back(p) ;
                    break ;
                case POSITIVE:
                    result.push_back(p) ;
                    break ;
                }

                prev_p = p ;
                prev_status = status ;
            }
        }
Esempio n. 12
0
 void convex_hull(const Polygon2d& PP, Polygon2d& result) {
     result.clear() ;
     int n = PP.size() ;
     vec2* P = new vec2[n+1] ;
     { for(int i=0; i<n; i++) {
         P[i] = PP[i] ;
     }}
     int u = make_chain(P, n, cmpl);  
     P[n] = P[0];
     int ch = u+make_chain(P+u, n-u+1, cmph);  
     {for(int i=0; i<ch; i++) {
         result.push_back(P[i]) ;
     }}
     delete[] P ;
 }
Esempio n. 13
0
 bool polygon_is_convex(const Polygon2d& P) {
     Sign s = ZERO ;
     for(unsigned int i=0; i<P.size(); i++) {
         unsigned int j = ((i+1) % P.size()) ;
         unsigned int k = ((j+1) % P.size()) ;
         Sign cur_s = orient(P[i],P[j],P[k]) ;
         if(s != ZERO && cur_s != ZERO && cur_s != s) {
             return false ;
         }
         if(cur_s != ZERO) {
             s = cur_s ;
         }
     }
     return true ;
 }
Esempio n. 14
0
	PolygonShape::PolygonShape(const Polygon2d& polygon, Material& attrs):
		m_polygon(polygon) {
		
		b2Vec2* vertecies = new b2Vec2[polygon.VerteciesCount()];
		const Vertecies& polygonVertecies = polygon.GetVertecies();
		for (size_t vertexNo = 0; vertexNo < polygonVertecies.size(); ++vertexNo) {
			vertecies[vertexNo] = ToBox2dVec(polygonVertecies[vertexNo]);
		}
		
		m_polygonShapePtr = new b2PolygonShape();
		m_polygonShapePtr->Set(vertecies, polygon.VerteciesCount());
		delete[] vertecies;
		
		Construct(m_polygonShapePtr, attrs);
	}
Esempio n. 15
0
        bool point_is_in_kernel(const Polygon2d& P, const vec2& p) {
            Sign sign = ZERO ;
            for(unsigned int i=0 ; i<P.size() ; i++) {
                unsigned int j = (i+1) % P.size() ;
                const vec2& p1 = P[i] ;
                const vec2& p2 = P[j] ;

                Sign cur_sign = orient(p, p1, p2) ;
                if(sign == ZERO) {
                    sign = cur_sign ;
                } else {
                    if(cur_sign != ZERO && cur_sign != sign) {
                        return false ;
                    }
                }
            }
            return true ;
        }
Esempio n. 16
0
 // Clipping with convex window using Sutherland-Hogdman reentrant clipping
 void convex_clip_polygon(
     const Polygon2d& P, const Polygon2d& clip, Polygon2d& result
 ) {
     gx_parano_assert(polygon_is_convex(clip)) ;
     Polygon2d tmp1 = P ;
     bool invert = (signed_area(tmp1) != signed_area(clip)) ;
     Polygon2d tmp2 ;
     Polygon2d* src = &tmp1 ;
     Polygon2d* dst = &tmp2 ;
     for(unsigned int i=0; i<clip.size(); i++) {
         unsigned int j = ((i+1) % clip.size()) ;
         const vec2& p1 = clip[i] ;
         const vec2& p2 = clip[j] ;
         clip_polygon_by_half_plane(*src, p1, p2, *dst, invert) ;
         gx_swap(src, dst) ;
     }
     result = *src ;
 }
Esempio n. 17
0
        // Compute the kernel using Sutherland-Hogdman reentrant clipping
        // The kernel is obtained by clipping the polygon with each 
        // half-plane yielded by its sides.
        void kernel(const Polygon2d& P, Polygon2d& result) {

            Array1d<Sign> sign(P.size()) ;
            for(unsigned int i=0; i<P.size(); i++) {
                unsigned int j = ((i+1) % P.size()) ;
                unsigned int k = ((j+1) % P.size()) ;
                sign(j) = orient(P[i],P[j],P[k]) ;
            }

            bool invert = (signed_area(P) < 0) ;

            Polygon2d tmp1 = P ;
            Polygon2d tmp2 ;
            Polygon2d* src = &tmp1 ;
            Polygon2d* dst = &tmp2 ;
            for(unsigned int i=0; i<P.size(); i++) {
                unsigned int j = ((i+1) % P.size()) ;
                const vec2& p1 = P[i] ;
                const vec2& p2 = P[j] ;

                if((p2-p1).length() == 0) {
                    std::cerr << "null edge in poly" << std::endl ;
                    continue ;
                }

                // Optimization: do not clip by convex-convex edges
                // (Thanks to Rodrigo Toledo for the tip !)

                if(!invert && sign(i) != NEGATIVE && sign(j) != NEGATIVE) {
                    continue ;
                }

                if(invert && sign(i) != POSITIVE && sign(j) != POSITIVE) {
                    continue ;
                }

                clip_polygon_by_half_plane(*src, p1, p2, *dst, invert) ;
                gx_swap(src, dst) ;

            }
            result = *src ;
        }
Esempio n. 18
0
  bool Polygon2d::overlaps(Polygon2d p) { // does not seem to work
//    return overlaps(&p);

    for (int i=1;i<=p.vs.len;i++)
      if (crosses(p.linefrom(i)))
        return true;
    bool pin=true;
    bool thisin=true;
    for (int i=1;i<=p.vs.len && pin;i++)
      if (!contains(p.vs.num(i)))
        pin=false;
    for (int i=1;i<=vs.len && thisin;i++)
      if (!p.contains(vs.num(i)))
        thisin=false;
    if (pin)
      return container; // this polygon completely contains p
    if (thisin)
      return contained;
    return false;
  }
Esempio n. 19
0
	void D3DRenderContext::RenderSolidPolygon(const Polygon2d& p, const ivec3& color) const {
		WireGeometryVertex* points = new WireGeometryVertex[p.VerteciesCount() + 1];
		for (uint i = 0; i <= p.VerteciesCount(); ++i) {
			if (i == p.VerteciesCount()) {
				points[i].x = p[0].x;
				points[i].y = p[0].y;
				points[i].z = MAX_ZCHOOORD;
				points[i].color = D3DCOLOR_XRGB(color.x, color.y, color.z);
			} else {
				points[i].x = p[i].x;
				points[i].y = p[i].y;
				points[i].z = MAX_ZCHOOORD;
				points[i].color = D3DCOLOR_XRGB(color.x, color.y, color.z);
			}
		}

		m_d3dDevice->SetFVF(D3DFVF_WIRE_GEOMETRY_VERTEX);
		m_d3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, p.VerteciesCount(), static_cast<void*>(points), sizeof(WireGeometryVertex));

		delete[] points;
	}
Esempio n. 20
0
float offness(Polygon2d p) {
      Region r=Region(p,oi->width,oi->height);
      r.makelist();
      V2d v=V2d(0,0);
      int cnt=0;
      for (int i=1;i<=r.list->len;i++) {
        int x=r.list->num(i).x;
        int y=r.list->num(i).y;
        if (angs->inmap(x,y)) {
          v=v+mag->pos[x][y]*V2d::rotate(V2d(1,0),angs->pos[x][y]);
          cnt++;
        }
      }
      float offness=v.mod()/(float)cnt;
      printf("Quad has offness %f count %i area %f\n",offness,cnt,p.area());
      return offness;
}
Esempio n. 21
0
float areaofpoly(Polygon2d p) {
  return p.area();
}
Esempio n. 22
0
  float Polygon2d::area(Polygon2d p) {
   return p.area();
 }
Esempio n. 23
0
 Polygon2d Polygon2d::operator*(float f) {
   Polygon2d p;
   for (int i=1;i<=vs.len;i++)
     p.add(vs.num(i)*f);
   return p;
 }
Esempio n. 24
0
bool TileMapImporter::ImportTileMap(TileSet &tileSet, TileMap &tileMap,
                                    bool importTileMap, bool importTileSetConf, bool importTileSetImage,
                                    bool importHitboxes, gd::Project &project)
{
    //Checks the map type
    if(m_map->GetOrientation() != Tmx::TMX_MO_ORTHOGONAL)
    {
        gd::LogError(_("Only orthogonal maps are supported !"));
        return false;
    }

    //Get the tileset list
    if(m_map->GetNumTilesets() < 1)
    {
        gd::LogError(_("There are no tilesets in this file !"));
        return false;
    }
    else if(m_map->GetNumTilesets() > 1)
    {
        gd::LogWarning(_("Only the first tileset will be taken into account. Tiles from supplementary tilesets may be lost."));
    }

    //Import the tileset image if needed
    if(importTileSetImage)
    {
        const Tmx::Image *importedImage = m_map->GetTileset(0)->GetImage();
        wxFileName imageFileName(importedImage->GetSource());
        imageFileName.MakeAbsolute(wxFileName(m_filePath).GetPath());

        if(!imageFileName.FileExists())
        {
            gd::LogError(_("The image can't be found !"));
            return false;
        }

        gd::String newResourceName = gd::NewNameGenerator::Generate(
                                         u8"imported_" + imageFileName.GetFullName(),
                                         [&project](const gd::String &name) -> bool { return project.GetResourcesManager().HasResource(name); }
                                     );

        gd::LogMessage(_("The image is imported as ") + "\"" + newResourceName + "\".");

        imageFileName.MakeRelativeTo(wxFileName(project.GetProjectFile()).GetPath());
        project.GetResourcesManager().AddResource(newResourceName, imageFileName.GetFullPath(), "image");

        tileSet.textureName = newResourceName;

        //Reload the texture
        tileSet.LoadResources(project);

        gd::LogStatus(_("Tileset image importation completed."));
    }

    //Import the tileset configuration if wanted
    if(importTileSetConf)
    {
        const Tmx::Tileset *importedTileset = m_map->GetTileset(0);

        if(importedTileset->GetImage()->GetWidth() != tileSet.GetWxBitmap().GetWidth() ||
                importedTileset->GetImage()->GetHeight() != tileSet.GetWxBitmap().GetHeight())
        {
            gd::LogWarning(_("Tileset image size is not the same. Some tiles may not be rendered correctly."));
        }

        tileSet.tileSize.x = importedTileset->GetTileWidth();
        tileSet.tileSize.y = importedTileset->GetTileHeight();
        tileSet.tileSpacing.x = tileSet.tileSpacing.y = importedTileset->GetSpacing();

        if(importedTileset->GetMargin() > 0)
        {
            gd::LogWarning(_("Tilemap objects don't handle tilesets with margins around the images. Consider cutting the picture."));
        }

        gd::LogStatus(_("Tileset configuration importation completed."));
    }

    //Import the tilemap tiles if wanted
    if(importTileMap)
    {
        //Tilemap size
        if(tileMap.GetColumnsCount() != m_map->GetWidth() || tileMap.GetRowsCount() != m_map->GetHeight())
            gd::LogMessage(_("Tilemap size is different."));
        tileMap.SetSize(0, 0);
        tileMap.SetSize(m_map->GetWidth(), m_map->GetHeight());

        if(!importTileSetConf && !importTileSetImage)
            CheckTilesCount(tileSet);

        //Import layers and tiles
        if(m_map->GetNumTileLayers() > 3)
        {
            gd::LogWarning(_("There are more than 3 tiles layers. Only the 3 firsts will be imported."));
        }
        else if(m_map->GetNumTileLayers() < 3)
        {
            gd::LogMessage(_("There are less than 3 tiles layers. Upper layer(s) will be empty."));
        }

        for(std::size_t i = 0; i < std::min(3, m_map->GetNumTileLayers()); i++)
        {
            const Tmx::TileLayer *layer = m_map->GetTileLayer(i);

            for(std::size_t x = 0; x < tileMap.GetColumnsCount(); x++)
            {
                for(std::size_t y = 0; y < tileMap.GetRowsCount(); y++)
                {
                    //Only tiles provided by the first tileset are imported (and also tests for empty tiles)
                    if(m_map->FindTilesetIndex(layer->GetTileGid(x, y)) == 0)
                    {
                        tileMap.SetTile(i, x, y, layer->GetTileId(x, y));
                    }
                }
            }
        }

        gd::LogStatus(_("Tilemap content importation completed."));
    }

    //Import the hitboxes
    if(importHitboxes)
    {
        const Tmx::Tileset *importedTileset = m_map->GetTileset(0);

        //Set all tiles not collidable in the tileset
        tileSet.ResetHitboxes();
        for(std::size_t i = 0; i < tileSet.GetTilesCount(); i++)
            tileSet.SetTileCollidable(i, false);

        if(!importTileSetConf && !importTileSetImage)
            CheckTilesCount(tileSet);

        bool hasMoreThanOneObjectPerTile = false;
        bool hasNotPolygoneObject = false;
        bool hasNotConvexPolygon = false;
        for(auto it = importedTileset->GetTiles().cbegin();
                it != importedTileset->GetTiles().cend();
                ++it)
        {
            const Tmx::Tile *importedTile = *it;

            if(importedTile->GetId() < tileSet.GetTilesCount()) //Check if the tileset has enough tiles to receive the imported hitboxes
            {
                if(importedTile->HasObjects())
                {
                    //Set the tile collidable and gets its hitbox
                    tileSet.SetTileCollidable(importedTile->GetId(), true);
                    TileHitbox &tileHitbox = tileSet.GetTileHitboxRef(importedTile->GetId());

                    //Warn the user if more than one hitbox per tile is found
                    if(importedTile->GetNumObjects() > 1)
                        hasMoreThanOneObjectPerTile = true;

                    const Tmx::Object *importedObj = importedTile->GetObject(0);
                    if(!importedObj->GetPolyline() && !importedObj->GetEllipse())
                    {
                        Polygon2d polygonHitbox;

                        if(!importedObj->GetPolygon())
                        {
                            //This is a rectangle
                            polygonHitbox = Polygon2d::CreateRectangle(importedObj->GetWidth(), importedObj->GetHeight());
                            polygonHitbox.Move(
                                importedObj->GetWidth() / 2.f,
                                importedObj->GetHeight() / 2.f
                            );
                        }
                        else
                        {
                            //This is a polygon
                            const Tmx::Polygon *importedPolygon = importedObj->GetPolygon();

                            for(int i = 0; i < importedPolygon->GetNumPoints(); i++)
                            {
                                polygonHitbox.vertices.emplace_back(
                                    importedPolygon->GetPoint(i).x,
                                    importedPolygon->GetPoint(i).y
                                );
                            }
                        }

                        polygonHitbox.Move(importedObj->GetX(), importedObj->GetY());
                        polygonHitbox.Rotate(importedObj->GetRot());

                        if(polygonHitbox.IsConvex())
                            tileHitbox.hitbox = polygonHitbox;
                        else
                            hasNotConvexPolygon = true;
                    }
                    else
                    {
                        //This is not a supported shape
                        hasNotPolygoneObject = true;
                    }
                }
            }
        }

        if(hasMoreThanOneObjectPerTile)
            gd::LogWarning(_("Some tiles have more than 1 hitbox. Only the first one is imported."));
        if(hasNotPolygoneObject)
            gd::LogWarning(_("Some tiles have a polyline or a ellipsis hitbox. Only rectangle and polygon hitboxes are supported."));
        if(hasNotConvexPolygon)
            gd::LogWarning(_("Some tiles have a concave polygon. It has been ignored and set to a rectangular hitbox as this object only supports convex hitboxes for tiles."));

        gd::LogStatus(_("Tiles hitboxes importation completed."));
    }

    return true;
}
Esempio n. 25
0
CollisionResult GD_API PolygonCollisionTest(Polygon2d& p1,
                                            Polygon2d& p2,
                                            bool ignoreTouchingEdges) {
  if (p1.vertices.size() < 3 || p2.vertices.size() < 3) {
    CollisionResult result;
    result.collision = false;
    result.move_axis.x = 0.0f;
    result.move_axis.y = 0.0f;
    return result;
  }

  p1.ComputeEdges();
  p2.ComputeEdges();

  sf::Vector2f edge;
  sf::Vector2f move_axis(0, 0);
  sf::Vector2f mtd(0, 0);

  float min_dist = FLT_MAX;

  CollisionResult result;

  // Iterate over all the edges composing the polygons
  for (std::size_t i = 0; i < p1.vertices.size() + p2.vertices.size(); i++) {
    if (i < p1.vertices.size())  // or <=
    {
      edge = p1.edges[i];
    } else {
      edge = p2.edges[i - p1.vertices.size()];
    }

    sf::Vector2f axis(
        -edge.y, edge.x);  // Get the axis to which polygons will be projected
    normalise(axis);

    float minA = 0;
    float minB = 0;
    float maxA = 0;
    float maxB = 0;

    project(axis, p1, minA, maxA);
    project(axis, p2, minB, maxB);

    float dist = distance(minA, maxA, minB, maxB);
    if (dist > 0.0f || (dist == 0.0 && ignoreTouchingEdges)) {
      // If the projections on the axis do not overlap, then
      // there is no collision
      result.collision = false;
      result.move_axis.x = 0.0f;
      result.move_axis.y = 0.0f;

      return result;
    }

    float absDist = std::abs(dist);

    if (absDist < min_dist) {
      min_dist = absDist;
      move_axis = axis;
    }
  }

  result.collision = true;

  sf::Vector2f d = p1.ComputeCenter() - p2.ComputeCenter();
  if (dotProduct(d, move_axis) < 0.0f) move_axis = -move_axis;
  result.move_axis = move_axis * min_dist;

  return result;
}
Esempio n. 26
0
RaycastResult GD_API PolygonRaycastTest(
    Polygon2d& poly, float startX, float startY, float endX, float endY) {
  RaycastResult result;
  result.collision = false;

  if (poly.vertices.size() < 2) {
    return result;
  }

  poly.ComputeEdges();
  sf::Vector2f p, q, r, s;
  float minSqDist = FLT_MAX;

  // Ray segment: p + t*r, with p = start and r = end - start
  p.x = startX;
  p.y = startY;
  r.x = endX - startX;
  r.y = endY - startY;

  for (int i = 0; i < poly.edges.size(); i++) {
    // Edge segment: q + u*s
    q = poly.vertices[i];
    s = poly.edges[i];
    sf::Vector2f deltaQP = q - p;
    float crossRS = crossProduct(r, s);
    float t = crossProduct(deltaQP, s) / crossRS;
    float u = crossProduct(deltaQP, r) / crossRS;

    // Collinear
    if (abs(crossRS) <= 0.0001 && abs(crossProduct(deltaQP, r)) <= 0.0001) {
      // Project the ray and the edge to work on floats, keeping linearity
      // through t
      sf::Vector2f axis(r.x, r.y);
      normalise(axis);
      float rayA = 0.0f;
      float rayB = dotProduct(axis, r);
      float edgeA = dotProduct(axis, deltaQP);
      float edgeB = dotProduct(axis, deltaQP + s);
      // Get overlapping range
      float minOverlap = std::max(std::min(rayA, rayB), std::min(edgeA, edgeB));
      float maxOverlap = std::min(std::max(rayA, rayB), std::max(edgeA, edgeB));
      if (minOverlap > maxOverlap) {
        return result;
      }
      result.collision = true;
      // Zero distance ray
      if (rayB == 0.0f) {
        result.closePoint = p;
        result.closeSqDist = 0.0f;
        result.farPoint = p;
        result.farSqDist = 0.0f;
      }
      float t1 = minOverlap / abs(rayB);
      float t2 = maxOverlap / abs(rayB);
      result.closePoint = p + t1 * r;
      result.closeSqDist = t1 * t1 * (r.x * r.x + r.y * r.y);
      result.farPoint = p + t2 * r;
      result.farSqDist = t2 * t2 * (r.x * r.x + r.y * r.y);

      return result;
    } else if (crossRS != 0 && 0 <= t && t <= 1 && 0 <= u && u <= 1) {
      sf::Vector2f point = p + t * r;

      float sqDist = (point.x - startX) * (point.x - startX) +
                     (point.y - startY) * (point.y - startY);
      if (sqDist < minSqDist) {
        if (!result.collision) {
          result.farPoint = point;
          result.farSqDist = sqDist;
        }
        minSqDist = sqDist;
        result.closePoint = point;
        result.closeSqDist = sqDist;
        result.collision = true;
      } else {
        result.farPoint = point;
        result.farSqDist = sqDist;
      }
    }
  }

  return result;
}