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 // 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