void tft_t::rectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t c) { if (!h || !w) return; uint16_t yt, bMask; if (!transform()) goto disp; if (!portrait()) { swap(x, y); swap(w, h); } yt = vsTransformBack(y); if ((int16_t)yt < (int16_t)topEdge() && \ (int16_t)(yt + h) >= (int16_t)topEdge()) { // Top edge clipping h -= topEdge() - yt; y = upperEdge(); yt = vsTransformBack(y); } else if (yt < bottomEdge() && yt + h >= bottomEdge()) // Bottom edge clipping h = bottomEdge() - yt; if (y + h > bottomEdge()) // Transform edge split if (y < bottomEdge()) { if (!portrait()) { rectangle(y, x, bottomEdge() - y, w, c); rectangle(topEdge(), x, h - (bottomEdge() - y), w, c); } else { rectangle(x, y, w, bottomEdge() - y, c); rectangle(x, topEdge(), w, h - (bottomEdge() - y), c); } return; } if (yt < topMask()) { if (yt + h < topMask()) return; h -= topMask() - yt; y = vsTransform(topMask()); } bMask = vsMaximum() - bottomMask(); if (yt >= bMask) return; if (yt + h > bMask) h -= yt + h - bMask; if (!portrait()) { area(y, x, h, w); goto draw; } disp: area(x, y, w, h); draw: start(); while (h--) for (uint16_t xx = 0; xx < w; xx++) write16(c); }
uint16_t tft_t::vsTransform(uint16_t y) const { #ifndef NO_CHECK if ((int16_t)y < 0) return y; #endif if (y < topEdge() || y >= bottomEdge()) return y; y -= topEdge(); // Relative to upperEdge y += upperEdge(); // Relative to 0 if (y >= bottomEdge()) // Transform edge y -= vsHeight(); return y; }
uint16_t tft_t::vsTransformBack(uint16_t y) const { #ifndef NO_CHECK if ((int16_t)y < 0) return y; #endif if (y < topEdge() || y >= bottomEdge()) return y; if (y < upperEdge()) y += vsHeight(); y -= upperEdge(); // Relative to upperEdge y += topEdge(); // Relative to 0 return y; }
Size Transformation::getCropSize(vector<Point2f> areaCorners, Size targetSize) { // Figure out the approximate width/height of the license plate region, so we can maintain the aspect ratio. LineSegment leftEdge(round(areaCorners[3].x), round(areaCorners[3].y), round(areaCorners[0].x), round(areaCorners[0].y)); LineSegment rightEdge(round(areaCorners[2].x), round(areaCorners[2].y), round(areaCorners[1].x), round(areaCorners[1].y)); LineSegment topEdge(round(areaCorners[0].x), round(areaCorners[0].y), round(areaCorners[1].x), round(areaCorners[1].y)); LineSegment bottomEdge(round(areaCorners[3].x), round(areaCorners[3].y), round(areaCorners[2].x), round(areaCorners[2].y)); float w = distanceBetweenPoints(leftEdge.midpoint(), rightEdge.midpoint()); float h = distanceBetweenPoints(bottomEdge.midpoint(), topEdge.midpoint()); float aspect = w/h; int width = targetSize.width; int height = round(((float) width) / aspect); if (height > targetSize.height) { height = targetSize.height; width = round(((float) height) * aspect); } return Size(width, height); }
ViewerGL::Implementation::WipePolygonEnum ViewerGL::Implementation::getWipePolygon(const RectD & texRectClipped, QPolygonF & polygonPoints, bool rightPlane) const { ///Compute a second point on the plane separator line ///we don't really care how far it is from the center point, it just has to be on the line QPointF firstPoint, secondPoint; QPointF center; double angle; { QMutexLocker l(&wipeControlsMutex); center = wipeCenter; angle = wipeAngle; } ///extrapolate the line to the maximum size of the RoD so we're sure the line ///intersection algorithm works double maxSize = std::max(texRectClipped.x2 - texRectClipped.x1, texRectClipped.y2 - texRectClipped.y1) * 10000.; double xmax, ymax; xmax = std::cos(angle + M_PI_2) * maxSize; ymax = std::sin(angle + M_PI_2) * maxSize; firstPoint.setX(center.x() - xmax); firstPoint.setY(center.y() - ymax); secondPoint.setX(center.x() + xmax); secondPoint.setY(center.y() + ymax); QLineF inter(firstPoint, secondPoint); QLineF::IntersectType intersectionTypes[4]; QPointF intersections[4]; QLineF topEdge(texRectClipped.x1, texRectClipped.y2, texRectClipped.x2, texRectClipped.y2); QLineF rightEdge(texRectClipped.x2, texRectClipped.y2, texRectClipped.x2, texRectClipped.y1); QLineF bottomEdge(texRectClipped.x2, texRectClipped.y1, texRectClipped.x1, texRectClipped.y1); QLineF leftEdge(texRectClipped.x1, texRectClipped.y1, texRectClipped.x1, texRectClipped.y2); bool crossingTop = false, crossingRight = false, crossingLeft = false, crossingBtm = false; int validIntersectionsIndex[4]; validIntersectionsIndex[0] = validIntersectionsIndex[1] = -1; int numIntersec = 0; intersectionTypes[0] = inter.intersect(topEdge, &intersections[0]); if (intersectionTypes[0] == QLineF::BoundedIntersection) { validIntersectionsIndex[numIntersec] = 0; crossingTop = true; ++numIntersec; } intersectionTypes[1] = inter.intersect(rightEdge, &intersections[1]); if (intersectionTypes[1] == QLineF::BoundedIntersection) { validIntersectionsIndex[numIntersec] = 1; crossingRight = true; ++numIntersec; } intersectionTypes[2] = inter.intersect(bottomEdge, &intersections[2]); if (intersectionTypes[2] == QLineF::BoundedIntersection) { validIntersectionsIndex[numIntersec] = 2; crossingBtm = true; ++numIntersec; } intersectionTypes[3] = inter.intersect(leftEdge, &intersections[3]); if (intersectionTypes[3] == QLineF::BoundedIntersection) { validIntersectionsIndex[numIntersec] = 3; crossingLeft = true; ++numIntersec; } if ( (numIntersec != 0) && (numIntersec != 2) ) { ///Don't bother drawing the polygon, it is most certainly not visible in this case return ViewerGL::Implementation::eWipePolygonEmpty; } ///determine the orientation of the planes double crossProd = ( secondPoint.x() - center.x() ) * ( texRectClipped.y1 - center.y() ) - ( secondPoint.y() - center.y() ) * ( texRectClipped.x1 - center.x() ); if (numIntersec == 0) { ///the bottom left corner is on the left plane if ( (crossProd > 0) && ( (center.x() >= texRectClipped.x2) || (center.y() >= texRectClipped.y2) ) ) { ///the plane is invisible because the wipe handle is below or on the left of the texRectClipped return rightPlane ? ViewerGL::Implementation::eWipePolygonEmpty : ViewerGL::Implementation::eWipePolygonFull; } ///otherwise we draw the entire texture as usual return rightPlane ? ViewerGL::Implementation::eWipePolygonFull : ViewerGL::Implementation::eWipePolygonEmpty; } else { ///we have 2 intersects assert(validIntersectionsIndex[0] != -1 && validIntersectionsIndex[1] != -1); bool isBottomLeftOnLeftPlane = crossProd > 0; ///there are 6 cases if (crossingBtm && crossingLeft) { if ( (isBottomLeftOnLeftPlane && rightPlane) || (!isBottomLeftOnLeftPlane && !rightPlane) ) { //btm intersect is the first polygonPoints.insert(0, intersections[validIntersectionsIndex[0]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[1]]); polygonPoints.insert( 2, QPointF(texRectClipped.x1, texRectClipped.y2) ); polygonPoints.insert( 3, QPointF(texRectClipped.x2, texRectClipped.y2) ); polygonPoints.insert( 4, QPointF(texRectClipped.x2, texRectClipped.y1) ); polygonPoints.insert(5, intersections[validIntersectionsIndex[0]]); } else { polygonPoints.insert(0, intersections[validIntersectionsIndex[0]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[1]]); polygonPoints.insert( 2, QPointF(texRectClipped.x1, texRectClipped.y1) ); polygonPoints.insert(3, intersections[validIntersectionsIndex[0]]); } } else if (crossingBtm && crossingTop) { if ( (isBottomLeftOnLeftPlane && rightPlane) || (!isBottomLeftOnLeftPlane && !rightPlane) ) { ///btm intersect is the second polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 2, QPointF(texRectClipped.x2, texRectClipped.y2) ); polygonPoints.insert( 3, QPointF(texRectClipped.x2, texRectClipped.y1) ); polygonPoints.insert(4, intersections[validIntersectionsIndex[1]]); } else { polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 2, QPointF(texRectClipped.x1, texRectClipped.y2) ); polygonPoints.insert( 3, QPointF(texRectClipped.x1, texRectClipped.y1) ); polygonPoints.insert(4, intersections[validIntersectionsIndex[1]]); } } else if (crossingBtm && crossingRight) { if ( (isBottomLeftOnLeftPlane && rightPlane) || (!isBottomLeftOnLeftPlane && !rightPlane) ) { ///btm intersect is the second polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 2, QPointF(texRectClipped.x2, texRectClipped.y1) ); polygonPoints.insert(3, intersections[validIntersectionsIndex[1]]); } else { polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 2, QPointF(texRectClipped.x2, texRectClipped.y2) ); polygonPoints.insert( 3, QPointF(texRectClipped.x1, texRectClipped.y2) ); polygonPoints.insert( 4, QPointF(texRectClipped.x1, texRectClipped.y1) ); polygonPoints.insert(5, intersections[validIntersectionsIndex[1]]); } } else if (crossingLeft && crossingTop) { if ( (isBottomLeftOnLeftPlane && rightPlane) || (!isBottomLeftOnLeftPlane && !rightPlane) ) { ///left intersect is the second polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 2, QPointF(texRectClipped.x1, texRectClipped.y2) ); polygonPoints.insert(3, intersections[validIntersectionsIndex[1]]); } else { polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 2, QPointF(texRectClipped.x2, texRectClipped.y2) ); polygonPoints.insert( 3, QPointF(texRectClipped.x2, texRectClipped.y1) ); polygonPoints.insert( 4, QPointF(texRectClipped.x1, texRectClipped.y1) ); polygonPoints.insert(5, intersections[validIntersectionsIndex[1]]); } } else if (crossingLeft && crossingRight) { if ( (isBottomLeftOnLeftPlane && rightPlane) || (!isBottomLeftOnLeftPlane && !rightPlane) ) { ///left intersect is the second polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert( 1, QPointF(texRectClipped.x1, texRectClipped.y2) ); polygonPoints.insert( 2, QPointF(texRectClipped.x2, texRectClipped.y2) ); polygonPoints.insert(3, intersections[validIntersectionsIndex[0]]); polygonPoints.insert(4, intersections[validIntersectionsIndex[1]]); } else { polygonPoints.insert(0, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 2, QPointF(texRectClipped.x2, texRectClipped.y1) ); polygonPoints.insert( 3, QPointF(texRectClipped.x1, texRectClipped.y1) ); polygonPoints.insert(4, intersections[validIntersectionsIndex[1]]); } } else if (crossingTop && crossingRight) { if ( (isBottomLeftOnLeftPlane && rightPlane) || (!isBottomLeftOnLeftPlane && !rightPlane) ) { ///right is second polygonPoints.insert(0, intersections[validIntersectionsIndex[0]]); polygonPoints.insert( 1, QPointF(texRectClipped.x2, texRectClipped.y2) ); polygonPoints.insert(2, intersections[validIntersectionsIndex[1]]); polygonPoints.insert(3, intersections[validIntersectionsIndex[0]]); } else { polygonPoints.insert(0, intersections[validIntersectionsIndex[0]]); polygonPoints.insert(1, intersections[validIntersectionsIndex[1]]); polygonPoints.insert( 2, QPointF(texRectClipped.x2, texRectClipped.y1) ); polygonPoints.insert( 3, QPointF(texRectClipped.x1, texRectClipped.y1) ); polygonPoints.insert( 4, QPointF(texRectClipped.x1, texRectClipped.y2) ); polygonPoints.insert(5, intersections[validIntersectionsIndex[0]]); } } else { assert(false); } } return ViewerGL::Implementation::eWipePolygonPartial; } // getWipePolygon
void tft_t::putch(char ch) { #ifndef NO_CHECK if ((int16_t)x() >= (int16_t)width() || (int16_t)y() >= (int16_t)height()) return; #endif if ((int16_t)(x() + FONT_WIDTH * zoom()) < 0) return; uint8_t h = FONT_HEIGHT * zoom(), w = FONT_WIDTH * zoom(); // Display coordinate, start coordinate uint16_t xx = x(), x0 = x(); uint16_t yy = y(), y0 = y(); uint8_t xStart = 0, xStop = w; uint8_t yStart = 0, yStop = h; #if 1 if (transform()) { if (!portrait()) { yy = xx; y0 = x0; yStop = xStop; swap(w, h); } uint16_t yt = vsTransformBack(yy); if ((int16_t)yt < (int16_t)topEdge() && \ (int16_t)(yt + h) >= (int16_t)topEdge()) { // Top edge clipping yStart = topEdge() - yt; yy = upperEdge(); y0 = yy - yStart; yt = vsTransformBack(yy); } else if (yt < bottomEdge() && yt + h >= bottomEdge()) // Bottom edge clipping yStop = bottomEdge() - yt; if (yt < topMask()) { if (yt + yStop - yStart < topMask()) return; yy = vsTransform(topMask()); yStart += topMask() - yt; y0 = yy - yStart; } uint16_t bMask = vsMaximum() - bottomMask(); if (yt >= bMask) return; if (yt + yStop - yStart > bMask) yStop -= yt + yStop - yStart - bMask; if (!portrait()) { swap(w, h); xx = yy; x0 = y0; xStart = yStart; xStop = yStop; yy = y(); y0 = y(); yStart = 0; yStop = h; } } #else if (transform()) { uint16_t xt = vsTransformBack(xx); if ((int16_t)xt < (int16_t)topEdge() && \ (int16_t)(xt + w) >= (int16_t)topEdge()) { // Top edge clipping xStart = topEdge() - xt; xx = upperEdge(); x0 = xx - xStart; xt = vsTransformBack(xx); } else if (xt < bottomEdge() && xt + w >= bottomEdge()) // Bottom edge clipping xStop = bottomEdge() - xt; if (xt < topMask()) { if (xt + xStop - xStart < topMask()) return; xx = vsTransform(topMask()); xStart += topMask() - xt; x0 = xx - xStart; } uint16_t bMask = vsMaximum() - bottomMask(); if (xt >= bMask) return; if (xt + xStop - xStart > bMask) xStop -= xt + xStop - xStart - bMask; } #endif bool xTransform = transform() && !portrait() && x0 < bottomEdge() && x0 + xStop - xStart > bottomEdge(); bool yTransform = transform() && portrait() && y0 < bottomEdge() && y0 + yStop - yStart > bottomEdge(); uint8_t xEnd = xTransform ? bottomEdge() - xx : xStop; draw: area(xx, yy, xEnd - xStart, h); start(); for (uint8_t i = yStart; i < yStop; i++) { if (yTransform && y0 + i == bottomEdge()) { area(x(), topEdge(), w, h); start(); yTransform = false; } unsigned char c; c = pgm_read_byte(&(ascii[ch - ' '][i / zoom()])) << (xStart / zoom()); for (uint8_t j = xStart; j < xEnd; j++) { if (c & 0x80) write16(foreground()); else write16(background()); if (j % zoom() == zoom() - 1) c <<= 1; } } if (xTransform) { xx = topEdge(); xStart = xEnd; xEnd = xStop; xTransform = false; goto draw; } }