├── ALine.h ├── AVector.h ├── GLContainer.cpp ├── GLContainer.h ├── GLWidget.cpp ├── GLWidget.h ├── IslamicStarPattern.png ├── IslamicStarPatterns.pro ├── IslamicStarPatterns.pro.user ├── PatternGenerator.cpp ├── PatternGenerator.h ├── README.md ├── RibbonSegment.h ├── SystemParams.cpp ├── SystemParams.h ├── TilingData.h ├── Triangulator.cpp ├── Triangulator.h ├── VertexData.h ├── archimedeans.xml ├── hanbury.xml ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── shader.frag ├── shader.vert ├── tinyxml2.cpp └── tinyxml2.h /ALine.h: -------------------------------------------------------------------------------- 1 | #ifndef ALINE_H 2 | #define ALINE_H 3 | 4 | #include "AVector.h" 5 | 6 | #include 7 | #include 8 | 9 | struct ALine 10 | { 11 | public: 12 | float XA; float YA; // start 13 | float XB; float YB; // end 14 | 15 | bool _isRight; 16 | int _side; 17 | 18 | // Constructor #1 19 | ALine() 20 | { 21 | this->XA = -1; this->YA = -1; 22 | this->XB = -1; this->YB = -1; 23 | 24 | this->_isRight = false; 25 | this->_side = -1; 26 | } 27 | 28 | // Constructor #2 29 | ALine(float XA, float YA, float XB, float YB) 30 | { 31 | this->XA = XA; this->YA = YA; 32 | this->XB = XB; this->YB = YB; 33 | 34 | this->_isRight = false; 35 | this->_side = -1; 36 | } 37 | 38 | // Constructor #3 39 | ALine(AVector v1, AVector v2) 40 | { 41 | this->XA = v1.x; this->YA = v1.y; 42 | this->XB = v2.x; this->YB = v2.y; 43 | 44 | this->_isRight = false; 45 | this->_side = -1; 46 | } 47 | 48 | // Constructor #4 49 | ALine(AVector v1, AVector v2, bool isRight, int side) 50 | { 51 | this->XA = v1.x; this->YA = v1.y; 52 | this->XB = v2.x; this->YB = v2.y; 53 | 54 | this->_isRight = isRight; 55 | this->_side = side; 56 | } 57 | 58 | 59 | ALine Resize(float val) 60 | { 61 | ALine newL; 62 | 63 | newL.XA = this->XA * val; 64 | newL.YA = this->YA * val; 65 | 66 | newL.XB = this->XB * val; 67 | newL.YB = this->YB * val; 68 | 69 | return newL; 70 | } 71 | 72 | // Uninitialized ? 73 | bool Invalid() 74 | { 75 | if(((int)XA) == -1 && ((int)YA) == -1 && ((int)XB) == -1 && ((int)YB) == -1) return true; 76 | return false; 77 | } 78 | 79 | // Start point 80 | AVector GetPointA() { return AVector(XA, YA); } 81 | 82 | // End point 83 | AVector GetPointB() { return AVector(XB, YB); } 84 | 85 | // Direction of the vector 86 | AVector Direction() { return AVector(XB - XA, YB - YA);} 87 | 88 | float Magnitude() 89 | { 90 | AVector dir = Direction(); 91 | return sqrt(dir.x * dir.x + dir.y * dir.y); 92 | } 93 | 94 | bool LiesHere(AVector vec) 95 | { 96 | float det = (XB - XA) * (vec.y - YA) - (YB - YA) * (vec.x - XA); 97 | if(det > -1e-8 && det < 1e-8) return true; 98 | return false; 99 | } 100 | 101 | // returns: 102 | // 1 : same direction 103 | // -1 : opposite direction 104 | // 0 : other else 105 | int HasSameDirection(ALine otherLine) 106 | { 107 | float mag1 = Magnitude(); 108 | float mag2 = otherLine.Magnitude(); 109 | 110 | AVector dir1 = Direction(); 111 | AVector dir2 = otherLine.Direction(); 112 | 113 | float a_dot_b = dir1.Dot(dir2); 114 | float a_b_mag = mag1 * mag2; 115 | 116 | float addValue = a_dot_b + a_b_mag; 117 | if(addValue > -std::numeric_limits::epsilon() && addValue < std::numeric_limits::epsilon() ) { return -1; } 118 | 119 | float subsValue = a_dot_b - a_b_mag; 120 | 121 | if(subsValue > -std::numeric_limits::epsilon() && subsValue < std::numeric_limits::epsilon() ) { return 1; } 122 | 123 | return 0; 124 | } 125 | }; 126 | 127 | // for comparison 128 | struct LessThanLineMagnitude 129 | { 130 | bool operator() (ALine i, ALine j) 131 | { return (i.Magnitude() < j.Magnitude()); } 132 | }; 133 | 134 | struct LessThanLineMagnitudePair 135 | { 136 | bool operator() (std::pair i, std::pair j) 137 | { return ( (i.first.Magnitude() + i.second.Magnitude()) < (j.first.Magnitude() + j.second.Magnitude()) ); } 138 | }; 139 | 140 | 141 | #endif // ALINE_H 142 | -------------------------------------------------------------------------------- /AVector.h: -------------------------------------------------------------------------------- 1 | #ifndef AVECTOR_H 2 | #define AVECTOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct AVector 9 | { 10 | public: 11 | // x 12 | float x; 13 | 14 | // y 15 | float y; 16 | 17 | // custom 18 | //int index; 19 | 20 | // Default constructor 21 | AVector() 22 | { 23 | this->x = -1; 24 | this->y = -1; 25 | //this->index = -1; 26 | } 27 | 28 | // Constructor 29 | AVector(float x, float y) 30 | { 31 | this->x = x; 32 | this->y = y; 33 | //this->index = -1; 34 | } 35 | 36 | // Constructor 37 | /*AVector(AVector otherVector) 38 | { 39 | this->x = otherVector.x; 40 | this->y = otherVector.y; 41 | //this->index = -1; 42 | }*/ 43 | 44 | // Scale a point 45 | AVector Resize(float val) 46 | { 47 | AVector newP; 48 | newP.x = this->x * val; 49 | newP.y = this->y * val; 50 | return newP; 51 | } 52 | 53 | // if a point is (-1, -1) 54 | bool Invalid() 55 | { 56 | if(((int)x) == -1 && ((int)y) == -1) 57 | { return true; } 58 | return false; 59 | } 60 | 61 | // Normalize 62 | AVector Norm() 63 | { 64 | float vlength = std::sqrt( x * x + y * y ); 65 | return AVector(this->x / vlength, this->y / vlength); 66 | } 67 | 68 | AVector Inverse() 69 | { 70 | return AVector(-this->x, -this->y); 71 | } 72 | 73 | // Euclidean distance 74 | float Distance(AVector other) 75 | { 76 | float xDist = x - other.x; 77 | float yDist = y - other.y; 78 | return sqrt(xDist * xDist + yDist * yDist); 79 | } 80 | 81 | // Euclidean distance 82 | float Distance(float otherX, float otherY) 83 | { 84 | float xDist = x - otherX; 85 | float yDist = y - otherY; 86 | return sqrt(xDist * xDist + yDist * yDist); 87 | } 88 | 89 | // squared euclidean distance 90 | float DistanceSquared(AVector other) 91 | { 92 | float xDist = x - other.x; 93 | float yDist = y - other.y; 94 | return (xDist * xDist + yDist * yDist); 95 | } 96 | 97 | // squared euclidean distance 98 | float DistanceSquared(float otherX, float otherY) 99 | { 100 | float xDist = x - otherX; 101 | float yDist = y - otherY; 102 | return (xDist * xDist + yDist * yDist); 103 | } 104 | 105 | // operator overloading 106 | AVector operator+ (const AVector& other) { return AVector(x + other.x, y + other.y); } 107 | 108 | // operator overloading 109 | AVector operator- (const AVector& other) { return AVector(x - other.x, y - other.y); } 110 | bool operator== (const AVector& other) 111 | { return (abs(this->x - other.x) < std::numeric_limits::epsilon() && abs(this->y - other.y) < std::numeric_limits::epsilon()); } 112 | 113 | // operator overloading 114 | bool operator!= (const AVector& other) 115 | { return (abs(this->x - other.x) >= std::numeric_limits::epsilon() || abs(this->y - other.y) >= std::numeric_limits::epsilon()); } 116 | 117 | // operator overloading 118 | AVector operator+= (const AVector& other) 119 | { 120 | x += other.x; 121 | y += other.y; 122 | return *this; 123 | } 124 | 125 | // operator overloading 126 | AVector operator-= (const AVector& other) 127 | { 128 | x -= other.x; 129 | y -= other.y; 130 | return *this; 131 | } 132 | 133 | // operator overloading 134 | AVector operator/ (const float& val) { return AVector(x / val, y / val); } 135 | 136 | // operator overloading 137 | AVector operator* (const float& val) { return AVector(x * val, y * val); } 138 | 139 | // operator overloading 140 | AVector operator*= (const float& val) 141 | { 142 | x *= val; 143 | y *= val; 144 | return *this; 145 | } 146 | 147 | // operator overloading 148 | AVector operator/= (const float& val) 149 | { 150 | x /= val; 151 | y /= val; 152 | return *this; 153 | } 154 | 155 | // length of a vector 156 | float Length() { return sqrt(x * x + y * y); } 157 | 158 | // squared length of a vector 159 | float LengthSquared() { return x * x + y * y; } 160 | 161 | // dot product 162 | float Dot(AVector otherVector) { return x * otherVector.x + y * otherVector.y; } 163 | 164 | // cross product 165 | AVector Cross(AVector otherVector) 166 | { 167 | //U x V = Ux*Vy-Uy*Vx 168 | return AVector(x * otherVector.y, y * otherVector.x); 169 | } 170 | 171 | // linear dependency test 172 | bool IsLinearDependent(AVector otherVector) 173 | { 174 | float det = (this->x * otherVector.y) - (this->y * otherVector.x); 175 | if(det > -std::numeric_limits::epsilon() && det < std::numeric_limits::epsilon()) { return true; } 176 | return false; 177 | } 178 | 179 | // angle direction 180 | AVector DirectionTo(AVector otherVector) 181 | { 182 | return AVector(otherVector.x - this->x, otherVector.y - this->y); 183 | } 184 | }; 185 | 186 | #endif // AVECTOR_H 187 | -------------------------------------------------------------------------------- /GLContainer.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | //#include "stdafx.h" 6 | 7 | #include "GLContainer.h" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | GLContainer::GLContainer(QWidget *parent) : 20 | QAbstractScrollArea (parent), 21 | _ctrlPressed(false), 22 | _mousePressed(false), 23 | _sWidth(20), 24 | _sHeight(20), 25 | _prevNum(-1), 26 | _scrollMoved(false) 27 | { 28 | QGLFormat format; 29 | format.setVersion(4, 0); 30 | format.setProfile(QGLFormat::CompatibilityProfile); 31 | format.setSampleBuffers(true); 32 | 33 | _glWidget = new GLWidget(format); 34 | _glWidget->setObjectName(QStringLiteral("myGLImageDisplay")); 35 | 36 | setViewport(_glWidget); 37 | 38 | horizontalScrollBar()->setSingleStep(10); 39 | horizontalScrollBar()->setPageStep(100); 40 | 41 | verticalScrollBar()->setSingleStep(10); 42 | verticalScrollBar()->setPageStep(100); 43 | 44 | connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),this, SLOT(HScrollChanged(int))); 45 | connect(verticalScrollBar(), SIGNAL(valueChanged(int)),this, SLOT(VScrollChanged(int))); 46 | 47 | setMouseTracking(true); 48 | 49 | _doubleClickTimer = new QTimer(this); connect(_doubleClickTimer, SIGNAL(timeout()), this, SLOT(DummyFunction())); 50 | _doubleClickTimeout = 100; 51 | 52 | this->_justInitialized = true; 53 | } 54 | 55 | void GLContainer::UpdateViewport(bool putInMiddle) 56 | { 57 | QSize barSize = QSize(this->width() - _sWidth, this->height() - _sHeight); 58 | 59 | float zoomFactor = _glWidget->GetZoomFactor(); 60 | QSize canvasSize = _glWidget->GetCanvasSize(); 61 | 62 | //QSize borderLimit( 10, 10); 63 | 64 | int img_width = canvasSize.width() * zoomFactor; 65 | int img_height = canvasSize.height() * zoomFactor; 66 | 67 | //std::cout << img_width << " " << img_height << "\n"; 68 | 69 | if(img_width == 0 || img_height == 0) 70 | { 71 | img_width = 100 * zoomFactor; 72 | img_height = 100 * zoomFactor; 73 | } 74 | 75 | float xSPos; 76 | float ySPos; 77 | if(!putInMiddle) 78 | { 79 | float xNormPos = _mousePos.x() + _xPrevF; 80 | float yNormPos = _mousePos.y() + _yPrevF; 81 | xNormPos /= _prevZoomFactor; 82 | yNormPos /= _prevZoomFactor; 83 | 84 | float xRev = xNormPos * zoomFactor; 85 | float yRev = yNormPos * zoomFactor; 86 | xSPos = xRev - _mousePos.x(); 87 | ySPos = yRev - _mousePos.y(); 88 | } 89 | 90 | int leftRange = 0; 91 | int rightRange = 0; 92 | int upRange = 0; 93 | int downRange = 0; 94 | 95 | float hPos = 0; 96 | float vPos = 0; 97 | 98 | int xGap = abs(barSize.width() - img_width); 99 | int yGap = abs(barSize.height() - img_height); 100 | 101 | if(img_width <= barSize.width()) 102 | { 103 | if(putInMiddle)hPos = -xGap * 0.5; // 104 | else hPos = xSPos; 105 | 106 | leftRange = -img_width - xGap; 107 | rightRange = img_width; 108 | 109 | } 110 | else 111 | { 112 | if(putInMiddle) hPos = xGap * 0.5; 113 | else hPos = xSPos; 114 | leftRange = -img_width + xGap; 115 | rightRange = img_width; 116 | } 117 | 118 | if(img_height <= barSize.height()) 119 | { 120 | if(putInMiddle) vPos = -yGap * 0.5; 121 | else vPos = ySPos; 122 | 123 | upRange = -img_height -yGap; 124 | downRange = img_height; 125 | 126 | } 127 | else 128 | { 129 | if(putInMiddle) vPos = yGap * 0.5; 130 | else vPos = ySPos; 131 | upRange = -img_height + yGap; 132 | downRange = img_height; 133 | } 134 | 135 | _xPrevF = hPos; 136 | _yPrevF = vPos; 137 | 138 | horizontalScrollBar()->setRange(leftRange, rightRange); 139 | verticalScrollBar()->setRange(upRange, downRange); 140 | 141 | horizontalScrollBar()->setSliderPosition(hPos); 142 | verticalScrollBar()->setSliderPosition(vPos); 143 | } 144 | 145 | void GLContainer::paintEvent(QPaintEvent *event) 146 | { 147 | if(this->_justInitialized) 148 | { 149 | UpdateViewport(true); 150 | this->_justInitialized = false; 151 | } 152 | 153 | // please fix me 154 | if(this->width() != _glWidget->width() || this->height() != _glWidget->height()) 155 | { 156 | _glWidget->setFixedWidth(this->width()); 157 | _glWidget->setFixedHeight(this->height()); 158 | } 159 | 160 | QAbstractScrollArea::paintEvent(event); 161 | _glWidget->updateGL(); 162 | } 163 | 164 | bool GLContainer::event(QEvent * event) 165 | { 166 | //if(scrollMoved) 167 | //{ 168 | // UpdateViewport(false); 169 | //} 170 | //else 171 | //{ 172 | 173 | // UpdateViewport(true); 174 | 175 | //} 176 | 177 | if(event->type() == QEvent::Resize) 178 | { 179 | //std::cout << "resize\n"; 180 | } 181 | 182 | bool evResult = QAbstractScrollArea::event(event); 183 | return evResult; 184 | } 185 | 186 | void GLContainer::SetScrolls() 187 | { 188 | horizontalScrollBar()->setVisible(true); 189 | verticalScrollBar()->setVisible(true); 190 | 191 | _prevZoomFactor = 1.0f; 192 | 193 | std::cout << "SetScrolls\n"; 194 | 195 | // nasty code here... 196 | bool shouldZoom = true; 197 | do 198 | { 199 | //int _w = this->width(); 200 | //int _h = this->height(); 201 | QSize imgSize = _glWidget->GetCanvasSize(); 202 | 203 | if(imgSize.width() == 0 || imgSize.height() == 0) 204 | { 205 | imgSize = QSize(100, 100); 206 | } 207 | 208 | std::cout << "image size " << imgSize.width() << " - " << imgSize.height() << "\n"; 209 | double zoomFactor = _glWidget->GetZoomFactor(); 210 | 211 | if((double)this->width() < (double)imgSize.width() * zoomFactor || (double)this->height() < (double)imgSize.height() *zoomFactor) 212 | { _glWidget->ZoomOut(); } 213 | else 214 | { shouldZoom = false; } 215 | } while (shouldZoom); 216 | UpdateViewport(true); 217 | } 218 | 219 | void GLContainer::VScrollChanged(int val) 220 | { 221 | _yPrevF = val; 222 | _glWidget->VerticalScroll(val); 223 | this->_scrollMoved = true; 224 | } 225 | void GLContainer::HScrollChanged(int val) 226 | { 227 | _xPrevF = val; 228 | _glWidget->HorizontalScroll(val); 229 | this->_scrollMoved = true; 230 | } 231 | 232 | void GLContainer::DummyFunction() 233 | { 234 | _doubleClickTimer->stop(); 235 | } 236 | 237 | void GLContainer::mousePressEvent(QMouseEvent *event) 238 | { 239 | if(_doubleClickTimer->isActive()) 240 | { 241 | _doubleClickTimer->stop(); 242 | _glWidget->mouseDoubleClick(event->x(), event->y()); 243 | } 244 | else 245 | { 246 | } 247 | 248 | this->_mousePressed = true; 249 | 250 | if(!this->_ctrlPressed) 251 | { 252 | _glWidget->mousePressEvent(event->x(), event->y()); 253 | } 254 | 255 | if(this->_ctrlPressed) 256 | { 257 | this->_prevMousePos = _mousePos; 258 | this->_prevScrollPos.setX(horizontalScrollBar()->sliderPosition()); 259 | this->_prevScrollPos.setY(verticalScrollBar()->sliderPosition()); 260 | } 261 | } 262 | 263 | void GLContainer::mouseMoveEvent(QMouseEvent *event) 264 | { 265 | _mousePos.setX(event->x()); 266 | _mousePos.setY(event->y()); 267 | 268 | if(this->_ctrlPressed && this->_mousePressed) 269 | { 270 | int xDelta = _mousePos.x() - _prevMousePos.x(); 271 | int yDelta = _mousePos.y() - _prevMousePos.y(); 272 | horizontalScrollBar()->setSliderPosition(_prevScrollPos.x() - xDelta); 273 | verticalScrollBar()->setSliderPosition(_prevScrollPos.y() - yDelta); 274 | } 275 | 276 | _glWidget->mouseMoveEvent(event->x(), event->y()); 277 | } 278 | 279 | void GLContainer::mouseReleaseEvent(QMouseEvent *event) 280 | { 281 | this->_mousePressed = false; 282 | if(!this->_ctrlPressed) 283 | { 284 | _glWidget->mouseReleaseEvent(event->x(), event->y()); 285 | } 286 | 287 | _doubleClickTimer->start(_doubleClickTimeout); 288 | } 289 | 290 | void GLContainer::wheelEvent(QWheelEvent* event) 291 | { 292 | bool scrollDir = (event->delta() > 0) ? true : false; // negative means scroll down, positive is otherwise 293 | _prevZoomFactor = _glWidget->GetZoomFactor(); // for anchor zoom 294 | 295 | if(scrollDir) _glWidget->ZoomOut(); 296 | else _glWidget->ZoomIn(); 297 | 298 | float zoomFactor = _glWidget->GetZoomFactor() * 100.0; 299 | 300 | // update scrollbars 301 | UpdateViewport(); 302 | } 303 | 304 | void GLContainer::keyPressEvent(QKeyEvent *event) 305 | { 306 | if(event->key() == Qt::Key_Control) 307 | { 308 | this->_ctrlPressed = true; 309 | QApplication::setOverrideCursor(Qt::OpenHandCursor); 310 | } 311 | 312 | /*if(event->key() == Qt::Key_Right) 313 | { 314 | //std::cout << "right\n"; 315 | _glWidget->IncreaseDiv(); 316 | } 317 | else if(event->key() == Qt::Key_Left) 318 | { 319 | //std::cout << "left\n"; 320 | _glWidget->DecreaseDiv(); 321 | }*/ 322 | 323 | //if(event->key() == Qt::Key_C) { this->glWidget->DoClustering(); } 324 | 325 | 326 | //_glWidget->updateGL(); 327 | _glWidget->repaint(); 328 | } 329 | 330 | void GLContainer::keyReleaseEvent(QKeyEvent *event) 331 | { 332 | if(event->key() == Qt::Key_Control) 333 | { 334 | this->_ctrlPressed = false; 335 | QApplication::restoreOverrideCursor(); 336 | } 337 | } 338 | 339 | // get renderer 340 | GLWidget* GLContainer::GetGLWidget() 341 | { 342 | return this->_glWidget; 343 | } 344 | -------------------------------------------------------------------------------- /GLContainer.h: -------------------------------------------------------------------------------- 1 | #ifndef GLCONTAINER_H 2 | #define GLCONTAINER_H 3 | 4 | //#include "stdafx.h" 5 | #include 6 | 7 | #include "GLWidget.h" 8 | 9 | class GLContainer : public QAbstractScrollArea 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | // constructor 15 | GLContainer(QWidget *parent = 0); 16 | 17 | // for Qt internal use 18 | void setWidget(QWidget *widget); 19 | QWidget *widget() const; 20 | 21 | // get renderer 22 | GLWidget* GetGLWidget(); 23 | 24 | // set up scrolls (vertical and horizontal) 25 | void SetScrolls(); 26 | 27 | 28 | protected: 29 | // global event 30 | bool event( QEvent * event ); 31 | 32 | // draw 33 | void paintEvent(QPaintEvent *event); 34 | 35 | // mouse events 36 | void mousePressEvent(QMouseEvent *event); 37 | void mouseMoveEvent(QMouseEvent *event); 38 | void mouseReleaseEvent(QMouseEvent *event); 39 | 40 | // mouse wheel 41 | void wheelEvent(QWheelEvent* event); 42 | 43 | // keyboard 44 | void keyPressEvent(QKeyEvent *event); 45 | void keyReleaseEvent(QKeyEvent *event); 46 | 47 | private: 48 | GLWidget* _glWidget; 49 | QPoint _prevScrollPos; 50 | QPoint _prevMousePos; 51 | bool _ctrlPressed; 52 | bool _mousePressed; 53 | 54 | int _sWidth; 55 | int _sHeight; 56 | QPoint _mousePos; 57 | 58 | // for updating opengl when scrolling display 59 | float _xPrevF; 60 | float _yPrevF; 61 | float _prevZoomFactor; 62 | 63 | // previous number of strokes (not used) 64 | int _prevNum; 65 | 66 | // timer for double click 67 | QTimer* _doubleClickTimer; 68 | 69 | // timing for double click 70 | int _doubleClickTimeout; 71 | 72 | bool _scrollMoved; 73 | bool _justInitialized; 74 | 75 | private: 76 | // update opengl viewport 77 | void UpdateViewport(bool putInMiddle = false); 78 | 79 | signals: 80 | 81 | private slots: 82 | // vertical scroll 83 | void VScrollChanged(int val); 84 | 85 | // horizontal scroll 86 | void HScrollChanged(int val); 87 | 88 | // for double click effect 89 | void DummyFunction(); 90 | }; 91 | 92 | #endif // GLCONTAINER_H 93 | -------------------------------------------------------------------------------- /GLWidget.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "GLWidget.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "VertexData.h" 14 | #include "SystemParams.h" 15 | 16 | GLWidget::GLWidget(QGLFormat format, QWidget *parent) : 17 | QGLWidget(format, parent), 18 | _isMouseDown(false), 19 | _zoomFactor(50.0), 20 | _shaderProgram(0), 21 | _patternGenerator(0), 22 | _img_width(50), 23 | _img_height(50) 24 | { 25 | } 26 | 27 | GLWidget::~GLWidget() 28 | { 29 | if(_shaderProgram) delete _shaderProgram; 30 | if(_patternGenerator) delete _patternGenerator; 31 | } 32 | 33 | void GLWidget::initializeGL() 34 | { 35 | QGLFormat glFormat = QGLWidget::format(); 36 | if (!glFormat.sampleBuffers()) { std::cerr << "Could not enable sample buffers." << std::endl; return; } 37 | 38 | glShadeModel(GL_SMOOTH); 39 | 40 | glEnable(GL_BLEND); 41 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 42 | QVector3D backColor = SystemParams::background_color; 43 | glClearColor( backColor.x(), backColor.y(), backColor.z(), 1.0 ); 44 | glEnable(GL_DEPTH_TEST); 45 | 46 | _shaderProgram = new QOpenGLShaderProgram(); 47 | if (!_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, "../IslamicStarPatterns/shader.vert")) 48 | { std::cerr << "Cannot load vertex shader." << std::endl; return; } 49 | 50 | if (!_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, "../IslamicStarPatterns/shader.frag")) 51 | { std::cerr << "Cannot load fragment shader." << std::endl; return; } 52 | 53 | if ( !_shaderProgram->link() ) 54 | { std::cerr << "Cannot link shaders." << std::endl; return; } 55 | 56 | _shaderProgram->bind(); 57 | _mvpMatrixLocation = _shaderProgram->uniformLocation("mvpMatrix"); 58 | _colorLocation = _shaderProgram->attributeLocation("vertexColor"); 59 | _vertexLocation = _shaderProgram->attributeLocation("vert"); 60 | _use_color_location = _shaderProgram->uniformLocation("use_color"); 61 | 62 | if(_patternGenerator) { delete _patternGenerator; } 63 | _patternGenerator = new PatternGenerator(); 64 | _patternGenerator->_shaderProgram = _shaderProgram; 65 | _patternGenerator->_colorLocation = _colorLocation; 66 | _patternGenerator->_vertexLocation = _vertexLocation; 67 | _patternGenerator->_use_color_location = _use_color_location; 68 | _patternGenerator->_img_width = _img_width; 69 | _patternGenerator->_img_height = _img_height; 70 | _patternGenerator->InitTiling(); 71 | _patternGenerator->GeneratePattern(SystemParams::default_tiling); 72 | //_patternGenerator->GeneratePattern("test"); 73 | } 74 | 75 | void GLWidget::GeneratePattern(std::string tilingName) 76 | { 77 | _patternGenerator->GeneratePattern(tilingName); 78 | } 79 | 80 | bool GLWidget::event( QEvent * event ) 81 | { 82 | return QGLWidget::event(event); 83 | } 84 | 85 | // This is an override function from Qt but I can't find its purpose 86 | void GLWidget::resizeGL(int width, int height) 87 | { 88 | } 89 | 90 | void GLWidget::paintGL() 91 | { 92 | QVector3D backColor = SystemParams::background_color; 93 | glClearColor( backColor.x(), backColor.y(), backColor.z(), 1.0 ); 94 | //glClearColor( 0, 0, 0, 1.0 ); 95 | 96 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 97 | 98 | glViewport(0, 0, this->width(), this->height()); 99 | 100 | int current_width = width(); 101 | int current_height = height(); 102 | 103 | // Set orthographic Matrix 104 | QMatrix4x4 orthoMatrix; 105 | 106 | orthoMatrix.ortho(0.0 + _scrollOffset.x(), 107 | (float)current_width + _scrollOffset.x(), 108 | (float)current_height + _scrollOffset.y(), 109 | 0.0 + _scrollOffset.y(), 110 | -100, 100); 111 | 112 | // Translate the view to the middle 113 | QMatrix4x4 transformMatrix; 114 | transformMatrix.setToIdentity(); 115 | transformMatrix.scale(_zoomFactor); 116 | 117 | _shaderProgram->setUniformValue(_mvpMatrixLocation, orthoMatrix * transformMatrix); 118 | 119 | _patternGenerator->Paint(_zoomFactor); 120 | //PaintCurve(); 121 | } 122 | 123 | // Mouse is pressed 124 | void GLWidget::mousePressEvent(int x, int y) 125 | { 126 | _isMouseDown = true; 127 | 128 | double dx = x + _scrollOffset.x(); 129 | dx /= _zoomFactor; 130 | 131 | double dy = y + _scrollOffset.y(); 132 | dy /= _zoomFactor; 133 | 134 | this->repaint(); 135 | } 136 | 137 | // Mouse is moved 138 | void GLWidget::mouseMoveEvent(int x, int y) 139 | { 140 | double dx = x + _scrollOffset.x(); 141 | dx /= _zoomFactor; 142 | 143 | double dy = y + _scrollOffset.y(); 144 | dy /= _zoomFactor; 145 | 146 | // your stuff 147 | 148 | this->repaint(); 149 | } 150 | 151 | 152 | // Mouse is released 153 | void GLWidget::mouseReleaseEvent(int x, int y) 154 | { 155 | _isMouseDown = false; 156 | double dx = x + _scrollOffset.x(); 157 | dx /= _zoomFactor; 158 | 159 | double dy = y + _scrollOffset.y(); 160 | dy /= _zoomFactor; 161 | 162 | // your stuff 163 | 164 | this->repaint(); 165 | } 166 | 167 | void GLWidget::mouseDoubleClick(int x, int y) 168 | { 169 | double dx = x + _scrollOffset.x(); 170 | dx /= _zoomFactor; 171 | 172 | double dy = y + _scrollOffset.y(); 173 | dy /= _zoomFactor; 174 | 175 | // your stuff 176 | 177 | this->repaint(); 178 | } 179 | 180 | 181 | void GLWidget::HorizontalScroll(int val) { _scrollOffset.setX(val); } 182 | void GLWidget::VerticalScroll(int val) { _scrollOffset.setY(val); } 183 | void GLWidget::ZoomIn() { this->_zoomFactor += 10.0f; } 184 | void GLWidget::ZoomOut() { this->_zoomFactor -= 10.0f; if(this->_zoomFactor < 1.0f) _zoomFactor = 1.0f; } 185 | 186 | 187 | void GLWidget::ResizeLines(std::vector &lines, AVector offsetVec, float scaleFactor) 188 | { 189 | for(int a = 0; a < lines.size(); a++) 190 | { 191 | lines[a].XA -= offsetVec.x; 192 | lines[a].YA -= offsetVec.y; 193 | lines[a].XB -= offsetVec.x; 194 | lines[a].YB -= offsetVec.y; 195 | lines[a].XA *= scaleFactor; 196 | lines[a].YA *= scaleFactor; 197 | lines[a].XB *= scaleFactor; 198 | lines[a].YB *= scaleFactor; 199 | } 200 | } 201 | 202 | 203 | void GLWidget::SaveToSvg() 204 | { 205 | std::vector tilingLines = _patternGenerator->GetTilingLines(); 206 | std::vector uLines = _patternGenerator->GetULines(); 207 | std::vector oLines = _patternGenerator->GetOLines(); 208 | std::vector triangleLines = _patternGenerator->GetTriangleLines(); 209 | std::vector backTriangleLines = _patternGenerator->GetBackTriangleLines(); 210 | std::vector addTriangleLines = _patternGenerator->GetAddTriangleLines(); 211 | 212 | float xLeft = 0 + _scrollOffset.x(); 213 | float yTop = 0 + _scrollOffset.y(); 214 | 215 | float invScale = 1.0 / this->_zoomFactor; 216 | xLeft *= invScale; 217 | yTop *= invScale; 218 | 219 | AVector offsetVec(xLeft, yTop); 220 | 221 | ResizeLines(tilingLines, offsetVec, _zoomFactor); 222 | ResizeLines(uLines, offsetVec, _zoomFactor); 223 | ResizeLines(oLines, offsetVec, _zoomFactor); 224 | ResizeLines(triangleLines, offsetVec, _zoomFactor); 225 | ResizeLines(backTriangleLines, offsetVec, _zoomFactor); 226 | ResizeLines(addTriangleLines, offsetVec, _zoomFactor); 227 | 228 | QSvgGenerator generator; 229 | generator.setFileName("image.svg"); 230 | generator.setSize(QSize(this->width(), this->height())); 231 | generator.setViewBox(QRect(0, 0, this->width(), this->height())); 232 | generator.setTitle(tr("Islamic Star Pattern")); 233 | generator.setDescription(tr("Islamic Star Pattern")); 234 | QPainter painter; 235 | painter.begin(&generator); 236 | painter.setClipRect(QRect(0, 0, this->width(), this->height())); 237 | 238 | QBrush myBrush; 239 | QVector3D backVec = SystemParams::background_color; 240 | QColor backCol(backVec.x() * 255, backVec.y() * 255, backVec.z() * 255); 241 | myBrush.setColor(backCol); 242 | myBrush.setStyle(Qt::SolidPattern); 243 | painter.fillRect(QRect(0, 0, this->width(), this->height()), myBrush); 244 | 245 | QVector3D ribVec = SystemParams::ribbon_color; 246 | QVector3D lineVec = SystemParams::interlacing_color; 247 | QVector3D starVec = SystemParams::star_color; 248 | QColor starCol(starVec.x() * 255, starVec.y() * 255, starVec.z() * 255); 249 | QColor ribCol(ribVec.x() * 255, ribVec.y() * 255, ribVec.z() * 255); 250 | QColor lineCol(lineVec.x() * 255, lineVec.y() * 255, lineVec.z() * 255); 251 | 252 | // star triangles 253 | myBrush.setColor(starCol); 254 | myBrush.setStyle(Qt::SolidPattern); 255 | painter.setPen(QPen(starCol, 0.75, Qt::SolidLine, Qt::RoundCap)); 256 | for(int a = 0; a < triangleLines.size(); a += 3) 257 | { 258 | ALine line1 = triangleLines[a]; 259 | ALine line2 = triangleLines[a+1]; 260 | ALine line3 = triangleLines[a+2]; 261 | 262 | QPolygonF poly; 263 | poly << QPointF(line1.XA, line1.YA) 264 | << QPointF(line1.XB, line1.YB) 265 | << QPointF(line3.XA, line3.YA); 266 | 267 | QPainterPath path; 268 | path.addPolygon(poly); 269 | painter.drawPolygon(poly); 270 | painter.fillPath(path, myBrush); 271 | } 272 | 273 | // back triangles 274 | myBrush.setColor(backCol); 275 | myBrush.setStyle(Qt::SolidPattern); 276 | painter.setPen(QPen(backCol, 0.75, Qt::SolidLine, Qt::RoundCap)); 277 | for(int a = 0; a < backTriangleLines.size(); a += 3) 278 | { 279 | ALine line1 = backTriangleLines[a]; 280 | ALine line2 = backTriangleLines[a+1]; 281 | ALine line3 = backTriangleLines[a+2]; 282 | 283 | QPolygonF poly; 284 | poly << QPointF(line1.XA, line1.YA) 285 | << QPointF(line1.XB, line1.YB) 286 | << QPointF(line3.XA, line3.YA); 287 | 288 | QPainterPath path; 289 | path.addPolygon(poly); 290 | painter.drawPolygon(poly); 291 | painter.fillPath(path, myBrush); 292 | } 293 | 294 | // add triangles 295 | myBrush.setColor(starCol); 296 | myBrush.setStyle(Qt::SolidPattern); 297 | painter.setPen(QPen(starCol, 0.75, Qt::SolidLine, Qt::RoundCap)); 298 | for(int a = 0; a < addTriangleLines.size(); a += 3) 299 | { 300 | ALine line1 = addTriangleLines[a]; 301 | ALine line2 = addTriangleLines[a+1]; 302 | ALine line3 = addTriangleLines[a+2]; 303 | 304 | QPolygonF poly; 305 | poly << QPointF(line1.XA, line1.YA) 306 | << QPointF(line1.XB, line1.YB) 307 | << QPointF(line3.XA, line3.YA); 308 | 309 | QPainterPath path; 310 | path.addPolygon(poly); 311 | painter.drawPolygon(poly); 312 | painter.fillPath(path, myBrush); 313 | } 314 | 315 | // under ribbons 316 | myBrush.setColor(ribCol); 317 | myBrush.setStyle(Qt::SolidPattern); 318 | painter.setPen(QPen(ribCol, 0.25, Qt::SolidLine, Qt::RoundCap)); 319 | for(int a = 0; a < uLines.size(); a += 2) 320 | { 321 | ALine line1 = uLines[a]; 322 | ALine line2 = uLines[a+1]; 323 | 324 | QPolygonF poly; 325 | poly << QPointF(line1.XA, line1.YA) 326 | << QPointF(line1.XB, line1.YB) 327 | << QPointF(line2.XB, line2.YB) 328 | << QPointF(line2.XA, line2.YA); 329 | 330 | QPainterPath path; 331 | path.addPolygon(poly); 332 | painter.drawPolygon(poly); 333 | painter.fillPath(path, myBrush); 334 | } 335 | 336 | painter.setPen(QPen(lineCol, SystemParams::line_width * _zoomFactor, Qt::SolidLine, Qt::RoundCap)); 337 | for(int a = 0; a < uLines.size(); a++) 338 | { 339 | ALine aLine = uLines[a]; 340 | painter.drawLine(QPointF(aLine.XA, aLine.YA), 341 | QPointF(aLine.XB, aLine.YB)); 342 | } 343 | 344 | 345 | myBrush.setColor(ribCol); 346 | myBrush.setStyle(Qt::SolidPattern); 347 | painter.setPen(QPen(ribCol, 0.25, Qt::SolidLine, Qt::RoundCap)); 348 | for(int a = 0; a < oLines.size(); a += 2) 349 | { 350 | ALine line1 = oLines[a]; 351 | ALine line2 = oLines[a+1]; 352 | 353 | QPolygonF poly; 354 | poly << QPointF(line1.XA, line1.YA) 355 | << QPointF(line1.XB, line1.YB) 356 | << QPointF(line2.XB, line2.YB) 357 | << QPointF(line2.XA, line2.YA); 358 | 359 | QPainterPath path; 360 | path.addPolygon(poly); 361 | painter.drawPolygon(poly); 362 | painter.fillPath(path, myBrush); 363 | } 364 | 365 | painter.setPen(QPen(lineCol, SystemParams::line_width * _zoomFactor, Qt::SolidLine, Qt::RoundCap)); 366 | for(int a = 0; a < oLines.size(); a++) 367 | { 368 | ALine aLine = oLines[a]; 369 | 370 | painter.drawLine(QPointF(aLine.XA, aLine.YA), 371 | QPointF(aLine.XB, aLine.YB)); 372 | } 373 | 374 | 375 | painter.end(); 376 | 377 | } 378 | 379 | 380 | -------------------------------------------------------------------------------- /GLWidget.h: -------------------------------------------------------------------------------- 1 | #ifndef GLWIDGET_H 2 | #define GLWIDGET_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "AVector.h" 14 | #include "ALine.h" 15 | #include "PatternGenerator.h" 16 | 17 | class GLWidget : public QGLWidget 18 | { 19 | Q_OBJECT 20 | 21 | private: 22 | bool _isMouseDown; 23 | float _zoomFactor; 24 | QPoint _scrollOffset; 25 | 26 | // image size 27 | int _img_width; 28 | int _img_height; 29 | 30 | // shader 31 | QOpenGLShaderProgram* _shaderProgram; 32 | 33 | PatternGenerator* _patternGenerator; 34 | 35 | // points 36 | std::vector _points; 37 | QOpenGLBuffer _pointsVbo; 38 | QOpenGLVertexArrayObject _pointsVao; 39 | 40 | // lines 41 | //std::vector _tilingLines; 42 | //QOpenGLBuffer _tilingLinesVbo; 43 | //QOpenGLVertexArrayObject _tilingLinesVao; 44 | 45 | // for rendering 46 | int _mvpMatrixLocation; 47 | int _colorLocation; 48 | int _vertexLocation; 49 | int _use_color_location; 50 | QMatrix4x4 _perspMatrix; 51 | QMatrix4x4 _transformMatrix; 52 | 53 | private: 54 | //void InitCurve(); 55 | //void PaintCurve(); 56 | //void CreateCurveVAO(); 57 | 58 | 59 | 60 | //void InitTiling(); 61 | //std::vector GenerateNGon(float sides, float radius, float angleOffset, AVector centerPt); 62 | //void ConcatNGon(std::vector sourcePolygon, std::vector &destinationLines); 63 | //AVector MultiplyVector(QMatrix3x3 mat, AVector vec); 64 | //void MultiplyShape(QMatrix3x3 mat, std::vector& shape); 65 | 66 | //void PreparePointsVAO(std::vector points, QOpenGLBuffer* ptsVbo, QOpenGLVertexArrayObject* ptsVao, QVector3D vecCol); 67 | //void PrepareLinesVAO(std::vector lines, QOpenGLBuffer* linesVbo, QOpenGLVertexArrayObject* linesVao, QVector3D vecCol); 68 | 69 | protected: 70 | // qt event 71 | bool event( QEvent * event ); 72 | // init opengl 73 | void initializeGL(); 74 | // draw 75 | void paintGL(); 76 | 77 | void resizeGL(int width, int height); 78 | 79 | public: 80 | 81 | // constructor 82 | GLWidget( QGLFormat format, QWidget *parent = 0); 83 | // destructor 84 | ~GLWidget(); 85 | 86 | QSize GetCanvasSize() { return QSize(_img_width, _img_height); } 87 | 88 | void SaveToSvg(); 89 | 90 | // zoom in handle 91 | void ZoomIn(); 92 | // zoom out handle 93 | void ZoomOut(); 94 | // set zoom value 95 | void SetZoom(int val){this->_zoomFactor = val;} 96 | // get zoom value 97 | float GetZoomFactor() { return this->_zoomFactor; } 98 | 99 | // set horizontal scroll position 100 | void HorizontalScroll(int val); 101 | // set vertical scroll position 102 | void VerticalScroll(int val); 103 | // get scroll position (horizontal and vertical) 104 | QPoint GetScrollOffset() {return this->_scrollOffset;} 105 | 106 | // mouse press 107 | void mousePressEvent(int x, int y); 108 | // mouse move 109 | void mouseMoveEvent(int x, int y); 110 | // mouse release 111 | void mouseReleaseEvent(int x, int y); 112 | // mouse double click 113 | void mouseDoubleClick(int x, int y); 114 | 115 | void GeneratePattern(std::string tilingName); 116 | 117 | void ResizeLines(std::vector &lines, AVector offsetVec, float scaleFactor); 118 | 119 | /*void IncreaseDiv() 120 | { 121 | std::cout << "increase\n"; 122 | _patternGenerator->sideDiv += 1; 123 | _patternGenerator->InitTiling2(); 124 | }*/ 125 | 126 | /*void DecreaseDiv() 127 | { 128 | std::cout << "decrease\n"; 129 | _patternGenerator->sideDiv -= 1; 130 | _patternGenerator->InitTiling2(); 131 | }*/ 132 | }; 133 | 134 | #endif // GLWIDGET_H 135 | -------------------------------------------------------------------------------- /IslamicStarPattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/azer89/Star_Patterns/20e2ce00918a8dc81bfeb4443a836daaf63503c2/IslamicStarPattern.png -------------------------------------------------------------------------------- /IslamicStarPatterns.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2015-07-06T12:01:20 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui opengl svg 8 | 9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 10 | 11 | TARGET = IslamicStarPatterns 12 | TEMPLATE = app 13 | 14 | 15 | SOURCES += main.cpp\ 16 | mainwindow.cpp \ 17 | GLContainer.cpp \ 18 | GLWidget.cpp \ 19 | tinyxml2.cpp \ 20 | PatternGenerator.cpp \ 21 | SystemParams.cpp \ 22 | Triangulator.cpp 23 | 24 | HEADERS += mainwindow.h \ 25 | ALine.h \ 26 | AVector.h \ 27 | GLContainer.h \ 28 | GLWidget.h \ 29 | VertexData.h \ 30 | tinyxml2.h \ 31 | PatternGenerator.h \ 32 | TilingData.h \ 33 | SystemParams.h \ 34 | RibbonSegment.h \ 35 | Triangulator.h 36 | 37 | FORMS += mainwindow.ui 38 | 39 | INCLUDEPATH += /usr/include/ 40 | LIBS += -L/usr/include/ 41 | LIBS += -lCGAL 42 | LIBS += -lgmp 43 | LIBS += -lmpfr 44 | 45 | QMAKE_CXXFLAGS += -frounding-math -O3 46 | 47 | QMAKE_CXXFLAGS += -std=gnu++1y 48 | 49 | OTHER_FILES += \ 50 | archimedeans.xml \ 51 | hanbury.xml 52 | -------------------------------------------------------------------------------- /IslamicStarPatterns.pro.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EnvironmentId 7 | {3bf7fdc9-23a2-4729-8484-e45b2219abe2} 8 | 9 | 10 | ProjectExplorer.Project.ActiveTarget 11 | 0 12 | 13 | 14 | ProjectExplorer.Project.EditorSettings 15 | 16 | true 17 | false 18 | true 19 | 20 | Cpp 21 | 22 | CppGlobal 23 | 24 | 25 | 26 | QmlJS 27 | 28 | QmlJSGlobal 29 | 30 | 31 | 2 32 | UTF-8 33 | false 34 | 4 35 | false 36 | 80 37 | true 38 | true 39 | 1 40 | true 41 | false 42 | 0 43 | true 44 | 0 45 | 8 46 | true 47 | 1 48 | true 49 | true 50 | true 51 | false 52 | 53 | 54 | 55 | ProjectExplorer.Project.PluginSettings 56 | 57 | 58 | 59 | ProjectExplorer.Project.Target.0 60 | 61 | Desktop Qt 5.5.1 GCC 64bit 62 | Desktop Qt 5.5.1 GCC 64bit 63 | qt.55.gcc_64_kit 64 | 1 65 | 0 66 | 0 67 | 68 | /home/azer/workspace/cpp/build-IslamicStarPatterns-Desktop_Qt_5_5_1_GCC_64bit-Debug 69 | 70 | 71 | true 72 | qmake 73 | 74 | QtProjectManager.QMakeBuildStep 75 | false 76 | true 77 | 78 | false 79 | false 80 | false 81 | 82 | 83 | true 84 | Make 85 | 86 | Qt4ProjectManager.MakeStep 87 | 88 | -w 89 | -r 90 | 91 | false 92 | 93 | 94 | 95 | 2 96 | Build 97 | 98 | ProjectExplorer.BuildSteps.Build 99 | 100 | 101 | 102 | true 103 | Make 104 | 105 | Qt4ProjectManager.MakeStep 106 | 107 | -w 108 | -r 109 | 110 | true 111 | clean 112 | 113 | 114 | 1 115 | Clean 116 | 117 | ProjectExplorer.BuildSteps.Clean 118 | 119 | 2 120 | false 121 | 122 | Debug 123 | 124 | Qt4ProjectManager.Qt4BuildConfiguration 125 | 2 126 | true 127 | 128 | 129 | /home/azer/workspace/cpp/build-IslamicStarPatterns-Desktop_Qt_5_5_1_GCC_64bit-Release 130 | 131 | 132 | true 133 | qmake 134 | 135 | QtProjectManager.QMakeBuildStep 136 | false 137 | true 138 | 139 | false 140 | false 141 | false 142 | 143 | 144 | true 145 | Make 146 | 147 | Qt4ProjectManager.MakeStep 148 | 149 | -w 150 | -r 151 | 152 | false 153 | 154 | 155 | 156 | 2 157 | Build 158 | 159 | ProjectExplorer.BuildSteps.Build 160 | 161 | 162 | 163 | true 164 | Make 165 | 166 | Qt4ProjectManager.MakeStep 167 | 168 | -w 169 | -r 170 | 171 | true 172 | clean 173 | 174 | 175 | 1 176 | Clean 177 | 178 | ProjectExplorer.BuildSteps.Clean 179 | 180 | 2 181 | false 182 | 183 | Release 184 | 185 | Qt4ProjectManager.Qt4BuildConfiguration 186 | 0 187 | true 188 | 189 | 2 190 | 191 | 192 | 0 193 | Deploy 194 | 195 | ProjectExplorer.BuildSteps.Deploy 196 | 197 | 1 198 | Deploy locally 199 | 200 | ProjectExplorer.DefaultDeployConfiguration 201 | 202 | 1 203 | 204 | 205 | 206 | false 207 | false 208 | false 209 | false 210 | true 211 | 0.01 212 | 10 213 | true 214 | 1 215 | 25 216 | 217 | 1 218 | true 219 | false 220 | true 221 | valgrind 222 | 223 | 0 224 | 1 225 | 2 226 | 3 227 | 4 228 | 5 229 | 6 230 | 7 231 | 8 232 | 9 233 | 10 234 | 11 235 | 12 236 | 13 237 | 14 238 | 239 | 2 240 | 241 | IslamicStarPatterns 242 | 243 | Qt4ProjectManager.Qt4RunConfiguration:/home/azer/workspace/cpp/IslamicStarPatterns/IslamicStarPatterns.pro 244 | 245 | IslamicStarPatterns.pro 246 | false 247 | false 248 | 249 | 3768 250 | false 251 | true 252 | false 253 | false 254 | true 255 | 256 | 1 257 | 258 | 259 | 260 | ProjectExplorer.Project.Target.1 261 | 262 | Desktop 263 | Desktop 264 | {150c7824-edb9-476b-afc6-2ae43f7e2fba} 265 | 0 266 | 0 267 | 0 268 | 269 | /home/azer/build-IslamicStarPatterns-Desktop-Debug 270 | 271 | 272 | true 273 | qmake 274 | 275 | QtProjectManager.QMakeBuildStep 276 | false 277 | true 278 | 279 | false 280 | false 281 | false 282 | 283 | 284 | true 285 | Make 286 | 287 | Qt4ProjectManager.MakeStep 288 | 289 | -w 290 | -r 291 | 292 | false 293 | 294 | 295 | 296 | 2 297 | Build 298 | 299 | ProjectExplorer.BuildSteps.Build 300 | 301 | 302 | 303 | true 304 | Make 305 | 306 | Qt4ProjectManager.MakeStep 307 | 308 | -w 309 | -r 310 | 311 | true 312 | clean 313 | 314 | 315 | 1 316 | Clean 317 | 318 | ProjectExplorer.BuildSteps.Clean 319 | 320 | 2 321 | false 322 | 323 | Debug 324 | 325 | Qt4ProjectManager.Qt4BuildConfiguration 326 | 2 327 | true 328 | 329 | 330 | /home/azer/build-IslamicStarPatterns-Desktop-Release 331 | 332 | 333 | true 334 | qmake 335 | 336 | QtProjectManager.QMakeBuildStep 337 | false 338 | true 339 | 340 | false 341 | false 342 | false 343 | 344 | 345 | true 346 | Make 347 | 348 | Qt4ProjectManager.MakeStep 349 | 350 | -w 351 | -r 352 | 353 | false 354 | 355 | 356 | 357 | 2 358 | Build 359 | 360 | ProjectExplorer.BuildSteps.Build 361 | 362 | 363 | 364 | true 365 | Make 366 | 367 | Qt4ProjectManager.MakeStep 368 | 369 | -w 370 | -r 371 | 372 | true 373 | clean 374 | 375 | 376 | 1 377 | Clean 378 | 379 | ProjectExplorer.BuildSteps.Clean 380 | 381 | 2 382 | false 383 | 384 | Release 385 | 386 | Qt4ProjectManager.Qt4BuildConfiguration 387 | 0 388 | true 389 | 390 | 2 391 | 392 | 393 | 0 394 | Deploy 395 | 396 | ProjectExplorer.BuildSteps.Deploy 397 | 398 | 1 399 | Deploy locally 400 | 401 | ProjectExplorer.DefaultDeployConfiguration 402 | 403 | 1 404 | 405 | 406 | 407 | false 408 | false 409 | false 410 | false 411 | true 412 | 0.01 413 | 10 414 | true 415 | 1 416 | 25 417 | 418 | 1 419 | true 420 | false 421 | true 422 | valgrind 423 | 424 | 0 425 | 1 426 | 2 427 | 3 428 | 4 429 | 5 430 | 6 431 | 7 432 | 8 433 | 9 434 | 10 435 | 11 436 | 12 437 | 13 438 | 14 439 | 440 | -1 441 | 442 | 443 | 444 | %{buildDir} 445 | Custom Executable 446 | 447 | ProjectExplorer.CustomExecutableRunConfiguration 448 | 3768 449 | false 450 | true 451 | false 452 | false 453 | true 454 | 455 | 1 456 | 457 | 458 | 459 | ProjectExplorer.Project.Target.2 460 | 461 | Desktop Qt 5.3 GCC 64bit 462 | Desktop Qt 5.3 GCC 64bit 463 | {ad1ac316-989f-47e8-a341-815b4bc5d59c} 464 | 1 465 | 0 466 | 0 467 | 468 | /home/azer/workspace/cpp/build-IslamicStarPatterns-Desktop_Qt_5_3_GCC_64bit-Debug 469 | 470 | 471 | true 472 | qmake 473 | 474 | QtProjectManager.QMakeBuildStep 475 | false 476 | true 477 | 478 | false 479 | false 480 | false 481 | 482 | 483 | true 484 | Make 485 | 486 | Qt4ProjectManager.MakeStep 487 | 488 | -w 489 | -r 490 | 491 | false 492 | 493 | 494 | 495 | 2 496 | Build 497 | 498 | ProjectExplorer.BuildSteps.Build 499 | 500 | 501 | 502 | true 503 | Make 504 | 505 | Qt4ProjectManager.MakeStep 506 | 507 | -w 508 | -r 509 | 510 | true 511 | clean 512 | 513 | 514 | 1 515 | Clean 516 | 517 | ProjectExplorer.BuildSteps.Clean 518 | 519 | 2 520 | false 521 | 522 | Debug 523 | 524 | Qt4ProjectManager.Qt4BuildConfiguration 525 | 2 526 | true 527 | 528 | 529 | /home/azer/workspace/cpp/build-IslamicStarPatterns-Desktop_Qt_5_3_GCC_64bit-Release 530 | 531 | 532 | true 533 | qmake 534 | 535 | QtProjectManager.QMakeBuildStep 536 | false 537 | true 538 | 539 | false 540 | false 541 | false 542 | 543 | 544 | true 545 | Make 546 | 547 | Qt4ProjectManager.MakeStep 548 | 549 | -w 550 | -r 551 | 552 | false 553 | 554 | 555 | 556 | 2 557 | Build 558 | 559 | ProjectExplorer.BuildSteps.Build 560 | 561 | 562 | 563 | true 564 | Make 565 | 566 | Qt4ProjectManager.MakeStep 567 | 568 | -w 569 | -r 570 | 571 | true 572 | clean 573 | 574 | 575 | 1 576 | Clean 577 | 578 | ProjectExplorer.BuildSteps.Clean 579 | 580 | 2 581 | false 582 | 583 | Release 584 | 585 | Qt4ProjectManager.Qt4BuildConfiguration 586 | 0 587 | true 588 | 589 | 2 590 | 591 | 592 | 0 593 | Deploy 594 | 595 | ProjectExplorer.BuildSteps.Deploy 596 | 597 | 1 598 | Deploy locally 599 | 600 | ProjectExplorer.DefaultDeployConfiguration 601 | 602 | 1 603 | 604 | 605 | 606 | false 607 | false 608 | false 609 | false 610 | true 611 | 0.01 612 | 10 613 | true 614 | 1 615 | 25 616 | 617 | 1 618 | true 619 | false 620 | true 621 | valgrind 622 | 623 | 0 624 | 1 625 | 2 626 | 3 627 | 4 628 | 5 629 | 6 630 | 7 631 | 8 632 | 9 633 | 10 634 | 11 635 | 12 636 | 13 637 | 14 638 | 639 | 2 640 | 641 | IslamicStarPatterns 642 | IslamicStarPatterns2 643 | Qt4ProjectManager.Qt4RunConfiguration:/home/azer/workspace/cpp/IslamicStarPatterns/IslamicStarPatterns.pro 644 | 645 | IslamicStarPatterns.pro 646 | false 647 | false 648 | 649 | 3768 650 | false 651 | true 652 | false 653 | false 654 | true 655 | 656 | 1 657 | 658 | 659 | 660 | ProjectExplorer.Project.TargetCount 661 | 3 662 | 663 | 664 | ProjectExplorer.Project.Updater.FileVersion 665 | 18 666 | 667 | 668 | Version 669 | 18 670 | 671 | 672 | -------------------------------------------------------------------------------- /PatternGenerator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include "tinyxml2.h" 7 | 8 | //#include "ARay.h" 9 | #include "VertexData.h" 10 | #include "PatternGenerator.h" 11 | #include "SystemParams.h" 12 | #include "Triangulator.h" 13 | 14 | 15 | PatternGenerator::PatternGenerator() 16 | { 17 | } 18 | 19 | PatternGenerator::~PatternGenerator() 20 | { 21 | } 22 | 23 | void PatternGenerator::ReadXML(std::string filename) 24 | { 25 | using namespace tinyxml2; 26 | 27 | XMLDocument doc; 28 | doc.LoadFile( filename.c_str() ); 29 | std::cout << "XMl error: " << doc.ErrorID() << "\n\n"; 30 | 31 | for( XMLNode* node = doc.FirstChildElement("tiling-library")->FirstChildElement("tiling"); 32 | node; 33 | node = node->NextSibling() ) 34 | { 35 | TilingData tilingData; 36 | 37 | XMLElement* elem = node->ToElement(); 38 | tilingData._name = elem->Attribute("name"); 39 | //std::cout << tilingData._name << "\n"; 40 | 41 | // translations 42 | XMLNode* tNode = node->FirstChildElement("translations"); 43 | XMLNode* vNode1 = tNode->FirstChildElement("vector"); 44 | XMLNode* vNode2 = vNode1->NextSibling(); 45 | 46 | XMLElement* vElement1 = vNode1->ToElement(); 47 | XMLElement* vElement2 = vNode2->ToElement(); 48 | 49 | tilingData._translation1 = AVector(std::stof(vElement1->Attribute("x")), std::stof(vElement1->Attribute("y"))); 50 | tilingData._translation2 = AVector(std::stof(vElement2->Attribute("x")), std::stof(vElement2->Attribute("y"))); 51 | //std::cout << "(" << trans1.x << ", " << trans1.y << ") (" << trans2.x << ", " << trans2.y << ")\n"; 52 | 53 | // tiles 54 | for( XMLNode* tileNode = tNode->NextSibling(); 55 | tileNode; 56 | tileNode = tileNode->NextSibling() ) 57 | { 58 | TileData tileData; 59 | 60 | // shape 61 | XMLNode* shapeNode = tileNode->FirstChildElement("shape"); 62 | XMLElement* shapeElement = shapeNode->ToElement(); 63 | 64 | std::string typeStr = shapeElement->Attribute("type"); 65 | 66 | ShapeType sType; 67 | if(typeStr == "regular") 68 | { 69 | sType = ShapeType::S_REGULAR; 70 | tileData._sides = std::stof(shapeElement->Attribute("sides")); 71 | } 72 | else if(typeStr == "polygon") 73 | { 74 | sType = ShapeType::S_POLYGON; 75 | 76 | for( XMLNode* vertexNode = shapeNode->FirstChildElement("vertex"); 77 | vertexNode; 78 | vertexNode = vertexNode->NextSibling() ) 79 | { 80 | XMLElement* vertexElement = vertexNode->ToElement(); 81 | tileData._vertices.push_back(AVector(std::stof(vertexElement->Attribute("x")), 82 | std::stof(vertexElement->Attribute("y")))); 83 | //std::cout << "v " << std::stof(vertexElement->Attribute("x")) << " " << std::stof(vertexElement->Attribute("y")) << "\n"; 84 | } 85 | // to do: why reverse ? 86 | std::reverse(tileData._vertices.begin(), tileData._vertices.end()); 87 | } 88 | 89 | tileData._shapeType = sType; 90 | 91 | //float sidesStr = std::stof(shapeElement->Attribute("sides")); 92 | //std::cout << typeStr << " " << sidesStr << "\n"; 93 | 94 | // transformations 95 | for( XMLNode* transformNode = tileNode->FirstChildElement("transform"); 96 | transformNode; 97 | transformNode = transformNode->NextSibling() ) 98 | { 99 | QMatrix3x3 mat; 100 | 101 | //std::cout << "t"; 102 | XMLElement* transformElement = transformNode->ToElement(); 103 | 104 | mat(0, 0) = std::stof(transformElement->Attribute("a")); 105 | mat(0, 1) = std::stof(transformElement->Attribute("b")); 106 | mat(0, 2) = std::stof(transformElement->Attribute("c")); 107 | 108 | mat(1, 0) = std::stof(transformElement->Attribute("d")); 109 | mat(1, 1) = std::stof(transformElement->Attribute("e")); 110 | mat(1, 2) = std::stof(transformElement->Attribute("f")); 111 | 112 | tileData._transforms.push_back(mat); 113 | //std::cout << mat(0, 0) << " " << mat(0, 1) << " " << mat(0, 2) << " " 114 | // << mat(1, 0) << " " << mat(1, 1) << " " << mat(1, 2) << "\n"; 115 | } 116 | tilingData._tiles.push_back(tileData); 117 | //std::cout << "\n"; 118 | } 119 | //std::cout << "\n"; 120 | this->_tilings.push_back(tilingData); 121 | } 122 | //std::cout << _tilings.size() << "\n"; 123 | 124 | } 125 | 126 | TilingData PatternGenerator::GetTiling(std::string tilingName) 127 | { 128 | TilingData tilingData; 129 | for(int a = 0; a < _tilings.size(); a++) 130 | { 131 | if(_tilings[a]._name == tilingName) 132 | { 133 | tilingData = _tilings[a]; 134 | break; 135 | } 136 | } 137 | 138 | return tilingData; 139 | } 140 | 141 | void PatternGenerator::InferenceAlgorithm(std::vector> shapes) 142 | { 143 | _rayLines.clear(); 144 | _tempPoints.clear(); 145 | _triangleLines.clear(); 146 | _backTriangleLines.clear(); 147 | _addTriangleLines.clear(); 148 | _tempLines.clear(); 149 | _uLines.clear(); 150 | _oLines.clear(); 151 | 152 | float eps_val = std::numeric_limits::epsilon() * 1000.0f; 153 | 154 | float angle1 = -SystemParams::rad_angle; 155 | float angle2 = -M_PI - angle1; 156 | 157 | float cos1 = cos(angle1); 158 | float sin1 = sin(angle1); 159 | float cos2 = cos(angle2); 160 | float sin2 = sin(angle2); 161 | 162 | for(int a = 0; a < shapes.size(); a++) 163 | { 164 | std::vector aShape = shapes[a]; 165 | int sides = aShape.size(); 166 | std::vector sRays; 167 | 168 | for(int b = 0; b < aShape.size(); b++) 169 | { 170 | ALine aLine = aShape[b]; 171 | 172 | AVector dirVec = (aLine.GetPointB() - aLine.GetPointA()).Norm(); 173 | AVector midPoint = (aLine.GetPointB() - aLine.GetPointA()) * 0.5 + aLine.GetPointA(); 174 | 175 | // a right ray 176 | AVector dirVecRotated1; 177 | dirVecRotated1.x = cos1 * dirVec.x - sin1 * dirVec.y; 178 | dirVecRotated1.y = sin1 * dirVec.x + cos1 * dirVec.y; 179 | sRays.push_back(ALine(midPoint + dirVec * SystemParams::contact_delta, 180 | dirVecRotated1.Norm(), true, b)); 181 | 182 | // a left ray 183 | AVector dirVecRotated2; 184 | dirVecRotated2.x = cos2 * dirVec.x - sin2 * dirVec.y; 185 | dirVecRotated2.y = sin2 * dirVec.x + cos2 * dirVec.y; 186 | sRays.push_back(ALine(midPoint + AVector(-dirVec.x, -dirVec.y) * SystemParams::contact_delta, 187 | dirVecRotated2.Norm(), false, b)); 188 | } 189 | 190 | // create combinations 191 | std::vector> rayCombination; 192 | for(int a = 0; a < sRays.size(); a++) 193 | { 194 | for(int b = a + 1; b < sRays.size(); b++) 195 | { 196 | ALine line1 = sRays[a]; 197 | ALine line2 = sRays[b]; 198 | 199 | if(line1._isRight) 200 | { 201 | std::pair aPair(line1, line2); 202 | rayCombination.push_back(aPair); 203 | } 204 | else // flip 205 | { 206 | std::pair aPair(line2, line1); 207 | rayCombination.push_back(aPair); 208 | } 209 | } 210 | } 211 | 212 | // calculate candidates 213 | std::vector> lineCombination1; 214 | for(int a = 0; a < rayCombination.size(); a++) 215 | { 216 | ALine rayA = rayCombination[a].first; 217 | ALine rayB = rayCombination[a].second; 218 | 219 | if(rayA._isRight == rayB._isRight) { continue; } 220 | if(rayA._side == rayB._side) { continue; } 221 | 222 | float dx = rayB.GetPointA().x - rayA.GetPointA().x; 223 | float dy = rayB.GetPointA().y - rayA.GetPointA().y; 224 | float det = rayB.GetPointB().x * rayA.GetPointB().y - rayB.GetPointB().y * rayA.GetPointB().x; 225 | float u = (dy * rayB.GetPointB().x - dx * rayB.GetPointB().y) / det; 226 | float v = (dy * rayA.GetPointB().x - dx * rayA.GetPointB().y) / det; 227 | 228 | 229 | if((det > eps_val || det < -eps_val) && u > 0 && v > 0) 230 | { 231 | ALine aLine1(rayA.GetPointA(), rayA.GetPointA() + rayA.GetPointB() * u); 232 | aLine1._isRight = rayA._isRight; 233 | aLine1._side = rayA._side; 234 | 235 | ALine aLine2(rayB.GetPointA(), rayB.GetPointA() + rayB.GetPointB() * v); 236 | aLine2._isRight = rayB._isRight; 237 | aLine2._side = rayB._side; 238 | 239 | lineCombination1.push_back(std::pair(aLine1, aLine2)); 240 | } 241 | else if(CheckCollinearCase(rayA, rayB) || CheckHorizontalVerticalCase(rayA, rayB)) 242 | { 243 | AVector midPoint = rayA.GetPointA() + (rayB.GetPointA() - rayA.GetPointA()) * 0.5f; 244 | 245 | ALine aLine1(rayA.GetPointA(), midPoint); 246 | aLine1._isRight = rayA._isRight; 247 | aLine1._side = rayA._side; 248 | 249 | ALine aLine2(rayB.GetPointA(), midPoint); 250 | aLine2._isRight = rayB._isRight; 251 | aLine2._side = rayB._side; 252 | 253 | lineCombination1.push_back(std::pair(aLine1, aLine2)); 254 | } 255 | } 256 | 257 | std::sort (lineCombination1.begin(), lineCombination1.end(), LessThanLineMagnitudePair()); 258 | 259 | int counter = 0; 260 | std::vector> lineCombination2; 261 | while(counter < sides) 262 | { 263 | 264 | ALine aLine1 = lineCombination1[0].first; 265 | ALine aLine2 = lineCombination1[0].second; 266 | 267 | lineCombination2.push_back(lineCombination1[0]); 268 | 269 | for(int i = lineCombination1.size() - 1; i >= 0; i--) 270 | { 271 | std::pair linePair = lineCombination1[i]; 272 | if(( linePair.first._isRight == aLine1._isRight && linePair.first._side == aLine1._side) || 273 | ( linePair.second._isRight == aLine1._isRight && linePair.second._side == aLine1._side ) || 274 | 275 | ( linePair.first._isRight == aLine2._isRight && linePair.first._side == aLine2._side) || 276 | ( linePair.second._isRight == aLine2._isRight && linePair.second._side == aLine2._side )) 277 | { 278 | lineCombination1.erase (lineCombination1.begin() + i); 279 | } 280 | } 281 | 282 | counter++; 283 | } 284 | 285 | 286 | for(int a = 0; a < lineCombination2.size(); a++) 287 | { 288 | ALine aLine1 = lineCombination2[a].first; 289 | ALine aLine2 = lineCombination2[a].second; 290 | _rayLines.push_back(aLine1); 291 | _rayLines.push_back(aLine2); 292 | 293 | CalculateInterlace(lineCombination2[a], aShape, _uLines, _oLines); 294 | } 295 | 296 | if(SystemParams::contact_delta > -eps_val && SystemParams::contact_delta < eps_val) 297 | { 298 | std::vector triangles1 = Triangulator::GetTriangles1(lineCombination2, aShape[0].GetPointA()); 299 | 300 | _triangleLines.insert( _triangleLines.end(), triangles1.begin(), triangles1.end() ); 301 | } 302 | else 303 | { 304 | std::vector triangles1 = Triangulator::GetTriangles2(aShape, AVector(-10, -10)); 305 | std::vector triangles2 = Triangulator::GetTriangles3(lineCombination2, aShape); 306 | std::vector triangles3 = Triangulator::GetTriangles4(lineCombination2, aShape); 307 | 308 | _triangleLines.insert( _triangleLines.end(), triangles1.begin(), triangles1.end() ); 309 | _addTriangleLines.insert( _addTriangleLines.end(), triangles3.begin(), triangles3.end() ); 310 | _backTriangleLines.insert( _backTriangleLines.end(), triangles2.begin(), triangles2.end() ); 311 | } 312 | } 313 | 314 | // debug 315 | //_tempLines.insert( _tempLines.end(), _triangleLines.begin(), _triangleLines.end() ); 316 | //_tempLines.insert( _tempLines.end(), _addTriangleLines.begin(), _addTriangleLines.end() ); 317 | //_tempLines.insert( _tempLines.end(), _backTriangleLines.begin(), _backTriangleLines.end() ); 318 | //PrepareLinesVAO1(_tempLines, &_tempLinesVbo, &_tempLinesVao, QVector3D(0, 1, 0)); 319 | 320 | BuildTrianglesVertexData(_triangleLines, &_trianglesVbo, &_trianglesVao, SystemParams::star_color); 321 | BuildTrianglesVertexData(_addTriangleLines, &_addTrianglesVbo, &_addTrianglesVao, SystemParams::star_color); 322 | BuildTrianglesVertexData(_backTriangleLines, &_backTrianglesVbo, &_backTrianglesVao, SystemParams::background_color); 323 | BuildQuadsVertexData(_uLines, &_uQuadsVbo, &_uQuadsVao, SystemParams::ribbon_color); 324 | BuildQuadsVertexData(_oLines, &_oQuadsVbo, &_oQuadsVao, SystemParams::ribbon_color); 325 | BuildLinesVertexData1(_uLines, &_uLinesVbo, &_uLinesVao, SystemParams::interlacing_color); 326 | BuildLinesVertexData1(_oLines, &_oLinesVbo, &_oLinesVao, SystemParams::interlacing_color); 327 | } 328 | 329 | void PatternGenerator::CalculateInterlace(std::pair segment, std::vector aShape, std::vector &uLines, std::vector &oLines) 330 | { 331 | ALine aLine1 = segment.first; 332 | ALine aLine2 = segment.second; 333 | AVector dir1 = aLine1.Direction().Norm(); 334 | AVector dir2 = aLine2.Direction().Norm(); 335 | 336 | float halfWidth = SystemParams::ribbon_width * 0.5f; 337 | float eps_val = std::numeric_limits::epsilon() * 1000; 338 | 339 | AVector cPt; 340 | AVector dPt; 341 | 342 | // parallel test 343 | float par_val = abs( dir1.Dot(dir2) / (dir1.Length() * dir2.Length()) ); 344 | if(par_val > 1.0f - eps_val) 345 | { 346 | dir1 = AVector(-dir1.y, dir1.x); 347 | dir2 = AVector(-dir2.y, dir2.x); 348 | 349 | AVector midDir = dir1; 350 | float hypotenuse1 = halfWidth; 351 | 352 | midDir *= hypotenuse1; 353 | 354 | AVector midPt = aLine1.GetPointB(); 355 | cPt = midPt - midDir; 356 | dPt = midPt + midDir; 357 | } 358 | else 359 | { 360 | AVector dir1 = aLine1.Direction().Norm(); 361 | AVector dir2 = aLine2.Direction().Norm(); 362 | AVector midDir = (dir1 + dir2) / 2.0f; 363 | 364 | float angle1 = AngleInBetween(dir1, dir2) / 2.0f; // half angle because intersection 365 | float angle2 = M_PI / 2.0f - angle1; // another angle 366 | float hypotenuse1 = halfWidth / cos(angle2); 367 | 368 | midDir = midDir.Norm(); 369 | midDir *= hypotenuse1; 370 | 371 | AVector midPt = aLine1.GetPointB(); 372 | 373 | float dir_angle = GetRotation(dir1, dir2); 374 | if(dir_angle < 0) 375 | { 376 | cPt = midPt + midDir; 377 | dPt = midPt - midDir; 378 | } 379 | else 380 | { 381 | cPt = midPt - midDir; 382 | dPt = midPt + midDir; 383 | } 384 | } 385 | 386 | // start 387 | float angleA = SystemParams::rad_angle; 388 | float angleB = M_PI / 2.0f - angleA; 389 | float hypotenuse2 = halfWidth / cos(angleB); 390 | AVector dirHA = aShape[aLine1._side].Direction().Norm(); 391 | AVector dirVA = AVector(dirHA.y, -dirHA.x); 392 | AVector aPt = aLine1.GetPointA() + dirVA * hypotenuse2; 393 | AVector bPt = aLine1.GetPointA() + dirHA * hypotenuse2; 394 | AVector bPtInv = aLine1.GetPointA() + dirHA.Inverse() * hypotenuse2; 395 | 396 | // end 397 | float angleX = M_PI - SystemParams::rad_angle; 398 | float angleY = M_PI / 2.0f - angleX; 399 | float hypotenuse3 = halfWidth / cos(angleY); 400 | AVector dirX = aShape[aLine2._side].Direction().Norm(); 401 | AVector dirVB = AVector(dirX.y, -dirX.x); 402 | AVector dirHB = AVector(-dirX.x, -dirX.y); 403 | AVector ePt = aLine2.GetPointA() + dirVB * hypotenuse3; 404 | AVector fPt = aLine2.GetPointA() + dirHB * hypotenuse3; 405 | AVector fPtInv = aLine2.GetPointA() + dirHB.Inverse() * hypotenuse3; 406 | 407 | // under 408 | //uLines.push_back(ALine(aPt, cPt)); // non interlace 409 | uLines.push_back(ALine(bPtInv, cPt)); // interlace 410 | uLines.push_back(ALine(bPt, dPt)); 411 | 412 | // over 413 | //oLines.push_back(ALine(cPt, ePt)); // non interlace 414 | oLines.push_back(ALine(cPt, fPtInv)); // interlace 415 | oLines.push_back(ALine(dPt, fPt)); 416 | } 417 | 418 | // signed 419 | float PatternGenerator::GetRotation(AVector pt1, AVector pt2) 420 | { 421 | float perpDot = pt1.x * pt2.y - pt1.y * pt2.x; 422 | return (float)atan2(perpDot, pt1.Dot(pt2)); 423 | } 424 | 425 | // unsigned 426 | float PatternGenerator::AngleInBetween(AVector vec1, AVector vec2) 427 | { 428 | //std::cout << vec1.Dot(vec2) << " " << vec1.Length() << " " << vec2.Length() << "\n"; 429 | return acos(vec1.Dot(vec2) / (vec1.Length() * vec2.Length())); 430 | } 431 | 432 | bool PatternGenerator::CheckHorizontalVerticalCase(ALine ray1, ALine ray2) 433 | { 434 | float eps_val = std::numeric_limits::epsilon() * 1000; 435 | AVector midPoint = ray1.GetPointA() + (ray2.GetPointA() - ray1.GetPointA()) * 0.5f; 436 | 437 | float u1 = (midPoint.x - ray1.GetPointA().x) / ray1.GetPointB().x; 438 | float u2 = (midPoint.y - ray1.GetPointA().y) / ray1.GetPointB().y; 439 | float v1 = (midPoint.x - ray2.GetPointA().x) / ray2.GetPointB().x; 440 | float v2 = (midPoint.y - ray2.GetPointA().y) / ray2.GetPointB().y; 441 | 442 | // vertical case 443 | if(abs(ray1.GetPointB().x) < eps_val && abs(ray2.GetPointB().x) < eps_val && 444 | ray1.GetPointB().y != 0 && ray2.GetPointB().y != 0 && 445 | u2 > 0 && v2 > 0 ) 446 | { 447 | return true; 448 | } 449 | // horizontal case 450 | else if(ray1.GetPointB().x != 0 && ray2.GetPointB().x != 0 && 451 | abs(ray1.GetPointB().y) < eps_val && abs(ray2.GetPointB().y) < eps_val && 452 | u1 > 0 && v1 > 0) 453 | { 454 | return true; 455 | } 456 | return false; 457 | } 458 | 459 | // to do: this function might be wrong 460 | bool PatternGenerator::CheckCollinearCase(ALine ray1, ALine ray2) 461 | { 462 | //std::cout << "CheckCollinearCase\n"; 463 | 464 | float eps_val = std::numeric_limits::epsilon() * 1000; 465 | 466 | AVector midPoint = ray1.GetPointA() + (ray2.GetPointA() - ray1.GetPointA()) * 0.5f; 467 | 468 | float u1 = (midPoint.x - ray1.GetPointA().x) / ray1.GetPointB().x; 469 | float u2 = (midPoint.y - ray1.GetPointA().y) / ray1.GetPointB().y; 470 | float v1 = (midPoint.x - ray2.GetPointA().x) / ray2.GetPointB().x; 471 | float v2 = (midPoint.y - ray2.GetPointA().y) / ray2.GetPointB().y; 472 | 473 | if(abs(u1 - u2) < eps_val && abs(v1 - v2) < eps_val && u1 > 0 && u2 > 0 && v1 > 0 && v2 > 0) 474 | { 475 | return true; 476 | } 477 | 478 | return false; 479 | } 480 | 481 | 482 | void PatternGenerator::GeneratePattern(std::string tilingName) 483 | { 484 | _tilingLines.clear(); 485 | _shapes.clear(); 486 | 487 | TilingData tilingData = GetTiling(tilingName); 488 | 489 | AVector trans1 = tilingData._translation1; 490 | AVector trans2 = tilingData._translation2; 491 | AVector centerPt(this->_img_width / 2, this->_img_height / 2); 492 | 493 | for(int a = 0; a < SystemParams::w; a++) 494 | { 495 | for(int b = 0; b < SystemParams::h; b++) 496 | { 497 | for(int c = 0; c < tilingData._tiles.size(); c++) 498 | { 499 | TileData tileData = tilingData._tiles[c]; 500 | 501 | float sides = tileData._sides; 502 | float radAngle = (M_PI / (float)sides); 503 | float radius = 1.0 / cos(radAngle); 504 | float angleOffset = tileData.GetRotation(); 505 | 506 | std::vector shape; 507 | if(tileData._shapeType == ShapeType::S_REGULAR) 508 | { 509 | shape = GenerateNGon(sides, radius, angleOffset, AVector(0, 0)); 510 | } 511 | else if(tileData._shapeType == ShapeType::S_POLYGON) 512 | { 513 | shape = std::vector(tileData._vertices); 514 | } 515 | 516 | for(int d = 0; d < tileData._transforms.size(); d++) 517 | { 518 | QMatrix3x3 mat = tileData._transforms[d]; 519 | std::vector tempShape(shape); 520 | MultiplyShape(mat, tempShape); 521 | 522 | AVector pos = centerPt + trans1 * a + trans2 * b; 523 | for(int i = 0; i < tempShape.size(); i++) 524 | { tempShape[i] += pos; } 525 | 526 | ConcatNGon(tempShape, _tilingLines); 527 | ConcatShapes(tempShape, _shapes); 528 | } 529 | } 530 | } 531 | } 532 | InferenceAlgorithm(_shapes); 533 | BuildLinesVertexData1(_tilingLines, &_tilingLinesVbo, &_tilingLinesVao, QVector3D(1.0, 0.0, 0.0)); 534 | } 535 | 536 | void PatternGenerator::InitTiling() 537 | { 538 | 539 | _tilings.clear(); 540 | 541 | ReadXML("../IslamicStarPatterns/archimedeans.xml"); 542 | ReadXML("../IslamicStarPatterns/hanbury.xml"); 543 | 544 | 545 | } 546 | 547 | void PatternGenerator::Paint(float zoomFactor) 548 | { 549 | _shaderProgram->setUniformValue(_use_color_location, (GLfloat)1.0); 550 | 551 | if(_tempLines.size() != 0) 552 | { 553 | glLineWidth(1.0f); 554 | _tempLinesVao.bind(); 555 | glDrawArrays(GL_LINES, 0, _tempLines.size() * 2); 556 | _tempLinesVao.release(); 557 | } 558 | 559 | if(_tempPointsVao.isCreated()) 560 | { 561 | glPointSize(10.0f); 562 | _tempPointsVao.bind(); 563 | glDrawArrays(GL_POINTS, 0, _tempPoints.size()); 564 | _tempPointsVao.release(); 565 | } 566 | 567 | if(_uLinesVao.isCreated()) 568 | { 569 | _shaderProgram->setUniformValue(_use_color_location, (GLfloat)1.0); 570 | _uLinesVao.bind(); 571 | glLineWidth(SystemParams::line_width * zoomFactor); 572 | glDrawArrays(GL_LINES, 0, _uLines.size() * 2); 573 | _uLinesVao.release(); 574 | } 575 | 576 | if(_uQuadsVao.isCreated()) 577 | { 578 | _shaderProgram->setUniformValue(_use_color_location, (GLfloat)1.0); 579 | _uQuadsVao.bind(); 580 | glDrawArrays(GL_QUADS, 0, _uLines.size() * 2); 581 | _uQuadsVao.release(); 582 | } 583 | 584 | if(_oLinesVao.isCreated()) 585 | { 586 | _shaderProgram->setUniformValue(_use_color_location, (GLfloat)1.0); 587 | _oLinesVao.bind(); 588 | glLineWidth(SystemParams::line_width * zoomFactor); 589 | glDrawArrays(GL_LINES, 0, _oLines.size() * 2); 590 | _oLinesVao.release(); 591 | } 592 | 593 | if(_oQuadsVao.isCreated()) 594 | { 595 | _shaderProgram->setUniformValue(_use_color_location, (GLfloat)1.0); 596 | _oQuadsVao.bind(); 597 | glDrawArrays(GL_QUADS, 0, _oLines.size() * 2); 598 | _oQuadsVao.release(); 599 | } 600 | 601 | 602 | 603 | if(_tilingLines.size() != 0 && SystemParams::show_tiling) 604 | { 605 | glLineWidth(1.0f); 606 | _tilingLinesVao.bind(); 607 | glDrawArrays(GL_LINES, 0, _tilingLines.size() * 2); 608 | _tilingLinesVao.release(); 609 | } 610 | 611 | if(_rayLines.size() != 0) 612 | { 613 | glLineWidth(3.0f); 614 | _rayLinesVao.bind(); 615 | glDrawArrays(GL_LINES, 0, _rayLines.size() * 2); 616 | _rayLinesVao.release(); 617 | } 618 | 619 | if(_addTrianglesVao.isCreated()) 620 | { 621 | _addTrianglesVao.bind(); 622 | glDrawArrays(GL_TRIANGLES, 0, _addTriangleLines.size()); 623 | _addTrianglesVao.release(); 624 | } 625 | 626 | if(_backTrianglesVao.isCreated()) 627 | { 628 | _backTrianglesVao.bind(); 629 | glDrawArrays(GL_TRIANGLES, 0, _backTriangleLines.size()); 630 | _backTrianglesVao.release(); 631 | } 632 | 633 | if(_trianglesVao.isCreated()) 634 | { 635 | _trianglesVao.bind(); 636 | glDrawArrays(GL_TRIANGLES, 0, _triangleLines.size()); 637 | _trianglesVao.release(); 638 | } 639 | 640 | } 641 | 642 | void PatternGenerator::ConcatNGon(std::vector sourcePolygon, std::vector &destinationLines) 643 | { 644 | for(uint a = 0; a < sourcePolygon.size(); a++) 645 | { 646 | destinationLines.push_back(ALine(sourcePolygon[a], 647 | sourcePolygon[(a + 1) % sourcePolygon.size()])); 648 | } 649 | } 650 | 651 | void PatternGenerator::ConcatShapes(std::vector sourcePolygon, std::vector> &shapes) 652 | { 653 | std::vector tempShape; 654 | for(uint a = 0; a < sourcePolygon.size(); a++) 655 | { 656 | tempShape.push_back(ALine(sourcePolygon[a], 657 | sourcePolygon[(a + 1) % sourcePolygon.size()])); 658 | } 659 | shapes.push_back(tempShape); 660 | 661 | } 662 | 663 | void PatternGenerator::MultiplyShape(QMatrix3x3 mat, std::vector& shape) 664 | { 665 | for(int a = 0; a < shape.size(); a++) 666 | { shape[a] = MultiplyVector(mat, shape[a]); } 667 | } 668 | 669 | AVector PatternGenerator::MultiplyVector(QMatrix3x3 mat, AVector vec) 670 | { 671 | float x = mat(0, 0) * vec.x + mat(0, 1) * vec.y + mat(0, 2) * 1.0; 672 | float y = mat(1, 0) * vec.x + mat(1, 1) * vec.y + mat(1, 2) * 1.0; 673 | //float z = mat(2, 0) * vec.x + mat(2, 1) * vec.y + mat(2, 2) * 1.0; 674 | return AVector(x, y); 675 | } 676 | 677 | std::vector PatternGenerator::GenerateNGon(float sides, float radius, float angleOffset, AVector centerPt) 678 | { 679 | std::vector shape; 680 | float addValue = M_PI * 2.0 / sides; 681 | float valLimit = M_PI * 2.0 + angleOffset; 682 | float epsilonLimit = std::numeric_limits::epsilon() * 1000; 683 | for(float a = angleOffset; (valLimit - a) > epsilonLimit; a += addValue) 684 | { 685 | float xPt = centerPt.x + radius * sin(a); 686 | float yPt = centerPt.y + radius * cos(a); 687 | shape.push_back(AVector(xPt, yPt)); 688 | } 689 | 690 | int intSides = (int)sides; 691 | if(intSides != shape.size()) 692 | { 693 | std::cout << "GenerateNGon error\n"; 694 | } 695 | 696 | return shape; 697 | } 698 | 699 | void PatternGenerator::BuildLinesVertexData2(std::vector lines, QOpenGLBuffer* linesVbo, QOpenGLVertexArrayObject* linesVao) 700 | { 701 | if(linesVao->isCreated()) { linesVao->destroy(); } 702 | 703 | linesVao->create(); 704 | linesVao->bind(); 705 | 706 | QVector data; 707 | //QVector3D vecCol; 708 | 709 | QVector3D vecCol1(1, 1, 0); 710 | QVector3D vecCol2(0, 0, 1); 711 | 712 | for(uint a = 0; a < lines.size(); a++) 713 | { 714 | if(a % 2 == 0) 715 | { 716 | //float r = (float)(rand() % 255) / 255.0; 717 | //float g = (float)(rand() % 255) / 255.0; 718 | //float b = (float)(rand() % 255) / 255.0; 719 | //vecCol = QVector3D(r, g, b); 720 | } 721 | //data.append(VertexData(QVector3D(lines[a].XA, lines[a].YA, 0), QVector2D(), vecCol)); 722 | //data.append(VertexData(QVector3D(lines[a].XB, lines[a].YB, 0), QVector2D(), vecCol)); 723 | 724 | data.append(VertexData(QVector3D(lines[a].XA, lines[a].YA, 0), QVector2D(), vecCol1)); 725 | data.append(VertexData(QVector3D(lines[a].XB, lines[a].YB, 0), QVector2D(), vecCol2)); 726 | } 727 | 728 | linesVbo->create(); 729 | linesVbo->bind(); 730 | linesVbo->allocate(data.data(), data.size() * sizeof(VertexData)); 731 | 732 | quintptr offset = 0; 733 | 734 | _shaderProgram->enableAttributeArray(_vertexLocation); 735 | _shaderProgram->setAttributeBuffer(_vertexLocation, GL_FLOAT, 0, 3, sizeof(VertexData)); 736 | 737 | offset += sizeof(QVector3D); 738 | offset += sizeof(QVector2D); 739 | 740 | _shaderProgram->enableAttributeArray(_colorLocation); 741 | _shaderProgram->setAttributeBuffer(_colorLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); 742 | 743 | linesVao->release(); 744 | } 745 | 746 | void PatternGenerator::BuildLinesVertexData0(std::vector lines, QOpenGLBuffer* linesVbo, QOpenGLVertexArrayObject* linesVao, QVector3D vecCol1, QVector3D vecCol2) 747 | { 748 | if(linesVao->isCreated()) { linesVao->destroy(); } 749 | 750 | linesVao->create(); 751 | linesVao->bind(); 752 | 753 | QVector data; 754 | QVector3D vecCol; 755 | for(uint a = 0; a < lines.size(); a++) 756 | { 757 | if(a % 2 == 0) 758 | { 759 | vecCol = vecCol1; 760 | } 761 | else 762 | { 763 | vecCol = vecCol2; 764 | } 765 | 766 | data.append(VertexData(QVector3D(lines[a].XA, lines[a].YA, 0), QVector2D(), vecCol)); 767 | data.append(VertexData(QVector3D(lines[a].XB, lines[a].YB, 0), QVector2D(), vecCol)); 768 | } 769 | 770 | linesVbo->create(); 771 | linesVbo->bind(); 772 | linesVbo->allocate(data.data(), data.size() * sizeof(VertexData)); 773 | 774 | quintptr offset = 0; 775 | 776 | _shaderProgram->enableAttributeArray(_vertexLocation); 777 | _shaderProgram->setAttributeBuffer(_vertexLocation, GL_FLOAT, 0, 3, sizeof(VertexData)); 778 | 779 | offset += sizeof(QVector3D); 780 | offset += sizeof(QVector2D); 781 | 782 | _shaderProgram->enableAttributeArray(_colorLocation); 783 | _shaderProgram->setAttributeBuffer(_colorLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); 784 | 785 | linesVao->release(); 786 | } 787 | 788 | 789 | void PatternGenerator::BuildLinesVertexData1(std::vector lines, QOpenGLBuffer* linesVbo, QOpenGLVertexArrayObject* linesVao, QVector3D vecCol) 790 | { 791 | if(linesVao->isCreated()) { linesVao->destroy(); } 792 | 793 | linesVao->create(); 794 | linesVao->bind(); 795 | 796 | QVector data; 797 | for(uint a = 0; a < lines.size(); a++) 798 | { 799 | data.append(VertexData(QVector3D(lines[a].XA, lines[a].YA, 0), QVector2D(), vecCol)); 800 | data.append(VertexData(QVector3D(lines[a].XB, lines[a].YB, 0), QVector2D(), vecCol)); 801 | } 802 | 803 | linesVbo->create(); 804 | linesVbo->bind(); 805 | linesVbo->allocate(data.data(), data.size() * sizeof(VertexData)); 806 | 807 | quintptr offset = 0; 808 | 809 | _shaderProgram->enableAttributeArray(_vertexLocation); 810 | _shaderProgram->setAttributeBuffer(_vertexLocation, GL_FLOAT, 0, 3, sizeof(VertexData)); 811 | 812 | offset += sizeof(QVector3D); 813 | offset += sizeof(QVector2D); 814 | 815 | _shaderProgram->enableAttributeArray(_colorLocation); 816 | _shaderProgram->setAttributeBuffer(_colorLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); 817 | 818 | linesVao->release(); 819 | } 820 | 821 | void PatternGenerator::BuildQuadsVertexData(std::vector lines, QOpenGLBuffer* vbo, QOpenGLVertexArrayObject* vao, QVector3D vecCol) 822 | { 823 | if(vao->isCreated()) { vao->destroy(); } 824 | 825 | vao->create(); 826 | vao->bind(); 827 | 828 | QVector data; 829 | for(uint a = 0; a < lines.size() - 1; a += 2) 830 | { 831 | data.append(VertexData(QVector3D(lines[a].XA, lines[a].YA, 0), QVector2D(), vecCol)); 832 | data.append(VertexData(QVector3D(lines[a].XB, lines[a].YB, 0), QVector2D(), vecCol)); 833 | 834 | data.append(VertexData(QVector3D(lines[a+1].XB, lines[a+1].YB, 0), QVector2D(), vecCol)); 835 | data.append(VertexData(QVector3D(lines[a+1].XA, lines[a+1].YA, 0), QVector2D(), vecCol)); 836 | 837 | } 838 | 839 | vbo->create(); 840 | vbo->bind(); 841 | vbo->allocate(data.data(), data.size() * sizeof(VertexData)); 842 | 843 | quintptr offset = 0; 844 | 845 | _shaderProgram->enableAttributeArray(_vertexLocation); 846 | _shaderProgram->setAttributeBuffer(_vertexLocation, GL_FLOAT, 0, 3, sizeof(VertexData)); 847 | 848 | offset += sizeof(QVector3D); 849 | offset += sizeof(QVector2D); 850 | 851 | _shaderProgram->enableAttributeArray(_colorLocation); 852 | _shaderProgram->setAttributeBuffer(_colorLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); 853 | 854 | vao->release(); 855 | } 856 | 857 | void PatternGenerator::BuildPointsVertexData(std::vector points, QOpenGLBuffer* ptsVbo, QOpenGLVertexArrayObject* ptsVao, QVector3D vecCol) 858 | { 859 | if(ptsVao->isCreated()) 860 | { 861 | ptsVao->destroy(); 862 | } 863 | 864 | ptsVao->create(); 865 | ptsVao->bind(); 866 | 867 | QVector data; 868 | for(size_t a = 0; a < points.size(); a++) 869 | { 870 | data.append(VertexData(QVector3D(points[a].x, points[a].y, 0), QVector2D(), vecCol)); 871 | } 872 | 873 | ptsVbo->create(); 874 | ptsVbo->bind(); 875 | ptsVbo->allocate(data.data(), data.size() * sizeof(VertexData)); 876 | 877 | quintptr offset = 0; 878 | 879 | int vertexLocation = _shaderProgram->attributeLocation("vert"); 880 | _shaderProgram->enableAttributeArray(vertexLocation); 881 | _shaderProgram->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, sizeof(VertexData)); 882 | 883 | offset += sizeof(QVector3D); 884 | offset += sizeof(QVector2D); 885 | 886 | _shaderProgram->enableAttributeArray(_colorLocation); 887 | _shaderProgram->setAttributeBuffer(_colorLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); 888 | 889 | ptsVao->release(); 890 | } 891 | 892 | void PatternGenerator::BuildTrianglesVertexData(std::vector lines, QOpenGLBuffer* vbo, QOpenGLVertexArrayObject* vao, QVector3D vecCol) 893 | { 894 | if(vao->isCreated()) { vao->destroy(); } 895 | 896 | vao->create(); 897 | vao->bind(); 898 | 899 | QVector data; 900 | for(uint a = 0; a < lines.size(); a += 3) 901 | { 902 | ALine line1 = lines[a]; 903 | ALine line2 = lines[a + 1]; 904 | ALine line3 = lines[a + 2]; 905 | 906 | /* 907 | triangles.push_back(ALine(v1, v2)); 908 | triangles.push_back(ALine(v2, v3)); 909 | triangles.push_back(ALine(v3, v1)); 910 | */ 911 | 912 | data.append(VertexData(QVector3D(line1.XA, line1.YA, 0), QVector2D(), vecCol)); 913 | data.append(VertexData(QVector3D(line1.XB, line1.YB, 0), QVector2D(), vecCol)); 914 | data.append(VertexData(QVector3D(line3.XA, line3.YA, 0), QVector2D(), vecCol)); 915 | 916 | //data.append(VertexData(QVector3D(lines[a].XA, lines[a].YA, 0), QVector2D(), vecCol)); 917 | //data.append(VertexData(QVector3D(lines[a].XB, lines[a].YB, 0), QVector2D(), vecCol)); 918 | //data.append(VertexData(QVector3D(lines[a+1].XB, lines[a+1].YB, 0), QVector2D(), vecCol)); 919 | //data.append(VertexData(QVector3D(lines[a+1].XA, lines[a+1].YA, 0), QVector2D(), vecCol)); 920 | 921 | } 922 | 923 | vbo->create(); 924 | vbo->bind(); 925 | vbo->allocate(data.data(), data.size() * sizeof(VertexData)); 926 | 927 | quintptr offset = 0; 928 | 929 | _shaderProgram->enableAttributeArray(_vertexLocation); 930 | _shaderProgram->setAttributeBuffer(_vertexLocation, GL_FLOAT, 0, 3, sizeof(VertexData)); 931 | 932 | offset += sizeof(QVector3D); 933 | offset += sizeof(QVector2D); 934 | 935 | _shaderProgram->enableAttributeArray(_colorLocation); 936 | _shaderProgram->setAttributeBuffer(_colorLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); 937 | 938 | vao->release(); 939 | } 940 | 941 | AVector PatternGenerator::GetPolygonCentroid(std::vector shapes) 942 | { 943 | AVector centroid(0, 0); 944 | float signedArea = 0.0f; 945 | //double x0 = 0.0; // Current vertex X 946 | //double y0 = 0.0; // Current vertex Y 947 | //double x1 = 0.0; // Next vertex X 948 | //double y1 = 0.0; // Next vertex Y 949 | //double a = 0.0; // Partial signed area 950 | 951 | // For all vertices except last 952 | //int i=0; 953 | for (int i = 0; i < shapes.size(); i++) 954 | { 955 | float x0 = shapes[i].GetPointA().x; 956 | float y0 = shapes[i].GetPointA().y; 957 | float x1 = shapes[i].GetPointB().x; 958 | float y1 = shapes[i].GetPointB().y; 959 | float a = x0 * y1 - x1 * y0; 960 | signedArea += a; 961 | centroid.x += (x0 + x1) * a; 962 | centroid.y += (y0 + y1) * a; 963 | } 964 | 965 | // Do last vertex 966 | //x0 = vertices[i].x; 967 | //y0 = vertices[i].y; 968 | //x1 = vertices[0].x; 969 | //y1 = vertices[0].y; 970 | //a = x0*y1 - x1*y0; 971 | //signedArea += a; 972 | //centroid.x += (x0 + x1)*a; 973 | //centroid.y += (y0 + y1)*a; 974 | 975 | signedArea *= 0.5; 976 | centroid.x /= (6.0f * signedArea); 977 | centroid.y /= (6.0f * signedArea); 978 | 979 | return centroid; 980 | } 981 | -------------------------------------------------------------------------------- /PatternGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef PATTERNGENERATOR_H 2 | #define PATTERNGENERATOR_H 3 | 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "ALine.h" 12 | #include "AVector.h" 13 | #include "TilingData.h" 14 | #include "RibbonSegment.h" 15 | 16 | class PatternGenerator 17 | { 18 | public: 19 | PatternGenerator(); 20 | ~PatternGenerator(); 21 | 22 | 23 | /* 24 | * Read xml files which contain tiling specifications 25 | */ 26 | void InitTiling(); 27 | 28 | /* 29 | * 1. generate an islamic ornamental tiling given a name of a tiling 30 | * 2. Call InferenceAlgorithm() 31 | * 3. Create vertex data 32 | */ 33 | void GeneratePattern(std::string tilingName); 34 | 35 | /* 36 | * Pain function, nothing special 37 | */ 38 | void Paint(float zoomFactor); 39 | 40 | 41 | /* 42 | * These functions are called by GLWidget to render an SVG file 43 | */ 44 | std::vector GetTilingLines() { return _tilingLines; } 45 | std::vector GetTriangleLines() { return _triangleLines; } 46 | std::vector GetBackTriangleLines() { return _backTriangleLines; } 47 | std::vector GetAddTriangleLines() { return _addTriangleLines; } 48 | std::vector GetULines() { return _uLines; } 49 | std::vector GetOLines() { return _oLines; } 50 | 51 | private: 52 | /* 53 | * Generate an N-Gon, this function has a numerical problem so I use epsilon 54 | */ 55 | std::vector GenerateNGon(float sides, float radius, float angleOffset, AVector centerPt); 56 | 57 | /* 58 | * Copy sourcePolygon to destinationLines 59 | */ 60 | void ConcatNGon(std::vector sourcePolygon, std::vector &destinationLines); 61 | 62 | /* 63 | * Copy sourcePolygon to shapes 64 | */ 65 | void ConcatShapes(std::vector sourcePolygon, std::vector> &shapes); 66 | 67 | /* 68 | * The greedy inference algorithm 69 | */ 70 | void InferenceAlgorithm(std::vector> shapes); 71 | 72 | /* 73 | * Affine transformation 74 | */ 75 | AVector MultiplyVector(QMatrix3x3 mat, AVector vec); 76 | 77 | /* 78 | * Affine transformation 79 | */ 80 | void MultiplyShape(QMatrix3x3 mat, std::vector& shape); 81 | 82 | /* 83 | * Unsigned angle in radian 84 | */ 85 | float AngleInBetween(AVector vec1, AVector vec2); 86 | 87 | /* 88 | * Read an XML file with TinyXML 89 | */ 90 | void ReadXML(std::string filename); 91 | 92 | /* 93 | * 94 | */ 95 | TilingData GetTiling(std::string tilingName); 96 | 97 | /* 98 | * Signed angle in radian 99 | */ 100 | float GetRotation(AVector pt1, AVector pt2); 101 | 102 | /* 103 | * Get a center of mass of a polygon 104 | */ 105 | AVector GetPolygonCentroid(std::vector shapes); 106 | 107 | /* 108 | * Do both rays are collinear ? 109 | */ 110 | bool CheckCollinearCase(ALine ray1, ALine ray2); 111 | 112 | /* 113 | * Do both rays create a 90 degree corner 114 | */ 115 | bool CheckHorizontalVerticalCase(ALine ray1, ALine ray2); 116 | 117 | /* 118 | * 119 | */ 120 | void CalculateInterlace(std::pair segment, std::vector aShape, std::vector &uLines, std::vector &oLines); 121 | 122 | void BuildPointsVertexData(std::vector points, QOpenGLBuffer* ptsVbo, QOpenGLVertexArrayObject* ptsVao, QVector3D vecCol); 123 | void BuildLinesVertexData0(std::vector lines, QOpenGLBuffer* linesVbo, QOpenGLVertexArrayObject* linesVao, QVector3D vecCol1, QVector3D vecCol2); 124 | void BuildLinesVertexData1(std::vector lines, QOpenGLBuffer* linesVbo, QOpenGLVertexArrayObject* linesVao, QVector3D vecCol); 125 | void BuildLinesVertexData2(std::vector lines, QOpenGLBuffer* linesVbo, QOpenGLVertexArrayObject* linesVao); 126 | void BuildQuadsVertexData(std::vector lines, QOpenGLBuffer* vbo, QOpenGLVertexArrayObject* vao, QVector3D vecCol); 127 | void BuildTrianglesVertexData(std::vector lines, QOpenGLBuffer* vbo, QOpenGLVertexArrayObject* vao, QVector3D vecCol); 128 | 129 | // to do: fix this 130 | public: 131 | QOpenGLShaderProgram* _shaderProgram; 132 | int _colorLocation; 133 | int _vertexLocation; 134 | int _use_color_location; 135 | int _img_width; 136 | int _img_height; 137 | 138 | // to do: delete me 139 | //float sideDiv; 140 | 141 | 142 | private: 143 | std::vector _rayLines; 144 | QOpenGLBuffer _rayLinesVbo; 145 | QOpenGLVertexArrayObject _rayLinesVao; 146 | 147 | // to do: delete this 148 | std::vector _tempLines; 149 | QOpenGLBuffer _tempLinesVbo; 150 | QOpenGLVertexArrayObject _tempLinesVao; 151 | 152 | // to do: delete this 153 | std::vector _tempPoints; 154 | QOpenGLBuffer _tempPointsVbo; 155 | QOpenGLVertexArrayObject _tempPointsVao; 156 | 157 | // triangles 158 | std::vector _triangleLines; 159 | QOpenGLBuffer _trianglesVbo; 160 | QOpenGLVertexArrayObject _trianglesVao; 161 | 162 | // triangles 163 | std::vector _backTriangleLines; 164 | QOpenGLBuffer _backTrianglesVbo; 165 | QOpenGLVertexArrayObject _backTrianglesVao; 166 | 167 | // triangles 168 | std::vector _addTriangleLines; 169 | QOpenGLBuffer _addTrianglesVbo; 170 | QOpenGLVertexArrayObject _addTrianglesVao; 171 | 172 | // under 173 | //std::vector _uSegments; 174 | std::vector _uLines; 175 | 176 | // over 177 | //std::vector _oSegments; 178 | std::vector _oLines; 179 | 180 | // lines under 181 | QOpenGLBuffer _uLinesVbo; 182 | QOpenGLVertexArrayObject _uLinesVao; 183 | 184 | // lines over 185 | QOpenGLBuffer _oLinesVbo; 186 | QOpenGLVertexArrayObject _oLinesVao; 187 | 188 | // quads under 189 | QOpenGLBuffer _uQuadsVbo; 190 | QOpenGLVertexArrayObject _uQuadsVao; 191 | 192 | // quads over 193 | QOpenGLBuffer _oQuadsVbo; 194 | QOpenGLVertexArrayObject _oQuadsVao; 195 | 196 | std::vector _tilingLines; 197 | QOpenGLBuffer _tilingLinesVbo; 198 | QOpenGLVertexArrayObject _tilingLinesVao; 199 | 200 | std::vector _tilings; 201 | 202 | std::vector> _shapes; 203 | }; 204 | 205 | #endif // PATTERNGENERATOR_H 206 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An implementation of Craig S. Kaplan's Polygons-in-Contact Algorithm to generate Islamic Star Patterns: 2 | (http://www.cgl.uwaterloo.ca/~csk/papers/kaplan_gi2005.pdf) 3 | 4 | 5 | ![alt tag](https://raw.githubusercontent.com/azer89/IslamicStarPatterns/master/IslamicStarPattern.png) 6 | -------------------------------------------------------------------------------- /RibbonSegment.h: -------------------------------------------------------------------------------- 1 | #ifndef RIBBONSEGMENT_H 2 | #define RIBBONSEGMENT_H 3 | 4 | #include "AVector.h" 5 | #include "ALine.h" 6 | 7 | #include 8 | 9 | struct RibbonSegment 10 | { 11 | public: 12 | //AVector _startMPt; 13 | //AVector _endMPt; 14 | 15 | //AVector _anchor1; 16 | //AVector _anchor2; 17 | 18 | AVector _startRPt; 19 | AVector _endRPt; 20 | 21 | AVector _startLPt; 22 | AVector _endLPt; 23 | 24 | //LayerType _layerType; 25 | //std::vector _cLines; 26 | 27 | //std::vector _rLines; 28 | //std::vector _lLines; 29 | 30 | ALine _rLine; 31 | ALine _lLine; 32 | }; 33 | 34 | #endif // RIBBONSEGMENT_H 35 | -------------------------------------------------------------------------------- /SystemParams.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SystemParams.h" 3 | 4 | #define _USE_MATH_DEFINES 5 | #include 6 | 7 | std::string SystemParams::default_tiling = "3.4.12 RD"; 8 | 9 | bool SystemParams::show_tiling = false; 10 | 11 | float SystemParams::rad_angle = M_PI / 4.0f; 12 | 13 | float SystemParams::ribbon_width = 0.02; 14 | 15 | float SystemParams::line_width = 0.006; 16 | 17 | float SystemParams::contact_delta = 0.0; 18 | 19 | int SystemParams::w = 1; 20 | int SystemParams::h = 1; 21 | 22 | QVector3D SystemParams::star_color = QVector3D(0, 0.75, 0.75); 23 | QVector3D SystemParams::ribbon_color = QVector3D(0, 0, 1); 24 | QVector3D SystemParams::background_color = QVector3D(1, 1, 1); 25 | QVector3D SystemParams::interlacing_color = QVector3D(1, 1, 0); 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /SystemParams.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSTEMPARAMS_H 2 | #define SYSTEMPARAMS_H 3 | 4 | #include 5 | #include 6 | 7 | class SystemParams 8 | { 9 | public: 10 | SystemParams(); 11 | ~SystemParams(); 12 | 13 | public: 14 | static std::string default_tiling; 15 | 16 | static bool show_tiling; 17 | static float rad_angle; 18 | 19 | static float ribbon_width; 20 | 21 | static float line_width; 22 | 23 | static float contact_delta; 24 | 25 | static int w; 26 | static int h; 27 | 28 | static QVector3D star_color; 29 | static QVector3D ribbon_color; 30 | static QVector3D background_color; 31 | static QVector3D interlacing_color; 32 | 33 | }; 34 | 35 | #endif // SYSTEMPARAMS_H 36 | -------------------------------------------------------------------------------- /TilingData.h: -------------------------------------------------------------------------------- 1 | #ifndef TILING_H 2 | #define TILING_H 3 | 4 | //#include 5 | //#include 6 | //#include 7 | 8 | enum ShapeType 9 | { 10 | S_REGULAR = 0, 11 | S_POLYGON = 1, 12 | }; 13 | 14 | struct TileData 15 | { 16 | public: 17 | ShapeType _shapeType; 18 | float _sides; 19 | std::vector _transforms; 20 | std::vector _vertices; 21 | 22 | 23 | float GetRotation() 24 | { 25 | if(this->_shapeType == ShapeType::S_POLYGON) 26 | { 27 | return 0; 28 | } 29 | else if(this->_sides == 3) 30 | { 31 | return M_PI / (this->_sides * 2.0f); 32 | } 33 | else if(this->_sides == 4) 34 | { 35 | return M_PI / this->_sides; 36 | } 37 | else if(this->_sides == 5) 38 | { 39 | // to do: why? 40 | return M_PI / (-2.0f) ; 41 | } 42 | else if(this->_sides == 6) 43 | { 44 | return 0; 45 | } 46 | else if(this->_sides == 8) 47 | { 48 | return M_PI / this->_sides; 49 | } 50 | else if(this->_sides == 9) 51 | { 52 | return M_PI / 6.0f; 53 | } 54 | else if(this->_sides == 12) 55 | { 56 | return M_PI / this->_sides; 57 | } 58 | else if(this->_sides == 16) 59 | { 60 | return M_PI / this->_sides; 61 | } 62 | 63 | 64 | return 0; 65 | } 66 | }; 67 | 68 | struct TilingData 69 | { 70 | public: 71 | std::string _name; 72 | AVector _translation1; 73 | AVector _translation2; 74 | std::vector _tiles; 75 | 76 | }; 77 | 78 | #endif // TILING_H 79 | -------------------------------------------------------------------------------- /Triangulator.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Triangulator.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "SystemParams.h" 12 | 13 | typedef CGAL::Exact_predicates_inexact_constructions_kernel K; 14 | typedef CGAL::Triangulation_vertex_base_2 Vb; 15 | typedef CGAL::Delaunay_mesh_face_base_2 Fb; 16 | typedef CGAL::Triangulation_data_structure_2 Tds; 17 | typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; 18 | typedef CGAL::Delaunay_mesh_size_criteria_2 Criteria; 19 | typedef CDT::Vertex_handle Vertex_handle; 20 | typedef CDT::Point Point; 21 | 22 | std::vector Triangulator::GetTriangles2(std::vector shape, AVector seedPt) 23 | { 24 | std::vector triangles; 25 | 26 | CDT cdt; 27 | std::list list_of_seeds; 28 | for(int a = 0; a < shape.size(); a++) 29 | { 30 | ALine line = shape[a]; 31 | Vertex_handle v1 = cdt.insert(Point(line.GetPointA().x, line.GetPointA().y)); 32 | Vertex_handle v2 = cdt.insert(Point(line.GetPointB().x, line.GetPointB().y)); 33 | cdt.insert_constraint(v1, v2); 34 | } 35 | list_of_seeds.push_back(Point(seedPt.x, seedPt.y)); 36 | 37 | CGAL::refine_Delaunay_mesh_2(cdt, list_of_seeds.begin(), list_of_seeds.end(), 38 | Criteria(0.125, 0)); 39 | 40 | for(CDT::Finite_faces_iterator fit = cdt.finite_faces_begin(); fit != cdt.finite_faces_end(); ++fit) 41 | { 42 | // to do: something wrong with is_in_domain 43 | if(fit->is_in_domain()) 44 | { 45 | AVector v1(fit->vertex(0)->point().x(), fit->vertex(0)->point().y()); 46 | AVector v2(fit->vertex(1)->point().x(), fit->vertex(1)->point().y()); 47 | AVector v3(fit->vertex(2)->point().x(), fit->vertex(2)->point().y()); 48 | 49 | triangles.push_back(ALine(v1, v2)); 50 | triangles.push_back(ALine(v2, v3)); 51 | triangles.push_back(ALine(v3, v1)); 52 | } 53 | } 54 | return triangles; 55 | } 56 | 57 | std::vector Triangulator::GetTriangles3(std::vector> shape, std::vector poly) 58 | { 59 | std::vector triangles; 60 | 61 | CDT cdt; 62 | std::list list_of_seeds; 63 | for(int a = 0; a < shape.size(); a++) 64 | { 65 | ALine line1 = shape[a].first; 66 | ALine line2 = shape[a].second; 67 | ALine line3 = poly[line1._side]; 68 | 69 | triangles.push_back(ALine(line1.GetPointA(), line1.GetPointB())); 70 | triangles.push_back(ALine(line1.GetPointB(), line3.GetPointB())); 71 | triangles.push_back(ALine(line3.GetPointB(), line1.GetPointA())); 72 | 73 | triangles.push_back(ALine(line1.GetPointB(), line2.GetPointA())); 74 | triangles.push_back(ALine(line2.GetPointA(), line3.GetPointB())); 75 | triangles.push_back(ALine(line3.GetPointB(), line1.GetPointB())); 76 | 77 | } 78 | 79 | return triangles; 80 | } 81 | 82 | std::vector Triangulator::GetTriangles1(std::vector > shape, AVector seedPt) 83 | { 84 | std::vector triangles; 85 | 86 | if(SystemParams::contact_delta != 0) 87 | { 88 | return triangles; 89 | } 90 | 91 | CDT cdt; 92 | std::list list_of_seeds; 93 | for(int a = 0; a < shape.size(); a++) 94 | { 95 | ALine line1 = shape[a].first; 96 | ALine line2 = shape[a].second; 97 | 98 | Vertex_handle v1 = cdt.insert(Point(line1.GetPointA().x, line1.GetPointA().y)); 99 | Vertex_handle v2 = cdt.insert(Point(line1.GetPointB().x, line1.GetPointB().y)); 100 | Vertex_handle v3 = cdt.insert(Point(line2.GetPointA().x, line2.GetPointA().y)); 101 | //Vertex_handle v4 = cdt.insert(Point(line2.GetPointB().x, line2.GetPointB().y)); 102 | 103 | // to do: check intersection 104 | cdt.insert_constraint(v1, v2); 105 | cdt.insert_constraint(v3, v2); 106 | 107 | //AVector midPt = line1.GetPointA() + (line2.GetPointA() - line1.GetPointA()) * 0.5f; 108 | //list_of_seeds.push_back(Point(midPt.x, midPt.y)); 109 | } 110 | 111 | // dealing with contact delta 112 | for(int a = 0; a < shape.size(); a++) 113 | { 114 | 115 | } 116 | 117 | list_of_seeds.push_back(Point(seedPt.x, seedPt.y)); 118 | //list_of_seeds.push_back(Point(0, 0)); 119 | CGAL::refine_Delaunay_mesh_2(cdt, list_of_seeds.begin(), list_of_seeds.end(), 120 | Criteria(0.125, 0)); 121 | 122 | for(CDT::Finite_faces_iterator fit = cdt.finite_faces_begin(); fit != cdt.finite_faces_end(); ++fit) 123 | { 124 | // to do: something wrong with is_in_domain 125 | if(fit->is_in_domain()) 126 | { 127 | AVector v1(fit->vertex(0)->point().x(), fit->vertex(0)->point().y()); 128 | AVector v2(fit->vertex(1)->point().x(), fit->vertex(1)->point().y()); 129 | AVector v3(fit->vertex(2)->point().x(), fit->vertex(2)->point().y()); 130 | 131 | triangles.push_back(ALine(v1, v2)); 132 | triangles.push_back(ALine(v2, v3)); 133 | triangles.push_back(ALine(v3, v1)); 134 | } 135 | } 136 | //std::cout << "Number of vertices: " << cdt.number_of_vertices() << std::endl; 137 | 138 | //std::cout << "Number of vertices: " << triangles.size() << std::endl; 139 | return triangles; 140 | } 141 | 142 | std::vector Triangulator::GetTriangles4(std::vector> shape, std::vector poly) 143 | { 144 | std::vector triangles; 145 | 146 | for(int a = 0; a < poly.size(); a++) 147 | { 148 | ALine rLine = SearchLine(shape, a, true); 149 | ALine lLine = SearchLine(shape, a, false); 150 | 151 | AVector intersection = GetIntersection(rLine, lLine); 152 | 153 | //std::cout << rLine._side << " " << rLine._isRight << "\n"; 154 | //std::cout << lLine._side << " " << lLine._isRight << "\n"; 155 | 156 | triangles.push_back(ALine(rLine.GetPointA(), intersection)); 157 | triangles.push_back(ALine(intersection, lLine.GetPointA())); 158 | triangles.push_back(ALine(lLine.GetPointA(), rLine.GetPointA())); 159 | } 160 | 161 | //std::cout << triangles.size() << "\n"; 162 | return triangles; 163 | } 164 | 165 | ALine Triangulator::SearchLine(std::vector> shape, int side, bool isRight) 166 | { 167 | ALine retLine; 168 | 169 | for(int a = 0; a < shape.size(); a++) 170 | { 171 | ALine line1 = shape[a].first; 172 | ALine line2 = shape[a].second; 173 | 174 | if(line1._side == side && line1._isRight == isRight) 175 | { 176 | //std::cout << "1\n"; 177 | return line1; 178 | } 179 | else if(line2._side == side && line2._isRight == isRight) 180 | { 181 | //std::cout << "2\n"; 182 | return line2; 183 | } 184 | } 185 | 186 | //std::cout << "shit\n"; 187 | return retLine; 188 | } 189 | 190 | AVector Triangulator::GetIntersection(ALine line1, ALine line2) 191 | { 192 | ALine rayA(line1.GetPointA(), line1.Direction().Norm()); 193 | ALine rayB(line2.GetPointA(), line2.Direction().Norm()); 194 | 195 | float dx = rayB.GetPointA().x - rayA.GetPointA().x; 196 | float dy = rayB.GetPointA().y - rayA.GetPointA().y; 197 | float det = rayB.GetPointB().x * rayA.GetPointB().y - rayB.GetPointB().y * rayA.GetPointB().x; 198 | float u = (dy * rayB.GetPointB().x - dx * rayB.GetPointB().y) / det; 199 | float v = (dy * rayA.GetPointB().x - dx * rayA.GetPointB().y) / det; 200 | 201 | return rayA.GetPointA() + rayA.GetPointB() * u; 202 | } 203 | 204 | -------------------------------------------------------------------------------- /Triangulator.h: -------------------------------------------------------------------------------- 1 | #ifndef TRIANGULATOR_H 2 | #define TRIANGULATOR_H 3 | 4 | #include "ALine.h" 5 | #include 6 | 7 | class Triangulator 8 | { 9 | public: 10 | Triangulator(); 11 | ~Triangulator(); 12 | 13 | 14 | static std::vector GetTriangles1(std::vector> shape, AVector seedPt); 15 | static std::vector GetTriangles2(std::vector shape, AVector seedPt); 16 | static std::vector GetTriangles3(std::vector> shape, std::vector poly); 17 | static std::vector GetTriangles4(std::vector> shape, std::vector poly); 18 | 19 | private: 20 | // to do: brute force 21 | static ALine SearchLine(std::vector> shape, int side, bool isRight); 22 | static AVector GetIntersection(ALine line1, ALine line2); 23 | 24 | }; 25 | 26 | #endif // TRIANGULATOR_H 27 | -------------------------------------------------------------------------------- /VertexData.h: -------------------------------------------------------------------------------- 1 | #ifndef VERTEXDATA_H 2 | #define VERTEXDATA_H 3 | 4 | #include 5 | #include 6 | 7 | // VertexData 8 | struct VertexData 9 | { 10 | QVector3D position; 11 | QVector2D texCoord; 12 | QVector3D color; 13 | 14 | public: 15 | 16 | VertexData(QVector3D position, QVector2D texCoord, QVector3D color) 17 | { 18 | this->position = position; 19 | this->texCoord = texCoord; 20 | this->color = color; 21 | } 22 | 23 | VertexData(QVector3D position, QVector2D texCoord) 24 | { 25 | this->position = position; 26 | this->texCoord = texCoord; 27 | this->color = QVector3D(); 28 | } 29 | 30 | VertexData() 31 | { 32 | this->position = QVector3D(); 33 | this->texCoord = QVector2D(); 34 | this->color = QVector3D(); 35 | } 36 | }; 37 | 38 | #endif // VERTEXDATA_H 39 | -------------------------------------------------------------------------------- /archimedeans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | 58 | 61 | 64 | 67 | 70 | 73 | 76 | 77 | 78 | 79 | 80 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 99 | 102 | 105 | 108 | 109 | 110 | 111 | 112 | 115 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 134 | 137 | 138 | 139 | 140 | 141 | 144 | 145 | 146 | 147 | 148 | 151 | 154 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 173 | 174 | 175 | 176 | 177 | 180 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 198 | 199 | 200 | 201 | 202 | 205 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 224 | 227 | 228 | 229 | 230 | 231 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 265 | 268 | 269 | 270 | 271 | 272 | 275 | 278 | 281 | 282 | 283 | 284 | 285 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 304 | 305 | 306 | 307 | 308 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 327 | 328 | 329 | 330 | 331 | 332 | -------------------------------------------------------------------------------- /hanbury.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 20 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 69 | 72 | 75 | 78 | 81 | 84 | 87 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 104 | 107 | 108 | 109 | 110 | 111 | 114 | 115 | 116 | 117 | 118 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 142 | 145 | 148 | 151 | 154 | 157 | 160 | 163 | 166 | 169 | 172 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 189 | 192 | 195 | 196 | 197 | 198 | 199 | 202 | 203 | 204 | 205 | 206 | 209 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 232 | 235 | 238 | 241 | 244 | 247 | 250 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 266 | 269 | 272 | 275 | 278 | 281 | 284 | 287 | 288 | 289 | 290 | 291 | 294 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 342 | 345 | 348 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 365 | 368 | 369 | 370 | 371 | 372 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 397 | 400 | 403 | 406 | 407 | 408 | 409 | 410 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 435 | 438 | 441 | 444 | 447 | 450 | 451 | 452 | 453 | 454 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 479 | 482 | 485 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 502 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 518 | 521 | 524 | 527 | 530 | 533 | 536 | 539 | 542 | 545 | 548 | 551 | 554 | 557 | 560 | 563 | 564 | 565 | 566 | 567 | 570 | 573 | 576 | 579 | 580 | 581 | 582 | 583 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 600 | 603 | 606 | 609 | 610 | 611 | 612 | 613 | 614 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | 9 | 10 | QApplication::setStyle(QStyleFactory::create("fusion")); 11 | QPalette p; 12 | p = qApp->palette(); 13 | p.setColor(QPalette::Button, QColor(200,200,200)); 14 | qApp->setPalette(p); 15 | 16 | 17 | /* 18 | qApp->setStyle(QStyleFactory::create("Fusion")); 19 | QPalette darkPalette; 20 | darkPalette.setColor(QPalette::Window, QColor(53,53,53)); 21 | darkPalette.setColor(QPalette::WindowText, Qt::white); 22 | darkPalette.setColor(QPalette::Base, QColor(25,25,25)); 23 | darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53)); 24 | darkPalette.setColor(QPalette::ToolTipBase, Qt::white); 25 | darkPalette.setColor(QPalette::ToolTipText, Qt::white); 26 | darkPalette.setColor(QPalette::Text, Qt::white); 27 | darkPalette.setColor(QPalette::Button, QColor(53,53,53)); 28 | darkPalette.setColor(QPalette::ButtonText, Qt::white); 29 | darkPalette.setColor(QPalette::BrightText, Qt::red); 30 | darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); 31 | 32 | darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); 33 | darkPalette.setColor(QPalette::HighlightedText, Qt::black); 34 | 35 | qApp->setPalette(darkPalette); 36 | 37 | qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 0px solid white; }"); 38 | */ 39 | 40 | MainWindow w; 41 | w.show(); 42 | 43 | return a.exec(); 44 | } 45 | -------------------------------------------------------------------------------- /mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "ui_mainwindow.h" 3 | 4 | #include "SystemParams.h" 5 | 6 | #include 7 | 8 | QColor ToQColor(QVector3D col) 9 | { 10 | return QColor(col.x() * 255.0f, col.y() * 255.0f, col.z() * 255.0f); 11 | } 12 | 13 | QColor InverseGrayScale(QColor col) 14 | { 15 | // 0.2989, 0.5870, 0.1140 16 | // 0.30 0.59 0.11 17 | float intensity = 0.3f * ((float)col.red()) + 0.59f * ((float)col.green()) + 0.11f * ((float)col.blue()); 18 | float invIntensity = 255.0 - intensity; 19 | 20 | if(invIntensity > 127.5) 21 | return QColor(255, 255, 255); 22 | 23 | return QColor(0, 0, 0); 24 | } 25 | 26 | MainWindow::MainWindow(QWidget *parent) : 27 | QMainWindow(parent), 28 | ui(new Ui::MainWindow) 29 | { 30 | ui->setupUi(this); 31 | 32 | connect(ui->actionSaveSVG, SIGNAL(triggered()), this, SLOT(SaveSVG())); 33 | connect(ui->treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int )), this, SLOT(ItemClicked(QTreeWidgetItem*, int))); 34 | connect(ui->angleSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ParamsChanged())); 35 | connect(ui->wSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ParamsChanged())); 36 | connect(ui->hSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ParamsChanged())); 37 | connect(ui->contactDeltaSpinBox, SIGNAL(valueChanged(double)), this, SLOT(ParamsChanged())); 38 | connect(ui->rWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(ParamsChanged())); 39 | connect(ui->lineWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(ParamsChanged())); 40 | connect(ui->tilingCheckBox, SIGNAL(stateChanged(int)), this, SLOT(ParamsChanged())); 41 | 42 | connect(ui->starColorButton, SIGNAL(clicked()), this, SLOT(StarColorChanged())); 43 | connect(ui->ribbonColorButton, SIGNAL(clicked()), this, SLOT(RibbonColorChanged())); 44 | connect(ui->backgroundColorButton, SIGNAL(clicked()), this, SLOT(BackgroundColorChanged())); 45 | connect(ui->interlacingColorButton, SIGNAL(clicked()), this, SLOT(InterlacingColorChanged())); 46 | 47 | 48 | QColor col1 = ToQColor(SystemParams::star_color); 49 | ui->starColorButton->setAutoFillBackground(true); 50 | QPalette palette1 = ui->starColorButton->palette(); 51 | palette1.setColor(ui->starColorButton->backgroundRole(), col1); 52 | //palette1.setColor(ui->starColorButton->foregroundRole(), QColor(255 - col1.red(), 255 - col1.green(), 255 - col1.blue())); 53 | palette1.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(col1)); 54 | ui->starColorButton->setPalette(palette1); 55 | 56 | QColor col2 = ToQColor(SystemParams::ribbon_color); 57 | ui->ribbonColorButton->setAutoFillBackground(true); 58 | QPalette palette2 = ui->ribbonColorButton->palette(); 59 | palette2.setColor(ui->ribbonColorButton->backgroundRole(), col2); 60 | //palette2.setColor(ui->ribbonColorButton->foregroundRole(), QColor(255 - col2.red(), 255 - col2.green(), 255 - col2.blue())); 61 | palette2.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(col2)); 62 | ui->ribbonColorButton->setPalette(palette2); 63 | 64 | QColor col3 = ToQColor(SystemParams::background_color); 65 | ui->backgroundColorButton->setAutoFillBackground(true); 66 | QPalette palette3 = ui->backgroundColorButton->palette(); 67 | palette3.setColor(ui->backgroundColorButton->backgroundRole(), col3); 68 | //palette3.setColor(ui->backgroundColorButton->foregroundRole(), QColor(255 - col3.red(), 255 - col3.green(), 255 - col3.blue())); 69 | palette3.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(col3)); 70 | ui->backgroundColorButton->setPalette(palette3); 71 | 72 | QColor col4 = ToQColor(SystemParams::interlacing_color); 73 | ui->interlacingColorButton->setAutoFillBackground(true); 74 | QPalette palette4 = ui->interlacingColorButton->palette(); 75 | palette4.setColor(ui->interlacingColorButton->backgroundRole(), col4); 76 | //palette4.setColor(ui->interlacingColorButton->foregroundRole(), QColor(255 - col4.red(), 255 - col4.green(), 255 - col4.blue())); 77 | palette1.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(col4)); 78 | ui->interlacingColorButton->setPalette(palette4); 79 | } 80 | 81 | MainWindow::~MainWindow() 82 | { 83 | delete ui; 84 | } 85 | 86 | void MainWindow::SaveSVG() 87 | { 88 | //std::cout << "save SVG\n"; 89 | ui->widget->GetGLWidget()->SaveToSvg(); 90 | } 91 | 92 | void MainWindow::StarColorChanged() 93 | { 94 | //std::cout << "StarColorChanged\n"; 95 | QColor col1 = ToQColor(SystemParams::star_color); 96 | QColor newColor = QColorDialog::getColor(col1, this); 97 | QPalette palette1 = ui->starColorButton->palette(); 98 | palette1.setColor(ui->starColorButton->backgroundRole(), newColor); 99 | //palette1.setColor(ui->starColorButton->foregroundRole(), QColor(255 - newColor.red(), 255 - newColor.green(), 255 - newColor.blue())); 100 | palette1.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(newColor)); 101 | ui->starColorButton->setPalette(palette1); 102 | 103 | //std::cout << newColor.redF() << " " << newColor.greenF() << " " << newColor.blueF() << "\n"; 104 | SystemParams::star_color = QVector3D(newColor.redF(), newColor.greenF(), newColor.blueF()); 105 | 106 | std::string tilingName; 107 | if(ui->treeWidget->selectedItems().size() > 0) 108 | { 109 | QTreeWidgetItem* item = ui->treeWidget->selectedItems()[0]; 110 | tilingName = item->text(0).toStdString(); 111 | } 112 | else 113 | { 114 | tilingName = SystemParams::default_tiling; 115 | } 116 | 117 | ui->widget->GetGLWidget()->GeneratePattern(tilingName); 118 | ui->widget->GetGLWidget()->repaint(); 119 | } 120 | 121 | void MainWindow::RibbonColorChanged() 122 | { 123 | //std::cout << "RibbonColorChanged\n"; 124 | QColor col2 = ToQColor(SystemParams::ribbon_color); 125 | QColor newColor = QColorDialog::getColor(col2, this); 126 | QPalette palette2 = ui->ribbonColorButton->palette(); 127 | palette2.setColor(ui->ribbonColorButton->backgroundRole(), newColor); 128 | //palette2.setColor(ui->ribbonColorButton->foregroundRole(), QColor(255 - newColor.red(), 255 - newColor.green(), 255 - newColor.blue())); 129 | palette2.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(newColor)); 130 | ui->ribbonColorButton->setPalette(palette2); 131 | 132 | SystemParams::ribbon_color = QVector3D(newColor.redF(), newColor.greenF(), newColor.blueF()); 133 | 134 | std::string tilingName; 135 | if(ui->treeWidget->selectedItems().size() > 0) 136 | { 137 | QTreeWidgetItem* item = ui->treeWidget->selectedItems()[0]; 138 | tilingName = item->text(0).toStdString(); 139 | } 140 | else 141 | { 142 | tilingName = SystemParams::default_tiling; 143 | } 144 | 145 | ui->widget->GetGLWidget()->GeneratePattern(tilingName); 146 | ui->widget->GetGLWidget()->repaint(); 147 | } 148 | 149 | void MainWindow::BackgroundColorChanged() 150 | { 151 | //std::cout << "BackgroundColorChanged\n"; 152 | QColor col3 = ToQColor(SystemParams::background_color); 153 | QColor newColor = QColorDialog::getColor(col3, this); 154 | QPalette palette3 = ui->backgroundColorButton->palette(); 155 | palette3.setColor(ui->backgroundColorButton->backgroundRole(), newColor); 156 | //palette3.setColor(ui->backgroundColorButton->foregroundRole(), QColor(255 - newColor.red(), 255 - newColor.green(), 255 - newColor.blue())); 157 | palette3.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(newColor)); 158 | ui->backgroundColorButton->setPalette(palette3); 159 | 160 | SystemParams::background_color = QVector3D(newColor.redF(), newColor.greenF(), newColor.blueF()); 161 | 162 | std::string tilingName; 163 | if(ui->treeWidget->selectedItems().size() > 0) 164 | { 165 | QTreeWidgetItem* item = ui->treeWidget->selectedItems()[0]; 166 | tilingName = item->text(0).toStdString(); 167 | } 168 | else 169 | { 170 | tilingName = SystemParams::default_tiling; 171 | } 172 | 173 | ui->widget->GetGLWidget()->GeneratePattern(tilingName); 174 | ui->widget->GetGLWidget()->repaint(); 175 | } 176 | 177 | void MainWindow::InterlacingColorChanged() 178 | { 179 | //std::cout << "InterlacingColorChanged\n"; 180 | QColor col4 = ToQColor(SystemParams::interlacing_color); 181 | QColor newColor = QColorDialog::getColor(col4, this); 182 | QPalette palette4 = ui->interlacingColorButton->palette(); 183 | palette4.setColor(ui->interlacingColorButton->backgroundRole(), newColor); 184 | //palette4.setColor(ui->interlacingColorButton->foregroundRole(), QColor(255 - newColor.red(), 255 - newColor.green(), 255 - newColor.blue())); 185 | palette4.setColor(ui->starColorButton->foregroundRole(), InverseGrayScale(newColor)); 186 | ui->interlacingColorButton->setPalette(palette4); 187 | 188 | SystemParams::interlacing_color = QVector3D(newColor.redF(), newColor.greenF(), newColor.blueF()); 189 | 190 | std::string tilingName; 191 | if(ui->treeWidget->selectedItems().size() > 0) 192 | { 193 | QTreeWidgetItem* item = ui->treeWidget->selectedItems()[0]; 194 | tilingName = item->text(0).toStdString(); 195 | } 196 | else 197 | { 198 | tilingName = SystemParams::default_tiling; 199 | } 200 | 201 | ui->widget->GetGLWidget()->GeneratePattern(tilingName); 202 | ui->widget->GetGLWidget()->repaint(); 203 | } 204 | 205 | void MainWindow::ParamsChanged() 206 | { 207 | float degAngle = ui->angleSpinBox->value(); 208 | float radAngle = degAngle * M_PI / 180.0; 209 | SystemParams::rad_angle = radAngle; 210 | SystemParams::ribbon_width = ui->rWidthSpinBox->value(); 211 | SystemParams::line_width = ui->lineWidthSpinBox->value(); 212 | SystemParams::w = ui->wSpinBox->value(); 213 | SystemParams::h = ui->hSpinBox->value(); 214 | SystemParams::show_tiling = ui->tilingCheckBox->isChecked(); 215 | SystemParams::contact_delta = ui->contactDeltaSpinBox->value(); 216 | 217 | std::string tilingName; 218 | if(ui->treeWidget->selectedItems().size() > 0) 219 | { 220 | QTreeWidgetItem* item = ui->treeWidget->selectedItems()[0]; 221 | tilingName = item->text(0).toStdString(); 222 | } 223 | else 224 | { 225 | tilingName = SystemParams::default_tiling; 226 | } 227 | 228 | ui->widget->GetGLWidget()->GeneratePattern(tilingName); 229 | ui->widget->GetGLWidget()->repaint(); 230 | } 231 | 232 | void MainWindow::ItemClicked(QTreeWidgetItem* item, int column) 233 | { 234 | if(item) 235 | { 236 | std::string tilingName = item->text(column).toStdString(); 237 | 238 | if(item->childCount() == 0) 239 | { 240 | ui->widget->GetGLWidget()->GeneratePattern(tilingName); 241 | ui->widget->GetGLWidget()->repaint(); 242 | //std::cout << item->text(column).toStdString() << "\n"; 243 | } 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | namespace Ui { 8 | class MainWindow; 9 | } 10 | 11 | class MainWindow : public QMainWindow 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit MainWindow(QWidget *parent = 0); 17 | ~MainWindow(); 18 | 19 | private: 20 | Ui::MainWindow *ui; 21 | 22 | private slots: 23 | void ItemClicked(QTreeWidgetItem * item, int column); 24 | void ParamsChanged(); 25 | void StarColorChanged(); 26 | void RibbonColorChanged(); 27 | void BackgroundColorChanged(); 28 | void InterlacingColorChanged(); 29 | void SaveSVG(); 30 | }; 31 | 32 | #endif // MAINWINDOW_H 33 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 1400 10 | 764 11 | 12 | 13 | 14 | Islamic Star Patterns 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 1400 29 | 22 30 | 31 | 32 | 33 | 34 | File 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 225 44 | 552 45 | 46 | 47 | 48 | 49 | 225 50 | 524287 51 | 52 | 53 | 54 | Qt::AllDockWidgetAreas 55 | 56 | 57 | 1 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 40 66 | 16777215 67 | 68 | 69 | 70 | Height 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 40 79 | 16777215 80 | 81 | 82 | 83 | Width 84 | 85 | 86 | 87 | 88 | 89 | 90 | Show Tiling 91 | 92 | 93 | false 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Tilings 102 | 103 | 104 | 105 | 106 | Archimedeans 107 | 108 | 109 | ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled 110 | 111 | 112 | 113 | 3.3.3.3.3.3 114 | 115 | 116 | 117 | 118 | 3.3.3.3.6 119 | 120 | 121 | 122 | 123 | 3.3.4.3.4 124 | 125 | 126 | 127 | 128 | 3.4.6.4 129 | 130 | 131 | 132 | 133 | 3.3.3.4.4 134 | 135 | 136 | 137 | 138 | 3.6.3.6 139 | 140 | 141 | 142 | 143 | 3.12.12 144 | 145 | 146 | 147 | 148 | 4.4.4.4 149 | 150 | 151 | 152 | 153 | 4.6.12 154 | 155 | 156 | 157 | 158 | 4.8.8 159 | 160 | 161 | 162 | 163 | 6.6.6 164 | 165 | 166 | 167 | 168 | 169 | Hanbury Tilings 170 | 171 | 172 | ItemIsDragEnabled|ItemIsUserCheckable|ItemIsEnabled 173 | 174 | 175 | 176 | 10 RD 177 | 178 | 179 | 180 | 181 | 8.12 RD 182 | 183 | 184 | 185 | 186 | 9.12 RD 187 | 188 | 189 | 190 | 191 | 3.4.12 RD 192 | 193 | 194 | 195 | 196 | 8 RD 197 | 198 | 199 | 200 | 201 | 4.8.8 RD 202 | 203 | 204 | 205 | 206 | 3.12.12 RD 207 | 208 | 209 | 210 | 211 | alhambra RD 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 80 222 | 16777215 223 | 224 | 225 | 226 | 1 227 | 228 | 229 | 100 230 | 231 | 232 | 1 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 80 241 | 16777215 242 | 243 | 244 | 245 | 1 246 | 247 | 248 | 100 249 | 250 | 251 | 1 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 80 260 | 16777215 261 | 262 | 263 | 264 | 90 265 | 266 | 267 | 1 268 | 269 | 270 | 45 271 | 272 | 273 | 274 | 275 | 276 | 277 | Contact Delta 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 80 286 | 16777215 287 | 288 | 289 | 290 | -1.000000000000000 291 | 292 | 293 | 1.000000000000000 294 | 295 | 296 | 0.010000000000000 297 | 298 | 299 | 300 | 301 | 302 | 303 | Ribbon Width 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 80 312 | 16777215 313 | 314 | 315 | 316 | 1.000000000000000 317 | 318 | 319 | 0.010000000000000 320 | 321 | 322 | 0.020000000000000 323 | 324 | 325 | 326 | 327 | 328 | 329 | Contact Angle 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 75 338 | true 339 | 340 | 341 | 342 | Star Color 343 | 344 | 345 | true 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 75 354 | true 355 | false 356 | 357 | 358 | 359 | Ribbon Color 360 | 361 | 362 | true 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 75 371 | true 372 | 373 | 374 | 375 | Line Color 376 | 377 | 378 | true 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 75 387 | true 388 | false 389 | 390 | 391 | 392 | Background Color 393 | 394 | 395 | true 396 | 397 | 398 | 399 | 400 | 401 | 402 | Line Width 403 | 404 | 405 | 406 | 407 | 408 | 409 | 4 410 | 411 | 412 | 2.000000000000000 413 | 414 | 415 | 0.001000000000000 416 | 417 | 418 | 0.006000000000000 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | Save SVG 428 | 429 | 430 | 431 | 432 | 433 | 434 | GLContainer 435 | QWidget 436 |
GLContainer.h
437 | 1 438 |
439 |
440 | 441 | 442 |
443 | -------------------------------------------------------------------------------- /shader.frag: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | in vec2 varying_uv; 4 | in vec3 varying_color; 5 | 6 | uniform float use_color; 7 | uniform sampler2D base_texture; 8 | 9 | out vec4 finalColor; 10 | 11 | void main() 12 | { 13 | finalColor = texture2D(base_texture, varying_uv); 14 | //finalColor.a = 0.5; 15 | if(use_color > 0.5) 16 | { 17 | finalColor = vec4(varying_color, 1.0); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /shader.vert: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | in vec3 vert; 4 | in vec2 uv; 5 | in vec3 vertexColor; 6 | out vec2 varying_uv; 7 | out vec3 varying_color; 8 | uniform mat4 mvpMatrix; 9 | 10 | void main() 11 | { 12 | gl_Position = mvpMatrix * vec4(vert, 1.0); 13 | varying_uv = uv; 14 | varying_color = vertexColor; 15 | } 16 | --------------------------------------------------------------------------------