framework2

Форк
0
908 строк · 27.5 Кб
1
#include "ofPath.h"
2
#include "ofColor.h"
3

4
using std::vector;
5

6
#if defined(TARGET_EMSCRIPTEN)
7
	ofTessellator ofPath::tessellator;
8
#elif HAS_TLS
9
    thread_local ofTessellator ofPath::tessellator;
10
#endif
11

12
ofPath::Command::Command(Type type)
13
:type(type){
14

15
}
16

17
//----------------------------------------------------------
18
ofPath::Command::Command(Type type , const glm::vec3 & p)
19
:type(type)
20
,to(p)
21
,cp1(glm::vec3(0))
22
,cp2(glm::vec3(0))
23
,radiusX(0)
24
,radiusY(0)
25
,angleBegin(0)
26
,angleEnd(0)
27
{}
28

29
//----------------------------------------------------------
30
ofPath::Command::Command(Type type , const glm::vec3 & p, const glm::vec3 & cp1, const glm::vec3 & cp2)
31
:type(type)
32
,to(p)
33
,cp1(cp1)
34
,cp2(cp2)
35
,radiusX(0)
36
,radiusY(0)
37
,angleBegin(0)
38
,angleEnd(0)
39
{
40
}
41

42
//----------------------------------------------------------
43
ofPath::Command::Command(Type type , const glm::vec3 & centre, float radiusX, float radiusY, float angleBegin, float angleEnd)
44
:type(type)
45
,to(centre)
46
,cp1(glm::vec3(0))
47
,cp2(glm::vec3(0))
48
,radiusX(radiusX)
49
,radiusY(radiusY)
50
,angleBegin(angleBegin)
51
,angleEnd(angleEnd)
52
{
53
}
54

55
//----------------------------------------------------------
56
ofPath::ofPath(){
57
	strokeWidth = 0;
58
	bFill = true;
59
	windingMode = OF_POLY_WINDING_ODD;
60
	prevCurveRes = 20;
61
	curveResolution = 20;
62
	circleResolution = 20;
63
	mode = COMMANDS;
64
	bNeedsTessellation = false;
65
	bHasChanged = false;
66
	bUseShapeColor = true;
67
	bNeedsPolylinesGeneration = false;
68
	clear();
69
}
70

71
//----------------------------------------------------------
72
void ofPath::clear(){
73
	commands.clear();
74
	// for performance, instead of clearing the whole vector
75
	// let one polyline and clear it: avoids instantiation
76
	polylines.resize(1);
77
	polylines[0].clear();
78
	cachedTessellation.clear();
79
	flagShapeChanged();
80
}
81

82
//----------------------------------------------------------
83
void ofPath::newSubPath(){
84
	if(mode==COMMANDS){
85
	}else{
86
		polylines.push_back(ofPolyline());
87
	}
88
}
89

90
//----------------------------------------------------------
91
void ofPath::lineTo(const glm::vec3 & p){
92
	if(mode==COMMANDS){
93
		addCommand(Command(Command::lineTo,p));
94
	}else{
95
		lastPolyline().lineTo(p);
96
	}
97
	flagShapeChanged();
98
}
99

100
//----------------------------------------------------------
101
void ofPath::lineTo(const glm::vec2 & p){
102
	lineTo(glm::vec3(p,0.0));
103
}
104

105
//----------------------------------------------------------
106
void ofPath::lineTo(float x, float y, float z){
107
	lineTo(glm::vec3(x,y,z));
108
}
109

110
//----------------------------------------------------------
111
void ofPath::lineTo(float x, float y){
112
	lineTo(glm::vec3(x,y,0));
113
}
114

115
//----------------------------------------------------------
116
void ofPath::moveTo(const glm::vec3 & p){
117
	if(mode==COMMANDS){
118
		addCommand(Command(Command::moveTo,p));
119
	}else{
120
		if(lastPolyline().size()>0) newSubPath();
121
		lastPolyline().addVertex(p);
122
	}
123
	flagShapeChanged();
124
}
125

126
//----------------------------------------------------------
127
void ofPath::moveTo(const glm::vec2 & p){
128
	moveTo(glm::vec3(p, 0.0));
129
}
130

131
//----------------------------------------------------------
132
void ofPath::moveTo(float x, float y, float z){
133
	moveTo(glm::vec3(x,y,z));
134
}
135

136
//----------------------------------------------------------
137
void ofPath::curveTo(const glm::vec3 & p){
138
	if(mode==COMMANDS){
139
		addCommand(Command(Command::curveTo,p));
140
	}else{
141
		lastPolyline().curveTo(p,curveResolution);
142
	}
143
	flagShapeChanged();
144
}
145

146
//----------------------------------------------------------
147
void ofPath::curveTo(const glm::vec2 & p){
148
	curveTo(glm::vec3(p, 0.0));
149
}
150

151
//----------------------------------------------------------
152
void ofPath::curveTo(float x, float y, float z){
153
	curveTo(glm::vec3(x,y,z));
154
}
155

156
//----------------------------------------------------------
157
void ofPath::curveTo(float x, float y){
158
	curveTo(glm::vec3(x,y,0));
159
}
160

161
//----------------------------------------------------------
162
void ofPath::bezierTo(const glm::vec3 & cp1, const glm::vec3 & cp2, const glm::vec3 & p){
163
	if(mode==COMMANDS){
164
		addCommand(Command(Command::bezierTo,p,cp1,cp2));
165
	}else{
166
		lastPolyline().bezierTo(cp1,cp2,p,curveResolution);
167
	}
168
	flagShapeChanged();
169
}
170

171
//----------------------------------------------------------
172
void ofPath::bezierTo(const glm::vec2 & cp1, const glm::vec2 & cp2, const glm::vec2 & p){
173
	bezierTo(glm::vec3(cp1,0.0), glm::vec3(cp2,0.0), glm::vec3(p,0.0));
174
}
175

176
//----------------------------------------------------------
177
void ofPath::bezierTo(float cx1, float cy1, float cx2, float cy2, float x, float y){
178
	bezierTo(glm::vec3(cx1,cy1,0),glm::vec3(cx2,cy2,0),glm::vec3(x,y,0));
179
}
180

181
//----------------------------------------------------------
182
void ofPath::bezierTo(float cx1, float cy1, float cz1, float cx2, float cy2, float cz2, float x, float y, float z){
183
	bezierTo(glm::vec3(cx1,cy1,cz1),glm::vec3(cx2,cy2,cz2),glm::vec3(x,y,z));
184
}
185

186
//----------------------------------------------------------
187
void ofPath::quadBezierTo(const glm::vec3 & cp1, const glm::vec3 & cp2, const glm::vec3 & p){
188
	if(mode==COMMANDS){
189
		addCommand(Command(Command::quadBezierTo,p,cp1,cp2));
190
	}else{
191
		lastPolyline().quadBezierTo(cp1,cp2,p,curveResolution);
192
	}
193
	flagShapeChanged();
194
}
195

196
//----------------------------------------------------------
197
void ofPath::quadBezierTo(const glm::vec2 & cp1, const glm::vec2 & cp2, const glm::vec2 & p){
198
	quadBezierTo(glm::vec3(cp1, 0.0), glm::vec3(cp2, 0.0), glm::vec3(p, 0.0));
199
}
200

201
//----------------------------------------------------------
202
void ofPath::quadBezierTo(float cx1, float cy1, float cx2, float cy2, float x, float y){
203
	quadBezierTo(glm::vec3(cx1,cy1,0),glm::vec3(cx2,cy2,0),glm::vec3(x,y,0));
204
}
205

206
//----------------------------------------------------------
207
void ofPath::quadBezierTo(float cx1, float cy1, float cz1, float cx2, float cy2, float cz2, float x, float y, float z){
208
	quadBezierTo(glm::vec3(cx1,cy1,cz1),glm::vec3(cx2,cy2,cz2),glm::vec3(x,y,z));
209
}
210

211
//----------------------------------------------------------
212
void ofPath::arc(const glm::vec3 & centre, float radiusX, float radiusY, float angleBegin, float angleEnd, bool clockwise){
213
    if(clockwise) {
214
        arc(centre,radiusX,radiusY,angleBegin,angleEnd);
215
    } else {
216
        arcNegative(centre,radiusX,radiusY,angleBegin,angleEnd);
217
    }
218
}
219

220
//----------------------------------------------------------
221
void ofPath::arc(const glm::vec2 & centre, float radiusX, float radiusY, float angleBegin, float angleEnd, bool clockwise){
222
	arc(glm::vec3(centre, 0.0), radiusX, radiusY, angleBegin, angleEnd, clockwise);
223
}
224

225
//----------------------------------------------------------
226
void ofPath::arc(const glm::vec3 & centre, float radiusX, float radiusY, float angleBegin, float angleEnd){
227
	if(mode==COMMANDS){
228
		//addCommand adds a moveTo if one hasn't been set, but in this case it is adding a moveTo to the center of the arc and not the beginning of the arc
229
		if(commands.empty() || commands.back().type==Command::close){
230
			glm::vec3 start = centre + glm::vec3( glm::cos( glm::radians(angleBegin) ) * radiusX, glm::sin( glm::radians(angleBegin) ) * radiusY, 0.0f );
231
			commands.push_back(Command(Command::moveTo,start));
232
		}
233
		addCommand(Command(Command::arc,centre,radiusX,radiusY,angleBegin,angleEnd));
234
	}else{
235
		lastPolyline().arc(centre,radiusX,radiusY,angleBegin,angleEnd,circleResolution);
236
	}
237
	flagShapeChanged();
238
}
239

240
//----------------------------------------------------------
241
void ofPath::arc(const glm::vec2 & centre, float radiusX, float radiusY, float angleBegin, float angleEnd){
242
	arc(glm::vec3(centre, 0.0), radiusX, radiusY, angleBegin, angleEnd);
243
}
244

245
//----------------------------------------------------------
246
void ofPath::arc(float x, float y, float radiusX, float radiusY, float angleBegin, float angleEnd){
247
	arc(glm::vec3(x,y,0),radiusX,radiusY,angleBegin,angleEnd);
248
}
249

250
//----------------------------------------------------------
251
void ofPath::arc(float x, float y, float z, float radiusX, float radiusY, float angleBegin, float angleEnd){
252
	arc(glm::vec3(x,y,z),radiusX,radiusY,angleBegin,angleEnd);
253
}
254

255
//----------------------------------------------------------
256
void ofPath::arcNegative(const glm::vec3 & centre, float radiusX, float radiusY, float angleBegin, float angleEnd){
257
	if(mode==COMMANDS){
258
		if(commands.empty() || commands.back().type==Command::close){
259
			glm::vec3 start = centre + glm::vec3( glm::cos( glm::radians(angleBegin) ) * radiusX, glm::sin( glm::radians(angleBegin) ) * radiusY, 0.0f );
260
			commands.push_back(Command(Command::moveTo,start));
261
		}
262
		addCommand(Command(Command::arcNegative,centre,radiusX,radiusY,angleBegin,angleEnd));
263
	}else{
264
		lastPolyline().arcNegative(centre,radiusX,radiusY,angleBegin,angleEnd,circleResolution);
265
	}
266
	flagShapeChanged();
267
}
268

269
//----------------------------------------------------------
270
void ofPath::arcNegative(const glm::vec2 & centre, float radiusX, float radiusY, float angleBegin, float angleEnd){
271
	arcNegative(glm::vec3(centre,0),radiusX,radiusY,angleBegin,angleEnd);
272
}
273

274
//----------------------------------------------------------
275
void ofPath::arcNegative(float x, float y, float radiusX, float radiusY, float angleBegin, float angleEnd){
276
	arcNegative(glm::vec3(x,y,0),radiusX,radiusY,angleBegin,angleEnd);
277
}
278

279
//----------------------------------------------------------
280
void ofPath::arcNegative(float x, float y, float z, float radiusX, float radiusY, float angleBegin, float angleEnd){
281
	arcNegative(glm::vec3(x,y,z),radiusX,radiusY,angleBegin,angleEnd);
282
}
283

284
//----------------------------------------------------------
285
void ofPath::triangle(float x1,float y1,float x2,float y2,float x3, float y3){
286
	triangle(x1,y1,0.0f,x2,y2,0.0f,x3,y3,0.0f);
287
}
288

289
//----------------------------------------------------------
290
void ofPath::triangle(float x1,float y1,float z1,float x2,float y2,float z2,float x3, float y3,float z3){
291
	moveTo(x1,y1,z1);
292
	lineTo(x2,y2,z2);
293
	lineTo(x3,y3,z3);
294
	close();
295
}
296

297
//----------------------------------------------------------
298
void ofPath::triangle(const glm::vec3 & p1, const glm::vec3 & p2, const glm::vec3 & p3){
299
	triangle(p1.x,p1.y,p1.z,p2.x,p2.y,p2.z,p3.x,p3.y,p3.z);
300
}
301

302
//----------------------------------------------------------
303
void ofPath::triangle(const glm::vec2 & p1, const glm::vec2 & p2, const glm::vec2 & p3){
304
	triangle(p1.x,p1.y,0.0,p2.x,p2.y,0.0,p3.x,p3.y,0.0);
305
}
306

307

308
//----------------------------------------------------------
309
void ofPath::circle(float x, float y, float radius){
310
	circle(x,y,0.0f,radius);
311
}
312

313
//----------------------------------------------------------
314
void ofPath::circle(float x, float y, float z, float radius){
315
	moveTo(x + radius, y, z);
316
	arc(x,y,z,radius,radius,0,360);
317
}
318

319
//----------------------------------------------------------
320
void ofPath::circle(const glm::vec3 & p, float radius){
321
	circle(p.x,p.y,p.z,radius);
322
}
323

324
//----------------------------------------------------------
325
void ofPath::circle(const glm::vec2 & p, float radius){
326
	circle(p.x,p.y,0.0,radius);
327
}
328

329

330
//----------------------------------------------------------
331
void ofPath::ellipse(float x, float y, float width, float height){
332
	ellipse(x,y,0.0f,width,height);
333
}
334

335
//----------------------------------------------------------
336
void ofPath::ellipse(float x, float y, float z, float width, float height){
337
	arc(x,y,z,width*.5f,height*.5f,0,360);
338
}
339

340
//----------------------------------------------------------
341
void ofPath::ellipse(const glm::vec3 & p, float width, float height){
342
	ellipse(p.x,p.y,p.z,width,height);
343
}
344

345
//----------------------------------------------------------
346
void ofPath::ellipse(const glm::vec2 & p, float width, float height){
347
	ellipse(p.x,p.y,0.0,width,height);
348
}
349

350
//----------------------------------------------------------
351
void ofPath::rectangle(const ofRectangle & r){
352
	moveTo(r.getTopLeft());
353
	lineTo(r.getTopRight());
354
	lineTo(r.getBottomRight());
355
	lineTo(r.getBottomLeft());
356
	close();
357
}
358

359
//----------------------------------------------------------
360
void ofPath::rectangle(const glm::vec3 & p,float w,float h){
361
	moveTo(p);
362
	lineTo(p.x+w,p.y,p.z);
363
	lineTo(p.x+w,p.y+h,p.z);
364
	lineTo(p.x,p.y+h,p.z);
365
	close();
366
}
367

368
//----------------------------------------------------------
369
void ofPath::rectangle(const glm::vec2 & p,float w,float h){
370
	rectangle(glm::vec3(p,0.0), w, h);
371
}
372

373
//----------------------------------------------------------
374
void ofPath::rectangle(float x,float y,float w,float h){
375
	moveTo(x,y);
376
	lineTo(x+w,y);
377
	lineTo(x+w,y+h);
378
	lineTo(x,y+h);
379
	close();
380
}
381

382
//----------------------------------------------------------
383
void ofPath::rectangle(float x,float y,float z,float w,float h){
384
	moveTo(x,y,z);
385
	lineTo(x+w,y,z);
386
	lineTo(x+w,y+h,z);
387
	lineTo(x,y+h,z);
388
	close();
389
}
390

391
//----------------------------------------------------------
392
void ofPath::rectRounded(const ofRectangle & b, float r){
393
	rectRounded(b.x,b.y,0,b.width,b.height,r,r,r,r);
394
}
395

396
//----------------------------------------------------------
397
void ofPath::rectRounded(const glm::vec3 & p, float w, float h, float r){
398
	rectRounded(p.x,p.y,p.z,w,h,r,r,r,r);
399
}
400

401
//----------------------------------------------------------
402
void ofPath::rectRounded(const glm::vec2 & p, float w, float h, float r){
403
	rectRounded(p.x,p.y,0.0,w,h,r,r,r,r);
404
}
405

406
//----------------------------------------------------------
407
void ofPath::rectRounded(float x, float y, float w, float h, float r){
408
	rectRounded(x,y,0.0f,w,h,r,r,r,r);
409
}
410

411
//----------------------------------------------------------
412
void ofPath::rectRounded(const glm::vec3 & p, float w, float h, float topLeftRadius,
413
														float topRightRadius,
414
														float bottomRightRadius,
415
														float bottomLeftRadius){
416

417
	rectRounded(p.x,p.y,p.z,w,h,topLeftRadius,topRightRadius,bottomRightRadius,bottomLeftRadius);
418
}
419

420
//----------------------------------------------------------
421
void ofPath::rectRounded(const glm::vec2 & p, float w, float h, float topLeftRadius,
422
														float topRightRadius,
423
														float bottomRightRadius,
424
														float bottomLeftRadius){
425

426
	rectRounded(p.x,p.y,0.0,w,h,topLeftRadius,topRightRadius,bottomRightRadius,bottomLeftRadius);
427
}
428

429
//----------------------------------------------------------
430
void ofPath::rectRounded(const ofRectangle & b, float topLeftRadius,
431
										  float topRightRadius,
432
										  float bottomRightRadius,
433
										  float bottomLeftRadius){
434
	rectRounded(b.x,b.y,0,b.width,b.height,topLeftRadius,topRightRadius,bottomRightRadius,bottomLeftRadius);
435
}
436

437
//----------------------------------------------------------
438
void ofPath::rectRounded(float x, float y, float z, float w, float h, float topLeftRadius,
439
												  float topRightRadius,
440
												  float bottomRightRadius,
441
												  float bottomLeftRadius){
442
	// since we support w / h < 0, canonicalize the rectangle for easier drawing
443
	if(w < 0.0f) {
444
		x += w;
445
		w *= -1.0f;
446
	}
447

448
	if(h < 0.0f) {
449
		y += h;
450
		h *= -1.0f;
451
	}
452

453
	// keep radii in check
454
	float maxRadius = std::min(w / 2.0f, h / 2.0f);
455
	topLeftRadius        = std::min(topLeftRadius,     maxRadius);
456
	topRightRadius       = std::min(topRightRadius,    maxRadius);
457
	bottomRightRadius    = std::min(bottomRightRadius, maxRadius);
458
	bottomLeftRadius     = std::min(bottomLeftRadius,  maxRadius);
459

460
	// if all radii are ~= 0.0f, then render as a normal rectangle
461
	if((fabs(topLeftRadius)     < std::numeric_limits<float>::epsilon()) &&
462
	   (fabs(topRightRadius)    < std::numeric_limits<float>::epsilon()) &&
463
	   (fabs(bottomRightRadius) < std::numeric_limits<float>::epsilon()) &&
464
	   (fabs(bottomLeftRadius)  < std::numeric_limits<float>::epsilon())) {
465

466
		// rect mode respect happens in ofRect
467
		rectangle(x, y, z, w, h);
468
	} else {
469
		float left   = x;
470
		float right  = x + w;
471
		float top    = y;
472
		float bottom = y + h;
473

474

475
		moveTo(left + topLeftRadius, top, z);
476

477
		// top right
478
		if(fabs(topRightRadius) >= std::numeric_limits<float>::epsilon()) {
479
			arc(right - topRightRadius, top + topRightRadius, z, topRightRadius, topRightRadius, 270, 360);
480
		} else {
481
			lineTo(right, top, z);
482
		}
483

484
		lineTo(right, bottom - bottomRightRadius);
485
		// bottom right
486
		if(fabs(bottomRightRadius) >= std::numeric_limits<float>::epsilon()) {
487
			arc(right - bottomRightRadius, bottom - bottomRightRadius, z, bottomRightRadius, bottomRightRadius, 0, 90);
488
		}
489

490
		lineTo(left + bottomLeftRadius, bottom, z);
491

492
		// bottom left
493
		if(fabs(bottomLeftRadius) >= std::numeric_limits<float>::epsilon()) {
494
			arc(left + bottomLeftRadius, bottom - bottomLeftRadius, z, bottomLeftRadius, bottomLeftRadius, 90, 180);
495
		}
496

497
		lineTo(left, top + topLeftRadius, z);
498

499
		// top left
500
		if(fabs(topLeftRadius) >= std::numeric_limits<float>::epsilon()) {
501
			arc(left + topLeftRadius, top + topLeftRadius, z, topLeftRadius, topLeftRadius, 180, 270);
502
		}
503
		close();
504

505
	}
506
}
507

508
//----------------------------------------------------------
509
void ofPath::close(){
510
	if(mode==COMMANDS){
511
		addCommand(Command(Command::close));
512
	}else{
513
		lastPolyline().setClosed(true);
514
	}
515
	flagShapeChanged();
516
}
517

518
//----------------------------------------------------------
519
void ofPath::setPolyWindingMode(ofPolyWindingMode newMode){
520
	if(windingMode != newMode){
521
		windingMode = newMode;
522
		bNeedsTessellation = true;
523
	}
524
}
525

526
//----------------------------------------------------------
527
void ofPath::setFilled(bool hasFill){
528
	if(bFill != hasFill){
529
		bFill = hasFill;
530
		bNeedsTessellation = true;
531
	}
532
}
533

534
//----------------------------------------------------------
535
void ofPath::setStrokeWidth(float width){
536
	strokeWidth = width;
537
}
538

539
//----------------------------------------------------------
540
ofPolyline & ofPath::lastPolyline(){
541
	if(polylines.empty() || polylines.back().isClosed()){
542
		polylines.push_back(ofPolyline());
543
	}
544
	return polylines.back();
545
}
546

547
//----------------------------------------------------------
548
vector<ofPath::Command> & ofPath::getCommands(){
549
	if(mode==POLYLINES){
550
		ofLogWarning("ofPath") << "getCommands(): trying to get path commands from shape with polylines only";
551
	}else{
552
		flagShapeChanged();
553
	}
554
	return commands;
555
}
556

557
//----------------------------------------------------------
558
const vector<ofPath::Command> & ofPath::getCommands() const{
559
	if(mode==POLYLINES){
560
		ofLogWarning("ofPath") << "getCommands(): trying to get path commands from shape with polylines only";
561
	}
562
	return commands;
563
}
564

565
//----------------------------------------------------------
566
ofPolyWindingMode ofPath::getWindingMode() const{
567
	return windingMode;
568
}
569

570
//----------------------------------------------------------
571
bool ofPath::isFilled() const{
572
	return bFill;
573
}
574

575
//----------------------------------------------------------
576
ofColor ofPath::getFillColor() const{
577
	return fillColor;
578
}
579

580
//----------------------------------------------------------
581
ofColor ofPath::getStrokeColor() const{
582
	return strokeColor;
583
}
584

585
//----------------------------------------------------------
586
float ofPath::getStrokeWidth() const{
587
	return strokeWidth;
588
}
589

590
//----------------------------------------------------------
591
void ofPath::generatePolylinesFromCommands(){
592
	if(mode==POLYLINES || commands.empty()) return;
593
	if(bNeedsPolylinesGeneration || curveResolution!=prevCurveRes){
594
		prevCurveRes = curveResolution;
595

596
		polylines.clear();
597
		int j=-1;
598

599
		for(int i=0; i<(int)commands.size();i++){
600
			switch(commands[i].type){
601
			case Command::moveTo:
602
				polylines.push_back(ofPolyline());
603
				j++;
604
				polylines[j].addVertex(commands[i].to);
605
				break;
606
			case Command::lineTo:
607
				polylines[j].addVertex(commands[i].to);
608
				break;
609
			case Command::curveTo:
610
				polylines[j].curveTo(commands[i].to, curveResolution);
611
				break;
612
			case Command::bezierTo:
613
				polylines[j].bezierTo(commands[i].cp1,commands[i].cp2,commands[i].to, curveResolution);
614
				break;
615
			case Command::quadBezierTo:
616
				polylines[j].quadBezierTo(commands[i].cp1,commands[i].cp2,commands[i].to, curveResolution);
617
				break;
618
			case Command::arc:
619
				polylines[j].arc(commands[i].to,commands[i].radiusX,commands[i].radiusY,commands[i].angleBegin,commands[i].angleEnd, circleResolution);
620
				break;
621
			case Command::arcNegative:
622
				polylines[j].arcNegative(commands[i].to,commands[i].radiusX,commands[i].radiusY,commands[i].angleBegin,commands[i].angleEnd, circleResolution);
623
				break;
624
			case Command::close:
625
				polylines[j].setClosed(true);
626
				break;
627
			}
628
		}
629

630
		bNeedsPolylinesGeneration = false;
631
		bNeedsTessellation = true;
632
	}
633
}
634

635
//----------------------------------------------------------
636
void ofPath::tessellate(){
637
	generatePolylinesFromCommands();
638
	if(!bNeedsTessellation || polylines.empty() || std::all_of(polylines.begin(), polylines.end(), [](const ofPolyline & p) {return p.getVertices().empty();})) return;
639
	if(bFill){
640
		tessellator.tessellateToMesh( polylines, windingMode, cachedTessellation);
641
	}
642
	if(hasOutline() && windingMode!=OF_POLY_WINDING_ODD){
643
		tessellator.tessellateToPolylines( polylines, windingMode, tessellatedContour);
644
	}
645
	bNeedsTessellation = false;
646
}
647

648
//----------------------------------------------------------
649
const vector<ofPolyline> & ofPath::getOutline() const{
650
	if(windingMode!=OF_POLY_WINDING_ODD){
651
		const_cast<ofPath*>(this)->tessellate();
652
		return tessellatedContour;
653
	}else{
654
		const_cast<ofPath*>(this)->generatePolylinesFromCommands();
655
		return polylines;
656
	}
657
}
658

659
//----------------------------------------------------------
660
const ofMesh & ofPath::getTessellation() const{
661
	const_cast<ofPath*>(this)->tessellate();
662
	return cachedTessellation;
663
}
664

665
//----------------------------------------------------------
666
void ofPath::draw(float x, float y) const{
667
	ofGetCurrentRenderer()->draw(*this,x,y);
668
}
669

670
//----------------------------------------------------------
671
void ofPath::draw() const{
672
	ofGetCurrentRenderer()->draw(*this);
673
}
674

675
//----------------------------------------------------------
676
void ofPath::flagShapeChanged(){
677
	if(mode==COMMANDS){
678
		bHasChanged = true;
679
		bNeedsPolylinesGeneration = true;
680
	}else{
681
		bNeedsTessellation = true;
682
	}
683
}
684

685
bool ofPath::hasChanged(){
686
	if(mode==COMMANDS){
687
		bool changed = bHasChanged;
688
		bHasChanged = false;
689
		return changed;
690
	}else{
691
		return bNeedsTessellation;
692
	}
693
}
694

695
//----------------------------------------------------------
696
void ofPath::setMode(Mode _mode){
697
	mode = _mode;
698
}
699

700
//----------------------------------------------------------
701
ofPath::Mode ofPath::getMode() const {
702
	return mode;
703
}
704

705
//----------------------------------------------------------
706
void ofPath::setCurveResolution(int _curveResolution){
707
	curveResolution = _curveResolution;
708
}
709

710
//----------------------------------------------------------
711
int ofPath::getCurveResolution() const {
712
	return curveResolution;
713
}
714

715
//----------------------------------------------------------
716
void ofPath::setCircleResolution(int res){
717
	circleResolution = res;
718
}
719

720
//----------------------------------------------------------
721
int ofPath::getCircleResolution() const {
722
	return circleResolution;
723
}
724

725
//----------------------------------------------------------
726
void ofPath::setArcResolution(int res){
727
	circleResolution = res;
728
}
729

730
//----------------------------------------------------------
731
int ofPath::getArcResolution() const {
732
	return circleResolution;
733
}
734

735
//----------------------------------------------------------
736
void ofPath::setUseShapeColor(bool useColor){
737
	bUseShapeColor = useColor;
738
}
739

740
//----------------------------------------------------------
741
bool ofPath::getUseShapeColor() const {
742
	return bUseShapeColor;
743
}
744

745
//----------------------------------------------------------
746
void ofPath::setColor( const ofColor& color ) {
747
	setFillColor( color );
748
	setStrokeColor( color );
749
}
750

751
//----------------------------------------------------------
752
void ofPath::setHexColor( int hex ) {
753
	setColor( ofColor().fromHex( hex ) );
754
}
755

756
//----------------------------------------------------------
757
void ofPath::setFillColor(const ofColor & color){
758
	setUseShapeColor(true);
759
	fillColor = color;
760
}
761

762
//----------------------------------------------------------
763
void ofPath::setFillHexColor( int hex ) {
764
	setFillColor( ofColor().fromHex( hex ) );
765
}
766

767
//----------------------------------------------------------
768
void ofPath::setStrokeColor(const ofColor & color){
769
	setUseShapeColor(true);
770
	strokeColor = color;
771
}
772

773
//----------------------------------------------------------
774
void ofPath::setStrokeHexColor( int hex ) {
775
	setStrokeColor( ofColor().fromHex( hex ) );
776
};
777

778
//----------------------------------------------------------
779
void ofPath::simplify(float tolerance){
780
	if(mode==COMMANDS) generatePolylinesFromCommands();
781
	for(int i=0;i<(int)polylines.size();i++){
782
		polylines[i].simplify(tolerance);
783
	}
784
}
785

786
//----------------------------------------------------------
787
void ofPath::translate(const glm::vec3 & p){
788
	if(mode==COMMANDS){
789
		for(int j=0;j<(int)commands.size();j++){
790
			commands[j].to += p;
791
			if(commands[j].type==Command::bezierTo || commands[j].type==Command::quadBezierTo){
792
				commands[j].cp1 += p;
793
				commands[j].cp2 += p;
794
			}
795
		}
796
	}else{
797
		for(int i=0;i<(int)polylines.size();i++){
798
			for(int j=0;j<(int)polylines[i].size();j++){
799
				polylines[i][j] += p;
800
			}
801
		}
802
	}
803
	flagShapeChanged();
804
}
805

806
//----------------------------------------------------------
807
void ofPath::translate(const glm::vec2 & p){
808
	translate(glm::vec3(p, 0.0));
809
}
810

811
//----------------------------------------------------------
812

813
void ofPath::rotateDeg(float degrees, const glm::vec3& axis ){
814
    auto radians = ofDegToRad(degrees);
815
    if(mode==COMMANDS){
816
        for(int j=0;j<(int)commands.size();j++){
817
            commands[j].to = glm::rotate(commands[j].to, radians, axis);
818
            if(commands[j].type==Command::bezierTo || commands[j].type==Command::quadBezierTo){
819
                commands[j].cp1 = glm::rotate(commands[j].cp1, radians, axis);
820
                commands[j].cp2 = glm::rotate(commands[j].cp2, radians, axis);
821
            }
822
            if(commands[j].type==Command::arc || commands[j].type==Command::arcNegative){
823
                commands[j].angleBegin += degrees;
824
                commands[j].angleEnd += degrees;
825
            }
826
        }
827
    }else{
828
        for(int i=0;i<(int)polylines.size();i++){
829
            for(int j=0;j<(int)polylines[i].size();j++){
830
                polylines[i][j] = glm::rotate(toGlm(polylines[i][j]), radians, axis);
831
            }
832
        }
833
    }
834
    flagShapeChanged();
835
}
836

837
//----------------------------------------------------------
838
void ofPath::rotateRad(float radians, const glm::vec3& axis ){
839
    rotateDeg(ofRadToDeg(radians), axis);
840
}
841

842
//----------------------------------------------------------
843
void ofPath::rotate(float degrees, const glm::vec3& axis ){
844
    rotateDeg(degrees, axis);
845
}
846

847
//----------------------------------------------------------
848
void ofPath::rotate(float degrees, const glm::vec2& axis ){
849
    rotateDeg(degrees, glm::vec3(axis, 0.0));
850
}
851

852
//----------------------------------------------------------
853
void ofPath::rotateDeg(float degrees, const glm::vec2& axis){
854
    rotateDeg(degrees, glm::vec3(axis, 0.0));
855
}
856

857
//----------------------------------------------------------
858
void ofPath::rotateRad(float radians, const glm::vec2& axis){
859
    rotateRad(radians, glm::vec3(axis, 0.0));
860
}
861

862
//----------------------------------------------------------
863
void ofPath::scale(float x, float y){
864
	if(mode==COMMANDS){
865
        for(std::size_t j=0;j<commands.size();j++){
866
			commands[j].to.x*=x;
867
			commands[j].to.y*=y;
868
			if(commands[j].type==Command::bezierTo || commands[j].type==Command::quadBezierTo){
869
				commands[j].cp1.x*=x;
870
				commands[j].cp1.y*=y;
871
				commands[j].cp2.x*=x;
872
				commands[j].cp2.y*=y;
873
			}
874
			if(commands[j].type==Command::arc || commands[j].type==Command::arcNegative){
875
				commands[j].radiusX *= x;
876
				commands[j].radiusY *= y;
877
			}
878
		}
879
	}else{
880
		for(std::size_t i=0;i<polylines.size();i++){
881
			for(std::size_t j=0;j<polylines[i].size();j++){
882
				polylines[i][j].x*=x;
883
				polylines[i][j].y*=y;
884
			}
885
		}
886
	}
887
	flagShapeChanged();
888
}
889

890
void ofPath::append(const ofPath & path){
891
	if(mode==COMMANDS){
892
		for(auto & command: path.getCommands()){
893
			addCommand(command);
894
		}
895
	}else{
896
		for(auto & poly: path.getOutline()){
897
			polylines.push_back(poly);
898
		}
899
	}
900
	flagShapeChanged();
901
}
902

903
void ofPath::addCommand(const ofPath::Command & command){
904
	if((commands.empty() || commands.back().type==Command::close) && command.type!=Command::moveTo){
905
		commands.push_back(Command(Command::moveTo,command.to));
906
	}
907
	commands.push_back(command);
908
}
909

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.