Beispiel #1
0
void test_arrays() {
      // Test rotate matrix
      int N = 5;
      int Im[][5] = {
            {11,12,13,14,15},
            {21,22,23,24,25},
            {31,32,33,34,35},
            {41,42,43,44,45},
            {51,52,53,54,55}};

      rotate90(N, Im);
      assert(Im[0][0] == 51 && Im[4][4] == 15);
      rotate90(N, Im);
      rotate90(N, Im);
      rotate90(N, Im);
      assert(Im[0][0] == 11 && Im[4][4] == 55);

      // Test set col and row to zeros if zero is found
      int N1 = 4, M1 = 7;
      int mat[][7] = {
            {1, 0, 1, 1, 1, 0, 1},
            {1, 1, 1 ,1, 1, 1, 1},
            {1, 1, 1, 0, 1, 1, 1},
            {1, 1, 1, 1, 1, 1, 1} };
      zero_entries_fix(N1, M1, mat);
}
Beispiel #2
0
TilePoint Tile::drawTile(Point3 p, float edges[4], TileParam& t, int id, int dir) {
	float hEdgeW = t.edgeWidth * .5f;
	float hEdgeH = t.edgeHeight * .5f;
			
	float randomSeed = (float)id * 1.23f + 0.1234f;
	if (dir) {
		edges[0] += t.eH_var ? hEdgeH * (1.f + noise(edges[0], randomSeed) * t.edgeHeightVar) : hEdgeH;
		edges[2] -= t.eH_var ? hEdgeH * (1.f + noise(edges[2], randomSeed) * t.edgeHeightVar) : hEdgeH;
		edges[3] += t.eW_var ? hEdgeW * (1.f + noise(edges[3], randomSeed) * t.edgeWidthVar) : hEdgeW;
		edges[1] -= t.eW_var ? hEdgeW * (1.f + noise(edges[1], randomSeed) * t.edgeWidthVar) : hEdgeW;
	} else {
		edges[0] += t.eW_var ? hEdgeW * (1.f + noise(edges[0], randomSeed) * t.edgeWidthVar) : hEdgeW;
		edges[2] -= t.eW_var ? hEdgeW * (1.f + noise(edges[2], randomSeed) * t.edgeWidthVar) : hEdgeW;
		edges[3] += t.eH_var ? hEdgeH * (1.f + noise(edges[3], randomSeed) * t.edgeHeightVar) : hEdgeH;
		edges[1] -= t.eH_var ? hEdgeH * (1.f + noise(edges[1], randomSeed) * t.edgeHeightVar) : hEdgeH;
	}

	if (p.x < edges[0]) return TilePoint();
	if (p.x > edges[2]) return TilePoint();
	if (p.y < edges[3]) return TilePoint();
	if (p.y > edges[1]) return TilePoint();

	float width = edges[2] - edges[0];
	float height = edges[1] - edges[3];
	if (width < 0 || height < 0) return TilePoint();

	TilePoint tp = corner(p.x - edges[0], p.y - edges[3], width, height, t);	
	if (tp.d < 0) return tp; // On edge

	//if (t.tileID || t.mapUV)
		tp.id = id;

	if (t.center || (t.mapUV && dir))
		tp.center = Point3(edges[0] + (edges[2] - edges[0]) * .5f,
		                   edges[3] + (edges[1] - edges[3]) * .5f, p.z);

	if (dir) {
		offsetEdges(edges, -tp.center.x, -tp.center.y);
		rotate90(edges[0], edges[3]);
		rotate90(edges[2], edges[1]);
		offsetEdges(edges, tp.center.x, tp.center.y);
		p -= tp.center; rotate90(p.x, p.y); p += tp.center;
	}
	
	if (t.mapUV)
		uvMapping(tp, p, edges, t, dir);

	if (dir) {
		offsetEdges(edges, -tp.center.x, -tp.center.y);
		rotate270(edges[0], edges[3]);
		rotate270(edges[2], edges[1]);
		offsetEdges(edges, tp.center.x, tp.center.y);
		p -= tp.center; rotate270(p.x, p.y); p += tp.center;
	}

	return tp;	
}
void
ImageSearch::search() {
    search(subImage);
    if (isMask) {
	PNG flippedMask = flipVertical(subImage);
	search(flippedMask);
	PNG rotImg = rotate90(subImage);
	search(rotImg);
	rotImg.write("rotated_mask.png");
	rotImg = rotate90(rotImg);
	rotImg = rotate90(rotImg);
	search(rotImg);
    }
}
void MyInbetweener::stabilizeSegments(TStroke *stroke)
{
	for (int j = 0; j + 4 < stroke->getControlPointCount(); j += 4) {
		TThickPoint q0 = stroke->getControlPoint(j);
		TThickPoint q4 = stroke->getControlPoint(j + 4);
		TPointD p0 = convert(q0);
		TPointD p1 = convert(stroke->getControlPoint(j + 1));
		TPointD p2 = convert(stroke->getControlPoint(j + 2));
		TPointD p3 = convert(stroke->getControlPoint(j + 3));
		TPointD p4 = convert(q4);
		TPointD v = normalize(p4 - p0);
		TPointD u = rotate90(v);
		double eps = tdistance(p0, p4) * 0.1;
		if (fabs(u * (p2 - p0)) < eps &&
			fabs(u * (p1 - p0)) < eps &&
			fabs(u * (p3 - p0)) < eps) {
			double e = 0.001;
			double d2 = norm2(p4 - p0);
			if (e * e * 6 * 6 > d2)
				e = sqrt(d2) / 6;
			TThickPoint q1(p0 + v * e, q0.thick);
			TThickPoint q3(p4 - v * e, q4.thick);
			stroke->setControlPoint(j + 1, q1);
			stroke->setControlPoint(j + 3, q3);
		}
	}
}
Beispiel #5
0
int rotate(int ** arr, int degrees, int size)
{
  if(degrees % 90 != 0)
  {
    printf("Rotation must be a positive factor of 90.\n");
    return(-1);
  }

  while(degrees > 270)
  {
    degrees -= 360;
  }

  switch(degrees)
  {
    case 90:
      rotate90(arr, size);
      break;
    case 180:
      rotate180(arr, size);
      break;
    case 270:
      rotate270(arr, size);
      break;
  }

  return(0);
}
Beispiel #6
0
void TPC::fixupCubeMap() {
	/* Do various fixups to the cube maps. This includes rotating and swapping a
	 * few sides around. This is done by the original games as well.
	 */

	if (!isCubeMap())
		return;

	for (size_t j = 0; j < getMipMapCount(); j++) {
		assert(getLayerCount() > 0);

		const size_t index0 = 0 * getMipMapCount() + j;
		assert(index0 < _mipMaps.size());

		const  int32 width  = _mipMaps[index0]->width;
		const  int32 height = _mipMaps[index0]->height;
		const uint32 size   = _mipMaps[index0]->size;

		for (size_t i = 1; i < getLayerCount(); i++) {
			const size_t index = i * getMipMapCount() + j;
			assert(index < _mipMaps.size());

			if ((width  != _mipMaps[index]->width ) ||
			    (height != _mipMaps[index]->height) ||
			    (size   != _mipMaps[index]->size  ))
				throw Common::Exception("Cube map layer dimensions mismatch");
		}
	}

	// Since we need to rotate the individual cube sides, we need to decompress them all
	decompress();

	// Rotate the cube sides so that they're all oriented correctly
	for (size_t i = 0; i < getLayerCount(); i++) {
		for (size_t j = 0; j < getMipMapCount(); j++) {
			const size_t index = i * getMipMapCount() + j;
			assert(index < _mipMaps.size());

			MipMap &mipMap = *_mipMaps[index];

			static const int rotation[6] = { 3, 1, 0, 2, 2, 0 };

			rotate90(mipMap.data, mipMap.width, mipMap.height, getBPP(_format), rotation[i]);
		}
	}

	// Swap the first two sides of the cube maps
	for (size_t j = 0; j < getMipMapCount(); j++) {
		const size_t index0 = 0 * getMipMapCount() + j;
		const size_t index1 = 1 * getMipMapCount() + j;
		assert((index0 < _mipMaps.size()) && (index1 < _mipMaps.size()));

		MipMap &mipMap0 = *_mipMaps[index0];
		MipMap &mipMap1 = *_mipMaps[index1];

		SWAP(mipMap0.data, mipMap1.data);
	}
}
int Java_com_lightbox_android_photoprocessing_PhotoProcessing_nativeRotate90(JNIEnv* env, jobject thiz) {
	int resultCode = rotate90(&bitmap, 1, 1, 1);
	if (resultCode != MEMORY_OK) {
		return resultCode;
	}

	//All the component dimensions should have changed, so copy the correct dimensions
	bitmap.width = bitmap.redWidth;
	bitmap.height = bitmap.redHeight;
}
int Java_com_kapoocino_camera_editimage_fliter_PhotoProcessing_nativeRotate90(JNIEnv* env, jobject thiz) {
	int resultCode = rotate90(&bitmap, 1, 1, 1);
	if (resultCode != MEMORY_OK) {
		return resultCode;
	}

	//All the component dimensions should have changed, so copy the correct dimensions
	bitmap.width = bitmap.redWidth;
	bitmap.height = bitmap.redHeight;
}
double tdistance(const TSegment &segment, const TPointD &point) {
  TPointD v1 = segment.getP1() - segment.getP0();
  TPointD v2 = point - segment.getP0();
  TPointD v3 = point - segment.getP1();

  if (v2 * v1 <= 0)
    return tdistance(point, segment.getP0());
  else if (v3 * v1 >= 0)
    return tdistance(point, segment.getP1());

  return fabs(v2 * rotate90(normalize(v1)));
}
Beispiel #10
0
// rotate == 1 is 90 degrees, 2 is 180, 3 is 270 (positive is CCW).
static __inline__ void rotate_fun(int rotate, char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){
    switch( rotate )
    {
        case 1:
            rotate90(source, srcWidth, srcHeight, destination, dstWidth, dstHeight);
            break;
        case 2:
            rotate180(source, srcWidth, srcHeight, destination, dstWidth, dstHeight);
            break;
        case 3:
            rotate270(source, srcWidth, srcHeight, destination, dstWidth, dstHeight);
            break;
        default:
            break;
    }
}
void testApp::doVision() {
	
	// rotate the pixels from the camera
	cam.update();
	unsigned char *rgb = cam.getPixels();
	unsigned char *depth = cam.getDepthPixels();
	if(rgb!=NULL) {
		rotateRgb90(rgb, rgbRot, rotateClockwise, flipX);
		colorImg.setFromPixels(rgbRot, VISION_HEIGHT, VISION_WIDTH);
	}
	if(depth!=NULL) {
		rotate90(depth, rgbRot, rotateClockwise, flipX);
		depthImg.setFromPixels(rgbRot, VISION_HEIGHT, VISION_WIDTH);
	}
	if(learnBackground) {
		learnBackground = false;
		bgImg = depthImg;
	}
	
	int numPix = VISION_WIDTH * VISION_HEIGHT;
	depth = depthImg.getPixels();
	unsigned char *bg = bgImg.getPixels();
	
	
	// remove any pixels that are smaller than the background
	for(int i = 0; i < numPix; i++) {
		if(depth[i]<bg[i]+bgHysteresis) {	// background hysteresis, you've got to be at least 
			// bgHysteresis away
			// from the background to count as foreground.
			depth[i] = 0;
		}
	}
	
	// do thresholding and tidying up on the depth data.
	threshImg = depthImg;
	threshImg.threshold(farThreshold);
	for(int i = 0; i < erosions; i++) {
		threshImg.erode_3x3();
	}
	for(int i = 0; i < dilations; i++) {
		threshImg.dilate_3x3();
	}
	for(int i = 0; i < blurs; i++) {
		threshImg.blur(blurSize*2+1);
	}
}
Beispiel #12
0
int main( int argc, char* argv[])
{
  
  srand(time(0));

  int** matrix = createAndRandomize2DIntArray(N,N);

  print2DArray(matrix,N,N);

  rotate90(matrix,N);

  cout << "\n*********************\n" << endl;
  print2DArray(matrix,N,N);

  del2DArray(matrix,N);

  return 0;
}
Beispiel #13
0
void 
img_rotate( Handle self, Byte * new_data, int new_line_size, int degrees)
{
	PImage i = ( PImage ) self;

	if (( i-> type & imBPP) < 8 )
		croak("Not implemented");

	switch ( degrees ) {
	case 90:
		rotate90(i, new_data, new_line_size);
		break;
	case 180:
		rotate180(i, new_data);
		break;
	case 270:
		rotate270(i, new_data, new_line_size);
		break;
	}
}
Beispiel #14
0
int main() {
    int a, x;
    scanf("%d", &a);
    for(int i = 0; i < a; i++) {
        for(int j = 0; j < a/32; j++) {
            scanf("%d", &x);
            for(int k = 0; k < 32; k++) {
                tab[i][j*32+k] = x&(1<<(32-k));
            }
        }
    }
    int x1, x2, y1, y2;
    scanf("%d %d %d %d",&x1, &y1, &x2, &y2);
    for(int i = 0; i < 5; i++) {
        printf("%d %d %d %d \n", x1, y1, x2, y2);
        rotate90(&x1, &x2, &y1, &y2);
    }


}
bool
ImageBufAlgo::rotate90 (ImageBuf &dst, const ImageBuf &src,
                        ROI roi, int nthreads)
{
    if (&dst == &src) {    // Handle in-place operation
        ImageBuf tmp;
        tmp.swap (const_cast<ImageBuf&>(src));
        return rotate90 (dst, tmp, roi, nthreads);
    }

    pvt::LoggedTimer logtime("IBA::rotate90");
    ROI src_roi = roi.defined() ? roi : src.roi();
    ROI src_roi_full = src.roi_full();

    // Rotated full ROI swaps width and height, and keeps its origin
    // where the original origin was.
    ROI dst_roi_full (src_roi_full.xbegin, src_roi_full.xbegin+src_roi_full.height(),
                      src_roi_full.ybegin, src_roi_full.ybegin+src_roi_full.width(),
                      src_roi_full.zbegin, src_roi_full.zend,
                      src_roi_full.chbegin, src_roi_full.chend);

    ROI dst_roi (src_roi_full.yend-src_roi.yend,
                 src_roi_full.yend-src_roi.ybegin,
                 src_roi.xbegin, src_roi.xend,
                 src_roi.zbegin, src_roi.zend,
                 src_roi.chbegin, src_roi.chend);
    ASSERT (dst_roi.width() == src_roi.height() &&
            dst_roi.height() == src_roi.width());

    bool dst_initialized = dst.initialized();
    if (! IBAprep (dst_roi, &dst, &src))
        return false;
    if (! dst_initialized)
        dst.set_roi_full (dst_roi_full);

    bool ok;
    OIIO_DISPATCH_COMMON_TYPES2 (ok, "rotate90", rotate90_,
                          dst.spec().format, src.spec().format,
                          dst, src, dst_roi, nthreads);
    return ok;
}
Beispiel #16
0
void TPC::fixupCubeMap() {
	/* Do various fixups to the cube maps. This includes rotating and swapping a
	 * few sides around. This is done by the original games as well.
	 */

	if (!isCubeMap())
		return;

	// Since we need to rotate the individual cube sides, we need to decompress them all
	decompress();

	// Rotate the cube sides so that they're all oriented correctly
	for (size_t i = 0; i < getLayerCount(); i++) {
		for (size_t j = 0; j < getMipMapCount(); j++) {
			const size_t index = i * getMipMapCount() + j;
			assert(index < _mipMaps.size());

			MipMap &mipMap = *_mipMaps[index];

			static const int rotation[6] = { 3, 1, 0, 2, 2, 0 };

			rotate90(mipMap.data, mipMap.width, mipMap.height, getBPP(_format), rotation[i]);
		}
	}

	// Swap the first two sides of the cube maps
	for (size_t j = 0; j < getMipMapCount(); j++) {
		const size_t index0 = 0 * getMipMapCount() + j;
		const size_t index1 = 1 * getMipMapCount() + j;
			assert((index0 < _mipMaps.size()) && (index1 < _mipMaps.size()));

		MipMap &mipMap0 = *_mipMaps[index0];
		MipMap &mipMap1 = *_mipMaps[index1];

		assert((mipMap0.width == mipMap1.width) && (mipMap0.height == mipMap1.height));

		SWAP(mipMap0.data, mipMap1.data);
	}
}
ToolsMenu::ToolsMenu(ImageViewer* iv, QWidget* parent) :
    QWidget(parent),
    ui(new Ui::ToolsMenu)
{
    ui->setupUi(this);
    setLayout(ui->verticalLayoutWidget->layout());

    m_viewer = (ImageViewer*) iv;
    m_tools = new Tools(m_viewer, this);

    // locking tools menu when performing transformation

    connect(m_viewer, SIGNAL(lockTools()), this, SLOT(disableAllTools()));
    connect(m_viewer, SIGNAL(unlockTools()), this, SLOT(enableAllTools()));

    /* -------------------------------------------------------
     * ROTATION
     * ------------------------------------------------------- */

    connect(ui->rotate90Button, SIGNAL(clicked()), m_tools, SLOT(rotate90()));
    connect(ui->rotate180Button, SIGNAL(clicked()), m_tools, SLOT(rotate180()));
    connect(ui->rotate270Button, SIGNAL(clicked()), m_tools, SLOT(rotate270()));

    /* -------------------------------------------------------
     * HISTOGRAM
     * ------------------------------------------------------- */

    QMenu* hMenu = new QMenu(ui->histogramButton);
    hMenu->addAction(
                QIcon(":/icons/icons/chart_curve_error.png"),
                QString("Equalize histograms"),
                m_tools,
                SLOT(histogramEqualize())
                );
    hMenu->addAction(
                QIcon(":/icons/icons/chart_curve_go.png"),
                QString("Stretch histograms"),
                m_tools,
                SLOT(histogramStretch())
                );

    ui->histogramButton->setMenu(hMenu);

    /* -------------------------------------------------------
     * FILTERS (convolution, blur)
     * ------------------------------------------------------- */

    QMenu* bMenu = new QMenu(ui->blurButton);
    bMenu->addAction(
                QIcon(":/icons/icons/draw_convolve.png"),
                QString("Gaussian blur"),
                m_tools,
                SLOT(blurGauss())
                );
    bMenu->addAction(
                QIcon(":/icons/icons/draw_convolve.png"),
                QString("Uniform blur"),
                m_tools,
                SLOT(blurUniform())
                );
    bMenu->addAction(
                QIcon(":/icons/icons/flag_airfield_vehicle_safety.png"),
                QString("Custom linear filter"),
                m_tools,
                SLOT(blurLinear())
                );

    ui->blurButton->setMenu(bMenu);

    /* -------------------------------------------------------
     * BINARIZATION
     * ------------------------------------------------------- */

    QMenu* binMenu = new QMenu(ui->binarizationButton);
    binMenu->addAction(
                QIcon(":/icons/icons/universal_binary.png"),
                QString("Manual"),
                m_tools,
                SLOT(binManual())
                );
    binMenu->addAction(
                QIcon(":/icons/icons/universal_binary.png"),
                QString("Gradient"),
                m_tools,
                SLOT(binGradient())
                );
    binMenu->addAction(
                QIcon(":/icons/icons/universal_binary.png"),
                QString("Iterative bimodal"),
                m_tools,
                SLOT(binIterBimodal())
                );
    binMenu->addAction(
                QIcon(":/icons/icons/universal_binary.png"),
                QString("Niblack"),
                m_tools,
                SLOT(binNiblack())
                );
    binMenu->addAction(
                QIcon(":/icons/icons/universal_binary.png"),
                QString("Otsu"),
                m_tools,
                SLOT(binOtsu())
                );

    ui->binarizationButton->setMenu(binMenu);

    /* -------------------------------------------------------
     * NOISE REDUCTION
     * ------------------------------------------------------- */

    QMenu* nMenu = new QMenu(ui->noiseButton);
    nMenu->addAction(
                QIcon(":/icons/icons/checkerboard.png"),
                QString("Median"),
                m_tools,
                SLOT(noiseMedian())
                );
    nMenu->addAction(
                QIcon(":/icons/icons/checkerboard.png"),
                QString("Bilateral"),
                m_tools,
                SLOT(noiseBilateral())
                );

    ui->noiseButton->setMenu(nMenu);

    /* -------------------------------------------------------
     * MORPHOLOGICAL
     * ------------------------------------------------------- */

    QMenu* morphMenu = new QMenu(ui->morphButton);
    morphMenu->addAction(
                QIcon(":/icons/icons/arrow_out.png"),
                QString("Dilate"),
                m_tools,
                SLOT(morphDilate())
                );
    morphMenu->addAction(
                QIcon(":/icons/icons/arrow_in.png"),
                QString("Erode"),
                m_tools,
                SLOT(morphErode())
                );
    morphMenu->addAction(
                QIcon(":/icons/icons/arrow_divide.png"),
                QString("Open"),
                m_tools,
                SLOT(morphOpen())
                );
    morphMenu->addAction(
                QIcon(":/icons/icons/arrow_join.png"),
                QString("Close"),
                m_tools,
                SLOT(morphClose())
                );

    ui->morphButton->setMenu(morphMenu);

    /* -------------------------------------------------------
     * EDGE DETECTION
     * ------------------------------------------------------- */

    QMenu* eMenu = new QMenu(ui->edgeButton);
    eMenu->addAction(
                QIcon(":/icons/icons/key_s.png"),
                QString("Sobel"),
                m_tools,
                SLOT(edgeSobel())
                );
    eMenu->addAction(
                QIcon(":/icons/icons/key_p.png"),
                QString("Prewitt"),
                m_tools,
                SLOT(edgePrewitt())
                );
    eMenu->addAction(
                QIcon(":/icons/icons/key_r.png"),
                QString("Roberts"),
                m_tools,
                SLOT(edgeRoberts())
                );
    eMenu->addAction(
                QIcon(":/icons/icons/edge_detection.png"),
                QString("Laplacian"),
                m_tools,
                SLOT(edgeLaplacian())
                );
    eMenu->addAction(
                QIcon(":/icons/icons/edge_detection.png"),
                QString("Zero-crossing (LoG)"),
                m_tools,
                SLOT(edgeZero())
                );

    eMenu->addAction(
                QIcon(":/icons/icons/edge_detection.png"),
                QString("Canny"),
                m_tools,
                SLOT(edgeCanny())
                );

    ui->edgeButton->setMenu(eMenu);

    /* -------------------------------------------------------
     * TEXTURES
     * ------------------------------------------------------- */

    QMenu* texMenu = new QMenu(ui->textureButton);
    texMenu->addAction(
                QIcon(":/icons/icons/flag_airfield_vehicle_safety.png"),
                QString("Height map"),
                m_tools,
                SLOT(mapHeight())
                );
    texMenu->addAction(
                QIcon(":/icons/icons/flag_airfield_vehicle_safety.png"),
                QString("Normal map"),
                m_tools,
                SLOT(mapNormal())
                );
    texMenu->addAction(
                QIcon(":/icons/icons/flag_airfield_vehicle_safety.png"),
                QString("Horizon map"),
                m_tools,
                SLOT(mapHorizon())
                );
    ui->textureButton->setMenu(texMenu);

    /* -------------------------------------------------------
     * TRANSFORMATIONS
     * ------------------------------------------------------- */

    QMenu* transMenu = new QMenu(ui->transformationsButton);
    transMenu->addAction(
                QIcon(":/icons/icons/videodisplay.png"),
                QString("Hough"),
                m_tools,
                SLOT(houghTransform())
                );
    transMenu->addAction(
                QIcon(":/icons/icons/videodisplay.png"),
                QString("Hough - lines"),
                m_tools,
                SLOT(houghLines())
                );
    transMenu->addAction(
                QIcon(":/icons/icons/videodisplay.png"),
                QString("Hough - rectangles"),
                m_tools,
                SLOT(houghRectangles())
                );
    transMenu->addAction(
                QIcon(":/icons/icons/videodisplay.png"),
                QString("Segmentation"),
                m_tools,
                SLOT(segmentation())
                );
    ui->transformationsButton->setMenu(transMenu);

    /* -------------------------------------------------------
     * CORNER DETECTION
     * ------------------------------------------------------- */

    QMenu* cornerMenu = new QMenu(ui->cornerButton);
    cornerMenu->addAction(
                QIcon(":/icons/icons/things_digital.png"),
                QString("Harris"),
                m_tools,
                SLOT(cornerHarris())
                );
    ui->cornerButton->setMenu(cornerMenu);

}
Beispiel #18
0
int main()
{
// load image and get some image properties
    IplImage *p_image = cvLoadImage("lena.jpg");
    //IplImage *p_image = cvLoadImage("obama_90_sw.bmp");

    // create new image structure
    // for the grayscale output image
    IplImage *p_grayImage = cvCreateImage(cvSize( p_image->width, p_image->height ), IPL_DEPTH_8U, 1 );
    // set type CV_RGB2GRAY to convert
    // RGB image to grayscale
    cvCvtColor(p_image, p_grayImage,CV_RGB2GRAY);

// some local variables
    int width      = p_grayImage->width;
    int height     = p_grayImage->height;
    int width_step = p_grayImage->widthStep;
    int x,y;
    printf("width:     %i\n", width);
    printf("heigth:    %i\n", height);

// allocation of a two-dimensional array
    uchar ** array    = (uchar **) malloc(sizeof(uchar *) * height);
    uchar ** tmpArray = (uchar **) malloc(sizeof(uchar *) * height);
    for (y = 0; y < height; y++)
    {
        array[y]    = (uchar *) malloc(sizeof(uchar ) * width);
        tmpArray[y] = (uchar *) malloc(sizeof(uchar ) * width);
    }

// copy IplImage to allocated array
    copyIplImageToArray(height,width,p_grayImage,tmpArray);


// implementation of algorithm 1
    invertGray(height,width,tmpArray,array);

// save result
    saveArrayToImage(height,width,array,p_grayImage);

// create a new image (90 Grad Drehung)
    IplImage *p_rotate90 = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    rotate90(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_rotate90);
// create a new image (180 Grad Drehung)
    IplImage *p_rotate180 = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    rotate180(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_rotate180);
// create a new image (270 Grad Drehung)
    IplImage *p_rotate270 = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    rotate270(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_rotate270);
// create a new image (Vertikale Spiegelung)
    IplImage *p_flipvertical = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    flipvertical(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_flipvertical);
// create a new image (Horizontale Spiegelung)
    IplImage *p_fliphorizontal = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    fliphorizontal(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_fliphorizontal);
// create a new image (Beide Spiegelungen)
    IplImage *p_flipboth = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    flipboth(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_flipboth);
// create a new image (Skalierung Faktor 2)
    IplImage *p_scale2 = cvCreateImage(cvSize(width*2, height*2), IPL_DEPTH_8U, 1);
    scale2(height,width,tmpArray,p_scale2); //Speichert auch
// create a new image (Skalierung Faktor 1/2)
    IplImage *p_scalehalf = cvCreateImage(cvSize(width/2, height/2), IPL_DEPTH_8U, 1);
    scalehalf(height,width,tmpArray,p_scalehalf); //Speichert auch
// create a new image (GrauwertSprünge horizontal)
    IplImage *p_grayhor = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    grayhor(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_grayhor);
// create a new image (GrauwertSprünge vertikal)
    IplImage *p_grayvert = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    grayvert(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_grayvert);
// create a new image (GrauwertSprünge beide)
    IplImage *p_grayboth = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    graytotal(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_grayboth);
// create a new image (Mittelung 2x2)
    IplImage *p_mid2x2 = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    mid2x2(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_mid2x2);
// create a new image (Mittelung 2x2)
    IplImage *p_mid3x3 = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1);
    mid3x3(height,width,tmpArray,array);
    saveArrayToImage(height,width,array,p_mid3x3);



    // show images
    cvNamedWindow("original", 1);
    cvShowImage("original", p_image);
    cvNamedWindow("invertedGray", 1);
    cvShowImage("invertedGray", p_grayImage);
    cvNamedWindow("Drehung 90 Grad", 1);
    cvShowImage("Drehung 90 Grad", p_rotate90);
    cvNamedWindow("Drehung 180 Grad", 1);
    cvShowImage("Drehung 180 Grad", p_rotate180);
    cvNamedWindow("Drehung 270 Grad", 1);
    cvShowImage("Drehung 270 Grad", p_rotate270);
    cvNamedWindow("Spiegelung vertikal", 1);
    cvShowImage("Spiegelung vertikal", p_flipvertical);
    cvNamedWindow("Spiegelung horizontal", 1);
    cvShowImage("Spiegelung horizontal", p_fliphorizontal);
    cvNamedWindow("Beide Spiegelungen", 1);
    cvShowImage("Beide Spiegelungen", p_flipboth);
    cvNamedWindow("Skalierung Faktor 2", 1);
    cvShowImage("Skalierung Faktor 2", p_scale2);
    cvNamedWindow("Skalierung Faktor 1/2", 1);
    cvShowImage("Skalierung Faktor 1/2", p_scalehalf);
    cvNamedWindow("Grauwertsprünge horizontal", 1);
    cvShowImage("Grauwertsprünge horizontal", p_grayhor);
    cvNamedWindow("Grauwertsprünge vertikal", 1);
    cvShowImage("Grauwertsprünge vertikal", p_grayvert);
    cvNamedWindow("Grauwertsprünge beide", 1);
    cvShowImage("Grauwertsprünge beide", p_grayboth);
    cvNamedWindow("Mittelung 2x2", 1);
    cvShowImage("Mittelung 2x2", p_mid2x2);
    cvNamedWindow("Mittelung 3x3", 1);
    cvShowImage("Mittelung 3x3", p_mid3x3);

    // wait for 'esc' key
    cvWaitKey(0);

    // clean up
    cvReleaseImage(&p_grayImage);
    cvDestroyWindow("invertedGray");
    cvReleaseImage(&p_image);
    cvDestroyWindow("original");
    cvReleaseImage(&p_rotate90);
    cvDestroyWindow("Drehung 90 Grad");
    cvReleaseImage(&p_rotate180);
    cvDestroyWindow("Drehung 180 Grad");
    cvReleaseImage(&p_rotate270);
    cvDestroyWindow("Drehung 270 Grad");
    cvReleaseImage(&p_flipvertical);
    cvDestroyWindow("Spiegelung vertikal");
    cvReleaseImage(&p_fliphorizontal);
    cvDestroyWindow("Spiegelung horizontal");
    cvReleaseImage(&p_flipboth);
    cvDestroyWindow("Beide Spiegelungen");
    cvReleaseImage(&p_scale2);
    cvDestroyWindow("Skalierung Faktor 2");
    cvReleaseImage(&p_scalehalf);
    cvDestroyWindow("Skalierung Faktor 1/2");
    cvReleaseImage(&p_grayhor);
    cvDestroyWindow("Grauwertsprünge horizontal");
    cvReleaseImage(&p_grayvert);
    cvDestroyWindow("Grauwertsprünge vertikal");
    cvReleaseImage(&p_grayboth);
    cvDestroyWindow("Grauwertsprünge beide");
    cvReleaseImage(&p_mid2x2);
    cvDestroyWindow("Mittelung 2x2");
    cvReleaseImage(&p_mid3x3);
    cvDestroyWindow("Mittelung 3x3");



    for (y = 0; y < height; y++)
    {
        free(array[y]);
        free(tmpArray[y]);
    }
    free(array);
    free(tmpArray);

//cvSaveImage
    // bye bye
    printf("Goodbye\n");

    return 0;
}
Beispiel #19
0
 V2 lineNormalThatPassesThroughPointAndOrigin(const P2& p) {
   return rotate90(p);
 }
Beispiel #20
0
int main(void)
{
    char property[PROPERTY_VALUE_MAX];
    int fd = dup(STDOUT_FILENO);
    //unsigned long fb_lock[2]   = {MTKFB_LOCK_FRONT_BUFFER,   (unsigned long)NULL};
    //unsigned long fb_unlock[2] = {MTKFB_UNLOCK_FRONT_BUFFER, (unsigned long)NULL};
    //unsigned long fb_capture[2] = {MTKFB_CAPTURE_FRAMEBUFFER, (unsigned long)NULL};
    void *base = NULL, *base_align = NULL;
    int capture_buffer_size = 0, capture_buffer_size_align = 0;
    struct fb_var_screeninfo vinfo;
    int fb;
    uint32_t bytespp;
    uint32_t w, h, f;
    size_t size = 0;
    int should_munlock = 0;

	ALOGI("Enter lcdc_screen_cap.");
    if (fd < 0)
    {
        ALOGE("[DDMSCap]Dup STDOUT_FILENO failed!\n");
        goto done;
    }
    if (0 > (fb = open("/dev/graphics/fb0", O_RDONLY))) {
    	ALOGE("[DDMSCap]Open /dev/graphics/fb0 failed!\n");
    	goto done;
    }

    fcntl(fb, F_SETFD, FD_CLOEXEC);
    if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) {
    	ALOGI("[DDMSCap]FBIOGET_VSCREENINFO FAILED!\n");
    	goto done;
    }

    if (vinfoToPixelFormat(&vinfo, &bytespp, &f) == 0) 
    {
        w = vinfo.xres;
        h = vinfo.yres;
        size = w * h * bytespp;
        ALOGI("[DDMSCap]screen_width = %d, screen_height = %d, bpp = %d, format = %d, size = %d\n", w, h, bytespp, f, size);
    }
    {
        capture_buffer_size = w * h * bytespp;
        capture_buffer_size_align = capture_buffer_size + 32; //for M4U 32-byte alignment
        base_align = malloc(capture_buffer_size_align);

        if(base_align == NULL)
        {
            ALOGE("[DDMSCap]pmem_alloc size 0x%08x failed", capture_buffer_size_align);
            goto done;
        }
        else
        {
            ALOGE("[DDMSCap]pmem_alloc size = 0x%08x, addr = 0x%08x", capture_buffer_size_align, (unsigned int)base_align);
        }

        if(mlock(base_align, capture_buffer_size_align))
        {
            ALOGI("[DDMSCap] mlock fail! va=0x%x, size=%d, err=%d, %s\n",
                    base_align, capture_buffer_size_align, errno, strerror(errno));
            should_munlock = 0;
            //goto done;
        }
        else
        {
            should_munlock = 1;
        }


        base = (void *)((unsigned long)base_align + 32 - ((unsigned long)base_align & 0x1F)); //for M4U 32-byte alignment
        ALOGI("[DDMSCap]pmem_alloc base = 0x%08x", (unsigned int)base);
        //fb_capture[1] = (unsigned long)&base;
    	ALOGI("[DDMSCap]start capture\n");
        if(ioctl(fb, MTKFB_CAPTURE_FRAMEBUFFER, (unsigned long)&base) < 0)
        {
            ALOGE("[DDMSCap]ioctl of MTKFB_CAPTURE_FRAMEBUFFER fail\n");
            goto done;
        }
    	ALOGI("[DDMSCap]capture finished\n");
    }

    if (base) 
    {
    	int displayOrientation = 0;

    	if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
    		displayOrientation = atoi(property);
    	}

    	switch(displayOrientation)
    	{
    	case 0:
    	{
    		ALOGI("[DDMSCap]rotate 0 degree\n");
    		write(fd, &w, 4);
    		write(fd, &h, 4);
    		write(fd, &f, 4);			
    		//write(fd, base, size);			
			writex(fd, base, size);
			
    	}
    	break;

    	case 90:
    		ALOGI("[DDMSCap]rotate 90 degree\n");
    		if(rotate90(w,h,f,bytespp,base,size,capture_buffer_size,fd) < 0)
    			goto done;
    		break;

    	case 180:
    		ALOGI("[DDMSCap]rotate 180 degree\n");
    		if(rotate180(w,h,f,bytespp,base,size,capture_buffer_size,fd) < 0)
    			goto done;
    		break;

    	case 270:
    		ALOGI("[DDMSCap]rotate 270 degree\n");
    		if(rotate270(w,h,f,bytespp,base,size,capture_buffer_size,fd) < 0)
    			goto done;
    		break;

    	}
    }

done:
    if (NULL != base_align)
    {
        if(should_munlock)
            munlock(base_align, capture_buffer_size_align);
        free(base_align);
    }
    if(fb >= 0)
        close(fb);
    if(fd >= 0)
        close(fd);
   	ALOGI("[DDMSCap]all capture procedure finished\n");

    return 0;
}
Beispiel #21
0
static __inline__ void rotate270(char * source, int srcWidth, int srcHeight, char * destination, int dstWidth, int dstHeight){
    rotate90(source, srcWidth, srcHeight, destination, dstWidth, dstHeight);
    flip_fun(3, destination, dstWidth, dstHeight, destination, dstWidth, dstHeight);
}
Beispiel #22
0
static int
put_file_func (CameraFilesystem *fs, const char *folder, const char *name, 
	CameraFileType type, CameraFile *file, void *data, GPContext *context)
{
#ifdef HAVE_GD
	Camera *camera = data;
	char *c, *in_name, *out_name, *filedata = NULL;
	int ret, in_width, in_height, in_x, in_y;
	size_t inc, outc;
	double aspect_in, aspect_out;
#ifdef HAVE_ICONV
	char *in, *out;
#endif
	unsigned long filesize = 0;
	gdImagePtr rotated, im_out, im_in = NULL;

	if (strcmp (folder, "/"))
		return GP_ERROR_DIRECTORY_NOT_FOUND;

	inc = strlen (name);
	in_name = strdup (name);
	outc = inc;
	out_name = malloc (outc + 1);
	if (!in_name || !out_name) {
		free (in_name);
		free (out_name);
		return GP_ERROR_NO_MEMORY;
	}

	/* Convert name to ASCII */
#ifdef HAVE_ICONV
	in = in_name;
	out = out_name;
	if (iconv (camera->pl->cd, &in, &inc, &out, &outc) == -1) {
		free (in_name);
		free (out_name);
		gp_log (GP_LOG_ERROR, "iconv",
			"Failed to convert filename to ASCII");
		return GP_ERROR_OS_FAILURE;
	}
	outc = out - out_name;
	out_name[outc] = 0;
#else
	for (i = 0; i < inc; i++) {
		if ((uint8_t)in_name[i] < 0x20 || (uint8_t)in_name[i] > 0x7E)
			out_name[i] = '?';
		else
			out_name[i] = in_name[i];
	}
	out_name[i] = 0;
#endif
	free (in_name);

	/* Remove file extension, and if necessary truncate the name */
	c = strrchr (out_name, '.');
	if (c)
		*c = 0;
	if (outc > ST2205_FILENAME_LENGTH)
		out_name[ST2205_FILENAME_LENGTH] = 0;

	ret = gp_file_get_data_and_size (file, (const char **)&filedata,
					 &filesize);
	if (ret < 0) { free (out_name); return ret; }

	/* Try loading the file using gd, starting with the most often
	   used types first */

	/* gdImageCreateFromJpegPtr is chatty on error, don't call it on
	   non JPEG files */
	if (filesize > 2 &&
	    (uint8_t)filedata[0] == 0xff && (uint8_t)filedata[1] == 0xd8)
		im_in = gdImageCreateFromJpegPtr(filesize, filedata);
	if (im_in == NULL)
		im_in = gdImageCreateFromPngPtr(filesize, filedata);
	if (im_in == NULL)
		im_in = gdImageCreateFromGifPtr(filesize, filedata);
	if (im_in == NULL)
		im_in = gdImageCreateFromWBMPPtr(filesize, filedata);
	if (im_in == NULL) {
		gp_log (GP_LOG_ERROR, "st2205",
			"Unrecognized file format for file: %s%s",
			folder, name);
		free (out_name);
		return GP_ERROR_BAD_PARAMETERS;
	}

	if (needs_rotation (camera)) {
		rotated = gdImageCreateTrueColor (im_in->sy, im_in->sx);
		if (rotated == NULL) {
			gdImageDestroy (im_in);
			free (out_name);
			return GP_ERROR_NO_MEMORY;
		}
		rotate90 (im_in, rotated);
		gdImageDestroy (im_in);
		im_in = rotated;
	}

	im_out = gdImageCreateTrueColor(camera->pl->width, camera->pl->height);
	if (im_out == NULL) {
		gdImageDestroy (im_in);
		free (out_name);
		return GP_ERROR_NO_MEMORY;
	}

	/* Keep aspect */
	aspect_in  = (double)im_in->sx / im_in->sy;
	aspect_out = (double)im_out->sx / im_out->sy;
	if (aspect_in > aspect_out) {
		/* Reduce in width (crop left and right) */
		in_width = (im_in->sx / aspect_in) * aspect_out;
		in_x = (im_in->sx - in_width) / 2;
		in_height = im_in->sy;
		in_y = 0;
	} else {
		/* Reduce in height (crop top and bottom) */
		in_width = im_in->sx;
		in_x = 0;
		in_height = (im_in->sy * aspect_in) / aspect_out;
		in_y = (im_in->sy - in_height) / 2;
	}

	gdImageCopyResampled (im_out, im_in, 0, 0, in_x, in_y,
			      im_out->sx, im_out->sy,
			      in_width, in_height);

	if (im_in->sx != im_out->sx ||
	    im_in->sy != im_out->sy)
		gdImageSharpen(im_out, 100);

	ret = st2205_write_file (camera, out_name, im_out->tpixels);
	if (ret >= 0) {
		/* Add to our filenames list */
		ST2205_SET_FILENAME(camera->pl->filenames[ret], out_name, ret);
		/* And commit the changes to the device */
		ret = st2205_commit(camera);
	}

	gdImageDestroy (im_in);
	gdImageDestroy (im_out);
	free (out_name);
	return ret;
#else
	gp_log(GP_LOG_ERROR,"st2205", "GD compression not supported - no libGD present during build");
	return GP_ERROR_NOT_SUPPORTED;
#endif
}
Beispiel #23
0
void LineBuilder::build() {

	// Need at least 2 points to draw a line
	if (points.size() < 2) {
		clear_output();
		return;
	}

	const float hw = width / 2.f;
	const float hw_sq = hw * hw;
	const float sharp_limit_sq = sharp_limit * sharp_limit;
	const int len = points.size();

	// Initial values

	Vector2 pos0 = points[0];
	Vector2 pos1 = points[1];
	Vector2 f0 = (pos1 - pos0).normalized();
	Vector2 u0 = rotate90(f0);
	Vector2 pos_up0 = pos0 + u0 * hw;
	Vector2 pos_down0 = pos0 - u0 * hw;

	Color color0;
	Color color1;

	float current_distance0 = 0.f;
	float current_distance1 = 0.f;
	float total_distance;
	_interpolate_color = gradient != NULL;
	bool distance_required = _interpolate_color || texture_mode == LINE_TEXTURE_TILE;
	if (distance_required)
		total_distance = calculate_total_distance(points);
	if (_interpolate_color)
		color0 = gradient->get_color(0);
	else
		colors.push_back(default_color);

	float uvx0 = 0.f;
	float uvx1 = 0.f;

	// Begin cap
	if (begin_cap_mode == LINE_CAP_BOX) {
		// Push back first vertices a little bit
		pos_up0 -= f0 * hw;
		pos_down0 -= f0 * hw;
		// The line's outer length will be a little higher due to begin and end caps
		total_distance += width;
		current_distance0 += hw;
		current_distance1 = current_distance0;
	} else if (begin_cap_mode == LINE_CAP_ROUND) {
		if (texture_mode == LINE_TEXTURE_TILE) {
			uvx0 = 0.5f;
		}
		new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, 1.f, 1.f));
		total_distance += width;
		current_distance0 += hw;
		current_distance1 = current_distance0;
	}

	strip_begin(pos_up0, pos_down0, color0, uvx0);

	//  pos_up0 ------------- pos_up1 --------------------
	//     |                     |
	//   pos0 - - - - - - - - - pos1 - - - - - - - - - pos2
	//     |                     |
	// pos_down0 ------------ pos_down1 ------------------
	//
	//   i-1                     i                      i+1

	// http://labs.hyperandroid.com/tag/opengl-lines
	// (not the same implementation but visuals help a lot)

	// For each additional segment
	for (int i = 1; i < len - 1; ++i) {

		pos1 = points[i];
		Vector2 pos2 = points[i + 1];

		Vector2 f1 = (pos2 - pos1).normalized();
		Vector2 u1 = rotate90(f1);

		// Determine joint orientation
		const float dp = u0.dot(f1);
		const Orientation orientation = (dp > 0.f ? UP : DOWN);

		Vector2 inner_normal0, inner_normal1;
		if (orientation == UP) {
			inner_normal0 = u0 * hw;
			inner_normal1 = u1 * hw;
		} else {
			inner_normal0 = -u0 * hw;
			inner_normal1 = -u1 * hw;
		}

		// ---------------------------
		//                        /
		// 0                     /    1
		//                      /          /
		// --------------------x------    /
		//                    /          /    (here shown with orientation == DOWN)
		//                   /          /
		//                  /          /
		//                 /          /
		//                     2     /
		//                          /

		// Find inner intersection at the joint
		Vector2 corner_pos_in, corner_pos_out;
		SegmentIntersectionResult intersection_result = segment_intersection(
				pos0 + inner_normal0, pos1 + inner_normal0,
				pos1 + inner_normal1, pos2 + inner_normal1,
				&corner_pos_in);

		if (intersection_result == SEGMENT_INTERSECT)
			// Inner parts of the segments intersect
			corner_pos_out = 2.f * pos1 - corner_pos_in;
		else {
			// No intersection, segments are either parallel or too sharp
			corner_pos_in = pos1 + inner_normal0;
			corner_pos_out = pos1 - inner_normal0;
		}

		Vector2 corner_pos_up, corner_pos_down;
		if (orientation == UP) {
			corner_pos_up = corner_pos_in;
			corner_pos_down = corner_pos_out;
		} else {
			corner_pos_up = corner_pos_out;
			corner_pos_down = corner_pos_in;
		}

		LineJointMode current_joint_mode = joint_mode;

		Vector2 pos_up1, pos_down1;
		if (intersection_result == SEGMENT_INTERSECT) {
			// Fallback on bevel if sharp angle is too high (because it would produce very long miters)
			if (current_joint_mode == LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / hw_sq > sharp_limit_sq) {
				current_joint_mode = LINE_JOINT_BEVEL;
			}
			if (current_joint_mode == LINE_JOINT_SHARP) {
				// In this case, we won't create joint geometry,
				// The previous and next line quads will directly share an edge.
				pos_up1 = corner_pos_up;
				pos_down1 = corner_pos_down;
			} else {
				// Bevel or round
				if (orientation == UP) {
					pos_up1 = corner_pos_up;
					pos_down1 = pos1 - u0 * hw;
				} else {
					pos_up1 = pos1 + u0 * hw;
					pos_down1 = corner_pos_down;
				}
			}
		} else {
			// No intersection: fallback
			pos_up1 = corner_pos_up;
			pos_down1 = corner_pos_down;
		}

		// Add current line body quad
		// Triangles are clockwise
		if (distance_required) {
			current_distance1 += pos0.distance_to(pos1);
		}
		if (_interpolate_color) {
			color1 = gradient->get_color_at_offset(current_distance1 / total_distance);
		}
		if (texture_mode == LINE_TEXTURE_TILE) {
			uvx0 = current_distance0 / width;
			uvx1 = current_distance1 / width;
		}

		strip_add_quad(pos_up1, pos_down1, color1, uvx1);

		// Swap vars for use in the next line
		color0 = color1;
		u0 = u1;
		f0 = f1;
		pos0 = pos1;
		current_distance0 = current_distance1;
		if (intersection_result == SEGMENT_INTERSECT) {
			if (current_joint_mode == LINE_JOINT_SHARP) {
				pos_up0 = pos_up1;
				pos_down0 = pos_down1;
			} else {
				if (orientation == UP) {
					pos_up0 = corner_pos_up;
					pos_down0 = pos1 - u1 * hw;
				} else {
					pos_up0 = pos1 + u1 * hw;
					pos_down0 = corner_pos_down;
				}
			}
		} else {
			pos_up0 = pos1 + u1 * hw;
			pos_down0 = pos1 - u1 * hw;
		}
		// From this point, bu0 and bd0 concern the next segment

		// Add joint geometry
		if (current_joint_mode != LINE_JOINT_SHARP) {

			// ________________ cbegin
			//               / \
			//              /   \
			// ____________/_ _ _\ cend
			//             |     |
			//             |     |
			//             |     |

			Vector2 cbegin, cend;
			if (orientation == UP) {
				cbegin = pos_down1;
				cend = pos_down0;
			} else {
				cbegin = pos_up1;
				cend = pos_up0;
			}

			if (current_joint_mode == LINE_JOINT_BEVEL) {
				strip_add_tri(cend, orientation);
			} else if (current_joint_mode == LINE_JOINT_ROUND) {
				Vector2 vbegin = cbegin - pos1;
				Vector2 vend = cend - pos1;
				strip_add_arc(pos1, vend.angle_to(vbegin), orientation);
			}

			if (intersection_result != SEGMENT_INTERSECT)
				// In this case the joint is too f****d up to be re-used,
				// start again the strip with fallback points
				strip_begin(pos_up0, pos_down0, color1, uvx1);
		}
	}

	// Last (or only) segment

	pos1 = points[points.size() - 1];

	Vector2 pos_up1 = pos1 + u0 * hw;
	Vector2 pos_down1 = pos1 - u0 * hw;

	// End cap (box)
	if (end_cap_mode == LINE_CAP_BOX) {
		pos_up1 += f0 * hw;
		pos_down1 += f0 * hw;
	}

	if (distance_required) {
		current_distance1 += pos0.distance_to(pos1);
	}
	if (_interpolate_color) {
		color1 = gradient->get_color(gradient->get_points_count() - 1);
	}
	if (texture_mode == LINE_TEXTURE_TILE) {
		uvx1 = current_distance1 / width;
	}

	strip_add_quad(pos_up1, pos_down1, color1, uvx1);

	// End cap (round)
	if (end_cap_mode == LINE_CAP_ROUND) {
		// Note: color is not used in case we don't interpolate...
		Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0);
		new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f, 0.f, 1.f, 1.f));
	}
}