Среда программирования:
CodeBlocks 13.12
Статья по теме:
Вход : множество точек, представляющих полигон в порядке обхода вершин в любом направлении.
Результат : определение типа полигона (выпуклый; не выпуклый).
Как использовать.
Набросать левой клавишей мыши (ЛКМ) вершины:
Нажать правую клавишу мыши(ПКМ), произойдет проверка.
Результат может быть таким:
или таким:
Проверка основывается на том факте, что у выпуклого полигона все повороты смежных ребер одного знака.
Код программы:
// пример работы с векторным произведением #include <SFML/Graphics.hpp> #include <SFML/Window.hpp> #include <iostream> // удобно для отладки void handleMouseLeft(sf::VertexArray& pVertex, sf::Vector2i iCurrPos, sf::Text& pText, sf::ConvexShape& polygon); void handleMouseRight(sf::VertexArray& pVertex, sf::Text& pText, sf::ConvexShape& polygon); bool isConvexPolygon(const sf::VertexArray& mVertex); int getSignVertex(sf::Vertex fVertex1, sf::Vertex fVertex2, sf::Vertex fVertex); bool polygonCheked = false; int main() { // без кнопки максимизации sf::RenderWindow window(sf::VideoMode(640, 480), "is convex polygon", sf::Style::Close|sf::Style::Titlebar); // LinesStrip - связывать 2 рядом идущие точки линией sf::VertexArray lines(sf::LinesStrip, 0); sf::ConvexShape polygon; polygon.setFillColor(sf::Color::Cyan); polygon.setOutlineThickness(2); polygon.setOutlineColor(sf::Color::Green); sf::Font font; font.loadFromFile("Sansation.ttf"); // ЛКМ - набрасывание точек; ПКМ - построение sf::Text mText("LKM - nabrasyvaniye tochek; PKM - postroeniye", font, 20); mText.setPosition(5.f, 425.f); mText.setColor(sf::Color::Cyan); // полигон не определен sf::Text mTextIs("polygon not defined", font, 20); mTextIs.setPosition(5.f, 450.f); mTextIs.setColor(sf::Color::Cyan); while (window.isOpen()) // цикл опроса событий { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) window.close(); // ЛКМ if ((event.type == sf::Event::MouseButtonPressed) & (sf::Mouse::isButtonPressed(sf::Mouse::Left)) ) { sf::Vector2i iCurrPos = sf::Mouse::getPosition(window) ; handleMouseLeft(lines, iCurrPos, mTextIs, polygon); } // ПКМ if ((event.type == sf::Event::MouseButtonPressed) & (sf::Mouse::isButtonPressed(sf::Mouse::Right)) ) handleMouseRight(lines, mTextIs, polygon); } window.clear(); window.draw(lines); window.draw(polygon); window.draw(mText); window.draw(mTextIs); window.display(); } } void handleMouseLeft(sf::VertexArray& pVertex, sf::Vector2i iCurrPos, sf::Text& pText, sf::ConvexShape& polygon) { // если новое ипользование if (polygonCheked) { pVertex.clear(); pText.setColor(sf::Color::Cyan); pText.setString("polygon not defined"); polygon.setPointCount(0); polygonCheked = false; } // VertexArray - только float (кроссплатформенность), // sf::Mouse::getPosition(window) - pair<int> sf::Vector2f fCurrPos(0.0 + iCurrPos.x, 0.0 + iCurrPos.y); // sf::VertexArray.append принимает вектор с float значениями; кроссплатформенность pVertex.append(fCurrPos); }; void handleMouseRight(sf::VertexArray& lines, sf::Text& pText, sf::ConvexShape& polygon) { polygonCheked = true; if (isConvexPolygon(lines) ) { pText.setString("convex polygon"); pText.setColor(sf::Color::Green); polygon.setPointCount(lines.getVertexCount()); sf::Vector2f fVector; for (unsigned int i = 0; i < lines.getVertexCount(); i++){ fVector.x = lines[i].position.x; fVector.y = lines[i].position.y; polygon.setPoint(i, fVector); } lines.clear(); } else { pText.setColor(sf::Color::Red); pText.setString("not convex polygon"); } // добавляем ребро к начальной точке lines.append(lines[0]); }; // Вход : множество вершин в порядке обхода в любом направлении // Выход : булево-значение [выпуклый <--> не выпуклый] bool isConvexPolygon(const sf::VertexArray& pVertex) { bool bRetVal = false; int signPrime = 0; int iVertexCount = pVertex.getVertexCount(); // взять первый ненулевой знак, если 0 - вернуть false int i = 0; // vertex 'iterator' for ( ; i < iVertexCount; ++i) { // getSignVertex(vertex[i], vertex[i+1], vertex[i+2]) ; n+2=2 // нет оператора присваивания: xxx = pVertex[i] , // выдержка: Vertex & operator[] (unsigned int index) // sf::Vertex::Vertex ( const Vector2f & thePosition ) signPrime = getSignVertex( pVertex[i], pVertex[(i+1)%iVertexCount], pVertex[(i+2)%iVertexCount]); if (signPrime != 0) break; } // for if (signPrime == 0) return bRetVal; // линия // сравниваем остальные знаки с образцом for ( ; i < iVertexCount; ++i) { int signNext = getSignVertex(pVertex[i], pVertex[(i+1)%iVertexCount], pVertex[(i+2)%iVertexCount]); // если знаки разные if ( (signNext != signPrime) & (signNext != 0) ) { return bRetVal; } // if } bRetVal = true; return bRetVal; }; // вычисление знака угла поворота // возврат -1, 0, 1 int getSignVertex(sf::Vertex fVertex1, sf::Vertex fVertex2, sf::Vertex fVertex3) { // уравнение прямой ab: Ax + By + C = 0; // A = a.y-b.y, B = b.x-a.x, C = -(a.x*A + a.y*B) // площадь на основе векторов ab и ac float fArea = ( (fVertex2.position.x - fVertex1.position.x)* (fVertex3.position.y - fVertex1.position.y) - (fVertex3.position.x - fVertex1.position.x)* (fVertex2.position.y - fVertex1.position.y) ); int iRetVal = 0; if (fArea == 0) return iRetVal; iRetVal = (fArea > 0) ? 1 : -1; return iRetVal; };
Прикрепленный файл | Размер |
---|---|
isConvex.rar | 477.16 кб |
source_is_convex.rar | 13.91 кб |