- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想创建一个 NSBezierPath 来表示“弯曲”或“臃肿”的正方形,如下所示:
我正在努力想出正确的数学方法来使这个形状完全正确。我查遍了互联网,但谷歌搜索这个主题主要是“这就是如何绘制圆角”,这不是我需要的。
任何人都可以向我指出一个可以用来放置这些曲线的控制点的公式吗?谢谢!
最佳答案
好的;经过多次尝试和错误,我得到了一些有用的东西。下面的代码将绘制一个像这样的形状。 (此图像对代码中的 #define 语句使用以下值):
#define SIDE_DEFLECTION 18.0f
#define CORNER_RAD 18.0f
#define KAPPA 0.55238f
#define CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION .10
#define SIDE_CENTER_CP_OFFSET 0.60
给定 500x500 像素 View ,这些值将绘制此形状:
就我而言,我在 NSButtonCell 子类中绘制此形状。因为我知道这个单元格的框架永远不会在我的应用程序中调整大小,所以我可以做一些优化。具体来说,我将 NSBezierPath 存储为 iVar,因此我不必每次通过 -drawImage 重新创建它...此外,我将 NSShadow 和 NSColor 存储为 iVar,因此也不必重新创建它们。
如果您要在可调整大小的 View 中绘制此形状,则需要稍微调整代码。如果正方形的大小发生剧烈变化,则需要立即手动调整 #define 语句的值(否则,角看起来不太正确。侧曲线过渡到圆角曲线时几乎没有缩进,等等)
下面的代码配置为在 52x52 像素的正方形中绘制相同的形状。一般的方法是设置你想要的“侧面偏转”和“拐角半径”,然后调整两个“偏移”定义语句(它们是百分比),直到拐角看起来完美。 “kappa”的值绝不能改变——这个值取 self 发现的一篇数学论文。
这是优化的绘图代码:
#import "LPProjectIconButtonCell.h"
#define SIDE_DEFLECTION 1.0f
#define CORNER_RAD 4.0f
// Distance (%) control points should be from curve start/end to form perfectly circular rounded corners
#define KAPPA 0.55238f
// Percentage offset (from perfectly circular rounded corner location) that the corner control points use to
// compensate for the fact that our sides are rounded. Without this, we get a rough transition between the
// curve of the side and the start of the corner curve
#define CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION .85
// As the curve approaches each side-center point, this is the percentage of the distance between the side endpoints
// and the side centerpoint where the control point for approaching the centerpoint is located. You are not expected
// to understand the preceeding sentence.
#define SIDE_CENTER_CP_OFFSET 0.60
@implementation LPProjectIconButtonCell
- (void) awakeFromNib
{
_shadow = [[NSShadow alloc] init];
[_shadow setShadowBlurRadius:1.0f];
[_shadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0f alpha:0.2f]];
[_shadow setShadowOffset:NSMakeSize(0.0f, -1.0f)];
_borderColor = [[NSColor colorWithCalibratedWhite:0.13 alpha:1.0f] retain];
}
- (void) dealloc
{
[_path release];
_path = nil;
[_shadow release];
_shadow = nil;
[_borderColor release];
_borderColor = nil;
[super dealloc];
}
- (void) drawImage:(NSImage *)image withFrame:(NSRect)frame inView:(NSView *)controlView
{
NSGraphicsContext *currentContext = [NSGraphicsContext currentContext];
// The path never changes because this view never resizes. So we'll save it to be efficient
if (!_path)
{
NSRect rect = NSInsetRect(frame, 2.0f, 2.0f);
// Create the primary points -- 3 per side
NSPoint TCenter = NSMakePoint(rect.size.width/2.0f, rect.origin.y);
NSPoint TLeft = NSMakePoint(rect.origin.x + CORNER_RAD + SIDE_DEFLECTION, rect.origin.y + SIDE_DEFLECTION);
NSPoint TRight = NSMakePoint(rect.origin.x + rect.size.width - (CORNER_RAD + SIDE_DEFLECTION), rect.origin.y + SIDE_DEFLECTION);
NSPoint LTop = NSMakePoint(rect.origin.x + SIDE_DEFLECTION, rect.origin.y + CORNER_RAD + SIDE_DEFLECTION);
NSPoint LCenter = NSMakePoint(rect.origin.x, rect.size.height/2.0f);
NSPoint LBottom = NSMakePoint(rect.origin.x + SIDE_DEFLECTION, rect.origin.y + rect.size.height - CORNER_RAD - SIDE_DEFLECTION);
NSPoint BLeft = NSMakePoint(TLeft.x, rect.origin.y + rect.size.height - SIDE_DEFLECTION);
NSPoint BCenter = NSMakePoint(TCenter.x, rect.origin.y + rect.size.height);
NSPoint BRight = NSMakePoint(TRight.x, BLeft.y);
NSPoint RTop = NSMakePoint(rect.origin.x + rect.size.width - SIDE_DEFLECTION, LTop.y);
NSPoint RCenter = NSMakePoint(rect.origin.x + rect.size.width, LCenter.y);
NSPoint RBottom = NSMakePoint(RTop.x, LBottom.y);
// Create corner control points for rounded corners
// We don't want them to be perfectly circular, because our sides are curved. So we adjust them slightly to compensate for that.
NSPoint CP_TLeft = NSMakePoint(TLeft.x - (TLeft.x - LTop.x) * KAPPA, TLeft.y + SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION);
NSPoint CP_LTop = NSMakePoint(LTop.x + SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION, LTop.y - (LTop.y - TLeft.y) * KAPPA);
NSPoint CP_LBottom = NSMakePoint(LBottom.x + SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION, LBottom.y + (BLeft.y - LBottom.y) * KAPPA);
NSPoint CP_BLeft = NSMakePoint(BLeft.x - (BLeft.x - LBottom.x) * KAPPA, BLeft.y - SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION);
NSPoint CP_BRight = NSMakePoint(BRight.x + (RBottom.x - BRight.x) * KAPPA, BRight.y - SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION);
NSPoint CP_RBottom = NSMakePoint(RBottom.x - SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION, RBottom.y + (BRight.y - RBottom.y) * KAPPA);
NSPoint CP_RTop = NSMakePoint(RTop.x - SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION, RTop.y - (RTop.y - TRight.y) * KAPPA);
NSPoint CP_TRight = NSMakePoint(TRight.x + (RTop.x - TRight.x) * KAPPA, TRight.y + SIDE_DEFLECTION * CORNER_CP_OFFSET_FOR_SIDE_DEFLECTION);
// Create control points for the rounded sides. (The "duplicate" control points are here in case I ever tweak this in the future.)
NSPoint CP_DepartingTCenterForTLeft = NSMakePoint(TCenter.x - (TCenter.x - TLeft.x) * SIDE_CENTER_CP_OFFSET, TCenter.y);
NSPoint CP_ApproachingTLeft = TLeft;
NSPoint CP_DepartingLTopForLCenter = LTop;
NSPoint CP_ApproachingLCenterFromLTop = NSMakePoint(LCenter.x, LCenter.y - (LCenter.y - LTop.y) * SIDE_CENTER_CP_OFFSET);
NSPoint CP_DepartingLCenterForLBottom = NSMakePoint(LCenter.x, LCenter.y + (LBottom.y - LCenter.y) * SIDE_CENTER_CP_OFFSET);
NSPoint CP_ApproachingLBottom = LBottom;
NSPoint CP_DepartingBLeftForBCenter = BLeft;
NSPoint CP_ApproachingBCenter = NSMakePoint(BCenter.x - (BCenter.x - BLeft.x) * SIDE_CENTER_CP_OFFSET, BCenter.y);
NSPoint CP_DepartingBCenterForBRight = NSMakePoint(BCenter.x + (BRight.x - BCenter.x) * SIDE_CENTER_CP_OFFSET, BCenter.y);
NSPoint CP_ApproachingBRight = BRight;
NSPoint CP_DepartingRBottomForRCenter = RBottom;
NSPoint CP_ApproachingRCenterFromRBottom = NSMakePoint(RCenter.x, RCenter.y + (RBottom.y - RCenter.y) * SIDE_CENTER_CP_OFFSET);
NSPoint CP_DepartingRCenterForRTop = NSMakePoint(RCenter.x, RCenter.y - (RCenter.y - RTop.y) * SIDE_CENTER_CP_OFFSET);
NSPoint CP_ApproachingRTopFromRCenter = RTop;
NSPoint CP_DepartingTRightForTCenter = TRight;
NSPoint CP_ApproachingTCenterFromTRight = NSMakePoint(TCenter.x + (TRight.x - TCenter.x) * SIDE_CENTER_CP_OFFSET, TCenter.y);
// Draw the bloody square
NSBezierPath *p = [[NSBezierPath alloc] init];
[p moveToPoint:TCenter];
[p curveToPoint:TLeft controlPoint1:CP_DepartingTCenterForTLeft controlPoint2:CP_ApproachingTLeft];
[p curveToPoint:LTop controlPoint1:CP_TLeft controlPoint2:CP_LTop];
[p curveToPoint:LCenter controlPoint1:CP_DepartingLTopForLCenter controlPoint2:CP_ApproachingLCenterFromLTop];
[p curveToPoint:LBottom controlPoint1:CP_DepartingLCenterForLBottom controlPoint2:CP_ApproachingLBottom];
[p curveToPoint:BLeft controlPoint1:CP_LBottom controlPoint2:CP_BLeft];
[p curveToPoint:BCenter controlPoint1:CP_DepartingBLeftForBCenter controlPoint2:CP_ApproachingBCenter];
[p curveToPoint:BRight controlPoint1:CP_DepartingBCenterForBRight controlPoint2:CP_ApproachingBRight];
[p curveToPoint:RBottom controlPoint1:CP_BRight controlPoint2:CP_RBottom];
[p curveToPoint:RCenter controlPoint1:CP_DepartingRBottomForRCenter controlPoint2:CP_ApproachingRCenterFromRBottom];
[p curveToPoint:RTop controlPoint1:CP_DepartingRCenterForRTop controlPoint2:CP_ApproachingRTopFromRCenter];
[p curveToPoint:TRight controlPoint1:CP_RTop controlPoint2:CP_TRight];
[p curveToPoint:TCenter controlPoint1:CP_DepartingTRightForTCenter controlPoint2:CP_ApproachingTCenterFromTRight];
[p closePath];
_path = p;
}
// We want a slightly white drop shadow on the stroke and fill, giving our square some sense of depth.
[_shadow set];
[[NSColor blackColor] set];
[_path fill];
// Clip to the bezier path and draw a fill image inside of it.
[currentContext saveGraphicsState];
[_path addClip];
[image drawInRect:frame fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0f respectFlipped:YES hints:nil];
if (self.isHighlighted)
{
// If we're clicked, draw a 50% black overlay to show that
NSColor *overColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.5];
[overColor set];
[_path fill];
}
[currentContext restoreGraphicsState];
// Stroke the square to create a nice border with a drop shadow at top and bottom.
[_borderColor set];
[_path stroke];
}
@end
关于objective-c - NSBezierPath:创建一个 "curved"正方形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14918396/
我遵循了一本名为“Sitepoint Full Stack Javascript with MEAN”的书中的教程,我刚刚完成了第 6 章,应该已经创建了一个带有“数据库”的“服务器”。数据库只不过是
在 Jquery 中,我创建两个数组,一个嵌入另一个数组,就像这样...... arrayOne = [{name:'a',value:1}, {name:'b',value:2}] var arra
这个问题在这里已经有了答案: What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wa
我被放在别人的代码上,有一个类用作其他组件的基础。当我尝试 ng serve --aot(或 build --prod)时,我得到以下信息。 @Component({ ...,
我正在测试一些代码,并使用数据创建了一个 json 文件。 问题是我在警报中收到“[object Object],[object Object]”。没有数据。 我做错了什么? 这是代码:
我想打印 [object Object],[object Object] 以明智地 "[[{ 'x': '1', 'y': '0' }, { 'x': '2', 'y': '1' }]]"; 在 ja
我有一个功能 View ,我正在尝试以特殊格式的方式输出。但我无法让列表功能正常工作。 我得到的唯一返回是[object Object][object Object] [object Object]
在使用优秀的 Sim.js 和 Three.js 库处理 WebGL 项目时,我偶然发现了下一个问题: 一路走来,它使用了 THREE.Ray 的下一个构造函数: var ray = new THRE
我正在使用 Material UI 进行多重选择。这是我的代码。 {listStates.map(col => (
我的代码使用ajax: $("#keyword").keyup(function() { var keyword = $("#keyword").val(); if (keyword.
我遇到了下一个错误,无法理解如何解决它。 Can't resolve all parameters for AuthenticationService: ([object Object], ?, [o
我正在尝试创建一个显示动态复选框的表单,至少应选中其中一个才能继续。我还需要获取一组选中的复选框。 这是组件的代码: import { Component, OnInit } from '@angul
我正在开发 NodeJs 应用程序,它是博客应用程序。我使用了快速验证器,我尝试在 UI 端使用快速闪存消息将帖子保存在数据库中之前使用闪存消息验证数据,我成功地将数据保存在数据库中,但在提交表单后消
我知道有些人问了同样的问题并得到了解答。我已经查看了所有这些,但仍然无法解决我的问题。我有一个 jquery snipet,它将值发送到处理程序,处理程序处理来自 JS 的值并将数据作为 JSON 数
我继承了一个非常草率的项目,我的任务是解释为什么它不好。我注意到他们在整个代码中都进行了这样的比较 (IQueryable).FirstOrDefault(x => x.Facility == fac
我只是在删除数组中的对象时偶然发现了这一点。 代码如下: friends = []; friends.push( { a: 'Nexus', b: 'Muffi
这两个代码片段有什么区别: object = nil; [object release] 对比 [object release]; object = nil; 哪个是最佳实践? 最佳答案 object
我应该为其他人将从中继承的第一个父对象传递哪个参数,哪个参数更有效 Object.create(Object.prototype) Object.create(Object) Object.creat
我在不同的对象上安排不同的选择器 [self performSelector:@selector(doSmth) withObject:objectA afterDelay:1]; [self per
NSLog(@"%p", &object); 和 NSLog(@"%p", object); 有什么区别? 两者似乎都打印出一个内存地址,但我不确定哪个是对象的实际内存地址。 最佳答案 这就是我喜欢的
我是一名优秀的程序员,十分优秀!