opengl绘制固定宽度多边形圆角边框算法(历时周半,撰博文以志纪念)II

BYLineII.h

//
//  BYLineII.h
//  SuperBalance1.1
//
//  Created by Bruce Yang on 7/26/11.
//  Copyright 2011 Home. All rights reserved.
//

@protocol BYLineII

struct BYLine {
	float k;
	float b;
	BOOL kExists;
	float extraX;
};
typedef struct BYLine BYLine;

@end


GenericBase.mm

//
//  GenericBase.mm
//  SuperBalance1.1
//
//  Created by Bruce Yang on 7/26/11.
//  Copyright 2011 Home. All rights reserved.
//

#import "GenericBase.h"


@implementation GenericBase


+ (BYLine) getLine:(CGPoint)p1 anotherPoint:(CGPoint)p2 {
	BYLine line;
	if((p1.x - p2.x) != 0) {
		float k = (p1.y - p2.y)/(p1.x - p2.x);
		float b = (p1.y - p1.x * k);
		
		line.kExists = true;
		line.k = k;
		line.b = b;
	} else {
		line.kExists = false;
		line.extraX = p1.x;
	}
	return line;
}

+ (BYLine) getLine:(CGPoint)point kParam:(float)aK {
	BYLine l;
	l.k = aK;
	l.b = point.y - aK*point.x;
	return l;
}

+ (float) get2PointsDistance:(CGPoint)p0 anotherPoint:(CGPoint)p1 {
	float distance = (float)sqrt(pow(p0.y - p1.y, 2) + pow(p0.x - p1.x, 2));
	return distance;
}

+ (CGPoint) getCrossPoint:(BYLine)l1 lineParam:(BYLine)l2 {
	float x, y;
	if(l1.kExists && l2.kExists) {
		x = (l2.b - l1.b) / (l1.k - l2.k);
		y = l1.k * x + l1.b;
	} else if(!l1.kExists && l2.kExists) {
		x = l1.extraX;
		y = l2.k * x + l2.b;
	} else if(l1.kExists && !l2.kExists) {
		x = l2.extraX;
		y = l1.k * x + l1.b;
	} else {
		x = 0.0f;
		y = 0.0f;
	}
	return ccp(x, y);
}

+ (CGPoint) getProjectivePoint:(CGPoint)p lineParam:(BYLine)l {
	CGPoint target;
	if(l.kExists) {
		if(l.k != 0) {
			BYLine newLine;
			
			// 难道是因为少写了这个??果然是因为这个!!
			// 足见一个良好的数据类型是多么的重要,如果一开始就是用类来完成BYLine结构体的功能的话,那将会大大降低出错的机率!!
			newLine.kExists = true;
			newLine.k = -1/l.k;
			newLine.b = p.y -(-1/l.k)*p.x;
			target = [GenericBase getCrossPoint:l lineParam:newLine];
		} else {
			target = ccp(p.x, l.b);
		}
	} else {
		target = ccp(l.extraX, p.y);
	}
	return target;
}

+ (float) getRadian:(CGPoint)p1 secondPoint:(CGPoint)p2 thirdPoint:(CGPoint)p3 {
	float l31, l12, l23, angle;
	l31 = BORDER_WIDTH;
	l12 = BORDER_WIDTH;
	l23 = [GenericBase get2PointsDistance:p2 anotherPoint:p3];
	float cosineValue = (l31*l31 + l12*l12 - l23*l23)/(2*l31*l12);
	angle = (float)acos(cosineValue);
	return angle;
}

+ (float) getB1:(float)k bParam:(float)b {
	float result = (float) b + BORDER_WIDTH*(float)sqrt(k*k + 1);
	return result;
	
}
+ (float) getB2:(float)k bParam:(float)b {
	float result = (float) b - BORDER_WIDTH*(float)sqrt(k*k + 1);
	return result;
}
+ (CGPoint*) getCircleCenter:(BYLine)l1 lineParam:(BYLine)l2 {
	CGPoint *dest = new CGPoint[4];
	BYLine l1_1, l1_2, l2_1, l2_2;

	if(l1.kExists && l2.kExists) {
		l1_1.kExists = true;
		l1_1.k = l1.k;
		l1_1.b = [GenericBase getB1:l1.k bParam:l1.b];
		
		l1_2.kExists = true;
		l1_2.k = l1.k;
		l1_2.b = [GenericBase getB2:l1.k bParam:l1.b];
		
		l2_1.kExists = true;
		l2_1.k = l2.k;
		l2_1.b = [GenericBase getB1:l2.k bParam:l2.b];
		
		l2_2.kExists = true;
		l2_2.k = l2.k;
		l2_2.b = [GenericBase getB2:l2.k bParam:l2.b];
		
	} else if(!l1.kExists && l2.kExists) {
		l1_1.kExists = false;
		l1_1.extraX = l1.extraX + BORDER_WIDTH;
		
		l1_2.kExists = false;
		l1_2.extraX = l1.extraX - BORDER_WIDTH;
		
		l2_1.kExists = true;
		l2_1.k = l2.k;
		l2_1.b = [GenericBase getB1:l2.k bParam:l2.b];
		
		l2_2.kExists = true;
		l2_2.k = l2.k;
		l2_2.b = [GenericBase getB2:l2.k bParam:l2.b];
		
	} else if(l1.kExists && !l2.kExists) {
		l1_1.kExists = true;
		l1_1.k = l1.k;
		l1_1.b = [GenericBase getB1:l1.k bParam:l1.b];
		
		l1_2.kExists = true;
		l1_2.k = l1.k;
		l1_2.b = [GenericBase getB2:l1.k bParam:l1.b];

		l2_1.kExists = false;
		l2_1.extraX = l2.extraX + BORDER_WIDTH;
		
		l2_2.kExists = false;
		l2_2.extraX = l2.extraX - BORDER_WIDTH;
	} else {
		NSLog(@"It's no possible!");
	}
	
	dest[0] = [GenericBase getCrossPoint:l1_1 lineParam:l2_1];
	dest[1] = [GenericBase getCrossPoint:l1_1 lineParam:l2_2];
	dest[2] = [GenericBase getCrossPoint:l1_2 lineParam:l2_1];
	dest[3] = [GenericBase getCrossPoint:l1_2 lineParam:l2_2];
	return dest;
	
}


+ (CGPoint) getNearestPoint:(CGPoint*)points lineParam:(BYLine)line {
	float minDistance = 0;
	int minIndex = 0;
	if(line.kExists) {
		for(int i = 0; i < 4; i ++) {
			CGPoint p = points[i];
			float d = (float)(abs(line.k*p.x-p.y+line.b)/sqrt(pow(line.k,2)+1));
			if(i == 0) {
				minDistance = d;
			}
			if(d < minDistance) {
				minDistance = d;
				minIndex = i;
			}
		}
	} else {
		for(int i = 0; i < 4; i ++) {
			CGPoint p = points[i];
			float d = abs(p.x - line.extraX);
			if(i == 0) {
				minDistance = d;
			}
			if(d < minDistance) {
				minDistance = d;
				minIndex = i;
			}
		}
	}
	
	CGPoint dest = points[minIndex];
	delete points;
	return dest;
}

+ (CGPoint*) genGroupPoints:(CGPoint)pCircle pointParam1:(CGPoint)pProj1 pointParam2:(CGPoint)pProj2 {
	CGPoint *target = new CGPoint[11];
	float radian = [GenericBase getRadian:pCircle secondPoint:pProj1 thirdPoint:pProj2];
	float deltaRadian = radian / 6;
	float startRadian;
	if((pProj1.y == pCircle.y) && (pProj1.x > pCircle.x)) {
		startRadian = 0;
	} else if((pProj1.y > pCircle.y) && (pProj1.x == pCircle.x)) {
		startRadian = PI_ROUGH / 2;
	} else if((pProj1.y == pCircle.y) && (pProj1.x < pCircle.x)) {
		startRadian = PI_ROUGH;
	} else if((pProj1.y < pCircle.y) && (pProj1.x == pCircle.x)) {
		startRadian = PI_ROUGH * 3 / 2;
	} else if((pProj1.y > pCircle.y) && (pProj1.x > pCircle.x)) {
		startRadian = (float)atan(abs((pProj1.y - pCircle.y)/(pProj1.x - pCircle.x)));
	} else if((pProj1.y > pCircle.y) && (pProj1.x < pCircle.x)) {
		startRadian = (float)(PI_ROUGH - atan(abs((pProj1.y - pCircle.y)/(pProj1.x - pCircle.x))));
	} else if((pProj1.y < pCircle.y) && (pProj1.x < pCircle.x)) {
		startRadian = (float)(PI_ROUGH + atan(abs((pProj1.y - pCircle.y)/(pProj1.x - pCircle.x))));
	} else {
		startRadian = (float)(2*PI_ROUGH - atan(abs((pProj1.y - pCircle.y)/(pProj1.x - pCircle.x))));
	}
	target[1] = pCircle;
	target[4] = pCircle;
	target[7] = pCircle;
	target[10] = pCircle;
	for(int i = 0; i < 11; i ++) {
		if(i==1 || i==4 || i==7 || i==10) {
			continue;
		} else {
			target[i].x = target[1].x + (float)(BORDER_WIDTH * cos(startRadian));
			target[i].y = target[1].y + (float)(BORDER_WIDTH * sin(startRadian));
			startRadian -= deltaRadian;
		}
	}
	if(DEBUG_MODE) {

	}
	return target;
}

@end


PointsGeneratorGeneric.mm

//
//  PointsGeneratorGeneric.mm
//  SuperBalance1.1
//
//  Created Bruce Yang on 7/26/11.
//  Copyright 2011 Home. All rights reserved.
//

#import "PointsGeneratorGeneric.h"


@implementation PointsGeneratorGeneric

+ (CGPoint*) genPolygonPoints:(CGPoint*)p pointsCount:(int)inPCount {
	int outPCount = inPCount*11 + 2;
	CGPoint *target = new CGPoint[outPCount];
	
	int targetCurrentIndex = 0;
	
	CGPoint p0, p1, p2;
	for(int i = 0; i < inPCount; i ++) {
		p0 = p[i];
		p1 = (i-1 == -1) ? p[inPCount-1] : p[i-1];
		p2 = (i+1 < inPCount) ? p[i+1] : p[0];
		
		CGPoint *pGroup = [PointsGeneratorGeneric handleUnit:p0 secondPoint:p1 thirdPoint:p2];
		
		for(int j = 0; j < 11; j ++) {
			target[targetCurrentIndex + j]  = pGroup[j];
		}
		delete pGroup;
		targetCurrentIndex += 11;
	}
	target[outPCount-2] = target[0];
	target[outPCount-1] = target[1];
	return target;
}

+ (CGPoint*) handleUnit:(CGPoint)p0 secondPoint:(CGPoint)p1 thirdPoint:(CGPoint)p2 {
	BYLine l_p0_p1 = [GenericBase getLine:p0 anotherPoint:p1];
	BYLine l_p0_p2 = [GenericBase getLine:p0 anotherPoint:p2];
	CGPoint *circleCenters = [GenericBase getCircleCenter:l_p0_p1 lineParam:l_p0_p2];
	
	BYLine l_p1_p2 = [GenericBase getLine:p1 anotherPoint:p2];
	CGPoint circleCenter = [GenericBase getNearestPoint:circleCenters lineParam:l_p1_p2];
	
	CGPoint projectivePoint1 = [GenericBase getProjectivePoint:circleCenter lineParam:l_p0_p1];
	CGPoint projectivePoint2 = [GenericBase getProjectivePoint:circleCenter lineParam:l_p0_p2];
	
	CGPoint *pGroup = [GenericBase genGroupPoints:circleCenter pointParam1:projectivePoint1 pointParam2:projectivePoint2];
	return pGroup;
}

@end



posted on 2011-07-27 11:23  yang3wei  阅读(334)  评论(0编辑  收藏  举报