зеркало из https://github.com/mozilla/moz-skia.git
add lineclipper, and test case
git-svn-id: http://skia.googlecode.com/svn/trunk@427 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
e72fee513a
Коммит
70149060a7
|
@ -0,0 +1,29 @@
|
|||
#ifndef SkLineClipper_DEFINED
|
||||
#define SkLineClipper_DEFINED
|
||||
|
||||
#include "SkRect.h"
|
||||
#include "SkPoint.h"
|
||||
|
||||
class SkLineClipper {
|
||||
public:
|
||||
enum {
|
||||
kMaxPoints = 4
|
||||
};
|
||||
|
||||
/* Clip the line pts[0]...pts[1] against clip, ignoring segments that
|
||||
lie completely above or below the clip. For portions to the left or
|
||||
right, turn those into vertical line segments that are aligned to the
|
||||
edge of the clip.
|
||||
|
||||
Return the number of line segments that result, and store the end-points
|
||||
of those segments sequentially in lines as follows:
|
||||
1st segment: lines[0]..lines[1]
|
||||
2nd segment: lines[1]..lines[2]
|
||||
3rd segment: lines[2]..lines[3]
|
||||
*/
|
||||
static int ClipLine(const SkPoint pts[2], const SkRect& clip,
|
||||
SkPoint lines[kMaxPoints]);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
#include "SampleCode.h"
|
||||
#include "SkView.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkGraphics.h"
|
||||
#include "SkImageDecoder.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkShader.h"
|
||||
#include "SkUtils.h"
|
||||
#include "SkXfermode.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkColorFilter.h"
|
||||
#include "SkTime.h"
|
||||
#include "SkRandom.h"
|
||||
#include "SkLineClipper.h"
|
||||
|
||||
enum {
|
||||
W = 640/4,
|
||||
H = 480/4
|
||||
};
|
||||
|
||||
class LineClipperView : public SkView {
|
||||
SkRect fClip;
|
||||
SkRandom fRand;
|
||||
SkPoint fPts[2];
|
||||
|
||||
void randPts() {
|
||||
fPts[0].set(fRand.nextUScalar1() * 640, fRand.nextUScalar1() * 480);
|
||||
fPts[1].set(fRand.nextUScalar1() * 640, fRand.nextUScalar1() * 480);
|
||||
}
|
||||
|
||||
public:
|
||||
LineClipperView() {
|
||||
int x = (640 - W)/2;
|
||||
int y = (480 - H)/2;
|
||||
fClip.set(x, y, x + W, y + H);
|
||||
this->randPts();
|
||||
}
|
||||
|
||||
protected:
|
||||
// overrides from SkEventSink
|
||||
virtual bool onQuery(SkEvent* evt) {
|
||||
if (SampleCode::TitleQ(*evt)) {
|
||||
SampleCode::TitleR(evt, "LineClipper");
|
||||
return true;
|
||||
}
|
||||
return this->INHERITED::onQuery(evt);
|
||||
}
|
||||
|
||||
void drawBG(SkCanvas* canvas) {
|
||||
canvas->drawColor(SK_ColorWHITE);
|
||||
}
|
||||
|
||||
static void drawVLine(SkCanvas* canvas, SkScalar x, const SkPaint& paint) {
|
||||
canvas->drawLine(x, -999, x, 999, paint);
|
||||
}
|
||||
|
||||
static void drawHLine(SkCanvas* canvas, SkScalar y, const SkPaint& paint) {
|
||||
canvas->drawLine(-999, y, 999, y, paint);
|
||||
}
|
||||
|
||||
static void check_lineclipper(int count, const SkPoint pts[],
|
||||
const SkRect& clip) {
|
||||
if (count > 0) {
|
||||
for (int i = 0; i <= count; i++) {
|
||||
SkASSERT(pts[i].fX >= clip.fLeft);
|
||||
SkASSERT(pts[i].fX <= clip.fRight);
|
||||
SkASSERT(pts[i].fY >= clip.fTop);
|
||||
SkASSERT(pts[i].fY <= clip.fBottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
this->drawBG(canvas);
|
||||
|
||||
SkPaint paint;
|
||||
|
||||
drawVLine(canvas, fClip.fLeft + SK_ScalarHalf, paint);
|
||||
drawVLine(canvas, fClip.fRight - SK_ScalarHalf, paint);
|
||||
drawHLine(canvas, fClip.fTop + SK_ScalarHalf, paint);
|
||||
drawHLine(canvas, fClip.fBottom - SK_ScalarHalf, paint);
|
||||
|
||||
paint.setColor(SK_ColorLTGRAY);
|
||||
canvas->drawRect(fClip, paint);
|
||||
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
paint.setStrokeWidth(SkIntToScalar(3));
|
||||
paint.setStrokeCap(SkPaint::kRound_Cap);
|
||||
SkPoint pts[SkLineClipper::kMaxPoints];
|
||||
int count = SkLineClipper::ClipLine(fPts, fClip, pts);
|
||||
check_lineclipper(count, pts, fClip);
|
||||
for (int i = 0; i < count; i++) {
|
||||
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, &pts[i], paint);
|
||||
}
|
||||
|
||||
paint.setColor(SK_ColorRED);
|
||||
paint.setStrokeWidth(0);
|
||||
canvas->drawPoints(SkCanvas::kLines_PointMode, 2, fPts, paint);
|
||||
|
||||
if (true) {
|
||||
this->randPts();
|
||||
this->inval(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
|
||||
this->randPts();
|
||||
this->inval(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual bool onClick(Click* click) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef SkView INHERITED;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkView* MyFactory() { return new LineClipperView; }
|
||||
static SkViewRegister reg(MyFactory);
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
#include "SkLineClipper.h"
|
||||
|
||||
// return X coordinate of intersection with horizontal line at Y
|
||||
static SkScalar sect_with_horizontal(const SkPoint src[2], SkScalar Y) {
|
||||
SkScalar dy = src[1].fY - src[0].fY;
|
||||
if (SkScalarNearlyZero(dy)) {
|
||||
return SkScalarAve(src[0].fX, src[1].fX);
|
||||
} else {
|
||||
return src[0].fX + SkScalarMulDiv(Y - src[0].fY, src[1].fX - src[0].fX,
|
||||
dy);
|
||||
}
|
||||
}
|
||||
|
||||
// return Y coordinate of intersection with vertical line at X
|
||||
static SkScalar sect_with_vertical(const SkPoint src[2], SkScalar X) {
|
||||
SkScalar dx = src[1].fX - src[0].fX;
|
||||
if (SkScalarNearlyZero(dx)) {
|
||||
return SkScalarAve(src[0].fY, src[1].fY);
|
||||
} else {
|
||||
return src[0].fY + SkScalarMulDiv(X - src[0].fX, src[1].fY - src[0].fY,
|
||||
dx);
|
||||
}
|
||||
}
|
||||
|
||||
int SkLineClipper::ClipLine(const SkPoint pts[], const SkRect& clip,
|
||||
SkPoint lines[]) {
|
||||
int index0, index1;
|
||||
|
||||
if (pts[0].fY < pts[1].fY) {
|
||||
index0 = 0;
|
||||
index1 = 1;
|
||||
} else {
|
||||
index0 = 1;
|
||||
index1 = 0;
|
||||
}
|
||||
|
||||
// Check if we're completely clipped out in Y (above or below
|
||||
|
||||
if (pts[index1].fY <= clip.fTop) { // we're above the clip
|
||||
return 0;
|
||||
}
|
||||
if (pts[index0].fY >= clip.fBottom) { // we're below the clip
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Chop in Y to produce a single segment, stored in tmp[0..1]
|
||||
|
||||
SkPoint tmp[2];
|
||||
memcpy(tmp, pts, sizeof(tmp));
|
||||
|
||||
// now compute intersections
|
||||
if (pts[index0].fY < clip.fTop) {
|
||||
tmp[index0].set(sect_with_horizontal(pts, clip.fTop), clip.fTop);
|
||||
}
|
||||
if (tmp[index1].fY > clip.fBottom) {
|
||||
tmp[index1].set(sect_with_horizontal(pts, clip.fBottom), clip.fBottom);
|
||||
}
|
||||
|
||||
// Chop it into 1..3 segments that are wholly within the clip in X.
|
||||
|
||||
// temp storage for up to 3 segments
|
||||
SkPoint resultStorage[kMaxPoints];
|
||||
SkPoint* result; // points to our results, either tmp or resultStorage
|
||||
int lineCount = 1;
|
||||
|
||||
if (pts[0].fX < pts[1].fX) {
|
||||
index0 = 0;
|
||||
index1 = 1;
|
||||
} else {
|
||||
index0 = 1;
|
||||
index1 = 0;
|
||||
}
|
||||
|
||||
if (tmp[index1].fX <= clip.fLeft) { // wholly to the left
|
||||
tmp[0].fX = tmp[1].fX = clip.fLeft;
|
||||
result = tmp;
|
||||
} else if (tmp[index0].fX >= clip.fRight) { // wholly to the right
|
||||
tmp[0].fX = tmp[1].fX = clip.fRight;
|
||||
result = tmp;
|
||||
} else {
|
||||
result = resultStorage;
|
||||
SkPoint* r = result;
|
||||
|
||||
if (tmp[index0].fX < clip.fLeft) {
|
||||
r->set(clip.fLeft, tmp[index0].fY);
|
||||
r += 1;
|
||||
r->set(clip.fLeft, sect_with_vertical(pts, clip.fLeft));
|
||||
} else {
|
||||
*r = tmp[index0];
|
||||
}
|
||||
r += 1;
|
||||
|
||||
if (tmp[index1].fX > clip.fRight) {
|
||||
r->set(clip.fRight, sect_with_vertical(pts, clip.fRight));
|
||||
r += 1;
|
||||
r->set(clip.fRight, tmp[index1].fY);
|
||||
} else {
|
||||
*r = tmp[index1];
|
||||
}
|
||||
|
||||
lineCount = r - result;
|
||||
}
|
||||
|
||||
// Now copy the results into the caller's lines[] parameter
|
||||
if (0 == index1) {
|
||||
// copy the pts in reverse order to maintain winding order
|
||||
for (int i = 0; i <= lineCount; i++) {
|
||||
lines[lineCount - i] = result[i];
|
||||
}
|
||||
} else {
|
||||
memcpy(lines, result, (lineCount + 1) * sizeof(SkPoint));
|
||||
}
|
||||
return lineCount;
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче