@@ -8,6 +8,7 @@ var renderValues = true;
8
8
var renderDnpOutline = false ;
9
9
var renderTracks = true ;
10
10
var renderZones = true ;
11
+ var emptyContext2d = document . createElement ( "canvas" ) . getContext ( "2d" ) ;
11
12
12
13
function deg2rad ( deg ) {
13
14
return deg * Math . PI / 180 ;
@@ -122,74 +123,79 @@ function drawedge(ctx, scalefactor, edge, color) {
122
123
}
123
124
}
124
125
125
- function drawChamferedRect ( ctx , color , size , radius , chamfpos , chamfratio , ctxmethod ) {
126
+ function getChamferedRectPath ( size , radius , chamfpos , chamfratio ) {
126
127
// chamfpos is a bitmask, left = 1, right = 2, bottom left = 4, bottom right = 8
127
- ctx . beginPath ( ) ;
128
- ctx . strokeStyle = color ;
128
+ var path = new Path2D ( ) ;
129
129
var width = size [ 0 ] ;
130
130
var height = size [ 1 ] ;
131
131
var x = width * - 0.5 ;
132
132
var y = height * - 0.5 ;
133
133
var chamfOffset = Math . min ( width , height ) * chamfratio ;
134
- ctx . moveTo ( x , 0 ) ;
134
+ path . moveTo ( x , 0 ) ;
135
135
if ( chamfpos & 4 ) {
136
- ctx . lineTo ( x , y + height - chamfOffset ) ;
137
- ctx . lineTo ( x + chamfOffset , y + height ) ;
138
- ctx . lineTo ( 0 , y + height ) ;
136
+ path . lineTo ( x , y + height - chamfOffset ) ;
137
+ path . lineTo ( x + chamfOffset , y + height ) ;
138
+ path . lineTo ( 0 , y + height ) ;
139
139
} else {
140
- ctx . arcTo ( x , y + height , x + width , y + height , radius ) ;
140
+ path . arcTo ( x , y + height , x + width , y + height , radius ) ;
141
141
}
142
142
if ( chamfpos & 8 ) {
143
- ctx . lineTo ( x + width - chamfOffset , y + height ) ;
144
- ctx . lineTo ( x + width , y + height - chamfOffset ) ;
145
- ctx . lineTo ( x + width , 0 ) ;
143
+ path . lineTo ( x + width - chamfOffset , y + height ) ;
144
+ path . lineTo ( x + width , y + height - chamfOffset ) ;
145
+ path . lineTo ( x + width , 0 ) ;
146
146
} else {
147
- ctx . arcTo ( x + width , y + height , x + width , y , radius ) ;
147
+ path . arcTo ( x + width , y + height , x + width , y , radius ) ;
148
148
}
149
149
if ( chamfpos & 2 ) {
150
- ctx . lineTo ( x + width , y + chamfOffset ) ;
151
- ctx . lineTo ( x + width - chamfOffset , y ) ;
152
- ctx . lineTo ( 0 , y ) ;
150
+ path . lineTo ( x + width , y + chamfOffset ) ;
151
+ path . lineTo ( x + width - chamfOffset , y ) ;
152
+ path . lineTo ( 0 , y ) ;
153
153
} else {
154
- ctx . arcTo ( x + width , y , x , y , radius ) ;
154
+ path . arcTo ( x + width , y , x , y , radius ) ;
155
155
}
156
156
if ( chamfpos & 1 ) {
157
- ctx . lineTo ( x + chamfOffset , y ) ;
158
- ctx . lineTo ( x , y + chamfOffset ) ;
159
- ctx . lineTo ( x , 0 ) ;
157
+ path . lineTo ( x + chamfOffset , y ) ;
158
+ path . lineTo ( x , y + chamfOffset ) ;
159
+ path . lineTo ( x , 0 ) ;
160
160
} else {
161
- ctx . arcTo ( x , y , x , y + height , radius ) ;
161
+ path . arcTo ( x , y , x , y + height , radius ) ;
162
162
}
163
- ctx . closePath ( ) ;
164
- ctxmethod ( ) ;
163
+ path . closePath ( ) ;
164
+ return path ;
165
165
}
166
166
167
- function drawOblong ( ctx , color , size , ctxmethod ) {
168
- drawChamferedRect ( ctx , color , size , Math . min ( size [ 0 ] , size [ 1 ] ) / 2 , 0 , 0 , ctxmethod ) ;
167
+ function getOblongPath ( size ) {
168
+ return getChamferedRectPath ( size , Math . min ( size [ 0 ] , size [ 1 ] ) / 2 , 0 , 0 ) ;
169
169
}
170
170
171
- function drawPolygons ( ctx , color , polygons , ctxmethod ) {
172
- ctx . fillStyle = color ;
171
+ function getPolygonsPath ( polygons ) {
172
+ var combinedPath = new Path2D ( ) ;
173
173
for ( var polygon of polygons ) {
174
- ctx . beginPath ( ) ;
174
+ var path = new Path2D ( ) ;
175
175
for ( var vertex of polygon ) {
176
- ctx . lineTo ( ...vertex )
176
+ path . lineTo ( ...vertex )
177
177
}
178
- ctx . closePath ( ) ;
179
- ctxmethod ( ) ;
178
+ path . closePath ( ) ;
179
+ combinedPath . addPath ( path ) ;
180
180
}
181
+ return combinedPath ;
181
182
}
182
183
183
184
function drawPolygonShape ( ctx , shape , color ) {
184
185
ctx . save ( ) ;
185
- if ( shape . svgpath ) {
186
- ctx . fillStyle = color ;
187
- ctx . fill ( new Path2D ( shape . svgpath ) ) ;
188
- } else {
186
+ ctx . fillStyle = color ;
187
+ if ( ! shape . path2d ) {
188
+ if ( shape . svgpath ) {
189
+ shape . path2d = new Path2D ( shape . svgpath ) ;
190
+ } else {
191
+ shape . path2d = getPolygonsPath ( shape . polygons ) ;
192
+ }
193
+ }
194
+ if ( ! shape . svgpath ) {
189
195
ctx . translate ( ...shape . pos ) ;
190
196
ctx . rotate ( deg2rad ( - shape . angle ) ) ;
191
- drawPolygons ( ctx , color , shape . polygons , ctx . fill . bind ( ctx ) ) ;
192
197
}
198
+ ctx . fill ( shape . path2d ) ;
193
199
ctx . restore ( ) ;
194
200
}
195
201
@@ -203,11 +209,32 @@ function drawDrawing(ctx, layer, scalefactor, drawing, color) {
203
209
}
204
210
}
205
211
206
- function drawCircle ( ctx , radius , ctxmethod ) {
207
- ctx . beginPath ( ) ;
208
- ctx . arc ( 0 , 0 , radius , 0 , 2 * Math . PI ) ;
209
- ctx . closePath ( ) ;
210
- ctxmethod ( ) ;
212
+ function getCirclePath ( radius ) {
213
+ var path = new Path2D ( ) ;
214
+ path . arc ( 0 , 0 , radius , 0 , 2 * Math . PI ) ;
215
+ path . closePath ( ) ;
216
+ return path ;
217
+ }
218
+
219
+ function getCachedPadPath ( pad ) {
220
+ if ( ! pad . path2d ) {
221
+ // if path2d is not set, build one and cache it on pad object
222
+ if ( pad . shape == "rect" ) {
223
+ pad . path2d = new Path2D ( ) ;
224
+ pad . path2d . rect ( ...pad . size . map ( c => - c * 0.5 ) , ...pad . size ) ;
225
+ } else if ( pad . shape == "oval" ) {
226
+ pad . path2d = getOblongPath ( pad . size ) ;
227
+ } else if ( pad . shape == "circle" ) {
228
+ pad . path2d = getCirclePath ( pad . size [ 0 ] / 2 ) ;
229
+ } else if ( pad . shape == "roundrect" ) {
230
+ pad . path2d = getChamferedRectPath ( pad . size , pad . radius , 0 , 0 ) ;
231
+ } else if ( pad . shape == "chamfrect" ) {
232
+ pad . path2d = getChamferedRectPath ( pad . size , pad . radius , pad . chamfpos , pad . chamfratio )
233
+ } else if ( pad . shape == "custom" ) {
234
+ pad . path2d = getPolygonsPath ( pad . polygons ) ;
235
+ }
236
+ }
237
+ return pad . path2d ;
211
238
}
212
239
213
240
function drawPad ( ctx , pad , color , outline , hole ) {
@@ -219,32 +246,18 @@ function drawPad(ctx, pad, color, outline, hole) {
219
246
}
220
247
ctx . fillStyle = color ;
221
248
ctx . strokeStyle = color ;
222
- var ctxmethod = outline ? ctx . stroke . bind ( ctx ) : ctx . fill . bind ( ctx ) ;
223
- if ( pad . shape == "rect" ) {
224
- var rect = [ ...pad . size . map ( c => - c * 0.5 ) , ...pad . size ] ;
225
- if ( outline ) {
226
- ctx . strokeRect ( ...rect ) ;
227
- } else {
228
- ctx . fillRect ( ...rect ) ;
229
- }
230
- } else if ( pad . shape == "oval" ) {
231
- drawOblong ( ctx , color , pad . size , ctxmethod ) ;
232
- } else if ( pad . shape == "circle" ) {
233
- drawCircle ( ctx , pad . size [ 0 ] / 2 , ctxmethod ) ;
234
- } else if ( pad . shape == "roundrect" ) {
235
- drawChamferedRect ( ctx , color , pad . size , pad . radius , 0 , 0 , ctxmethod ) ;
236
- } else if ( pad . shape == "chamfrect" ) {
237
- drawChamferedRect ( ctx , color , pad . size , pad . radius , pad . chamfpos , pad . chamfratio , ctxmethod )
238
- } else if ( pad . shape == "custom" ) {
239
- drawPolygons ( ctx , color , pad . polygons , ctxmethod ) ;
249
+ var path = getCachedPadPath ( pad ) ;
250
+ if ( outline ) {
251
+ ctx . stroke ( path ) ;
252
+ } else {
253
+ ctx . fill ( path ) ;
240
254
}
241
255
if ( pad . type == "th" && hole ) {
242
- ctxmethod = ctx . fill . bind ( ctx ) ;
243
256
ctx . fillStyle = "#CCCCCC" ;
244
257
if ( pad . drillshape == "oblong" ) {
245
- drawOblong ( ctx , "#CCCCCC" , pad . drillsize , ctxmethod ) ;
258
+ ctx . fill ( getOblongPath ( pad . drillsize ) ) ;
246
259
} else {
247
- drawCircle ( ctx , pad . drillsize [ 0 ] / 2 , ctxmethod ) ;
260
+ ctx . fill ( getCirclePath ( pad . drillsize [ 0 ] / 2 ) ) ;
248
261
}
249
262
}
250
263
ctx . restore ( ) ;
@@ -345,12 +358,16 @@ function drawTracks(canvas, layer, color, highlight) {
345
358
function drawZones ( canvas , layer , color , highlight ) {
346
359
ctx = canvas . getContext ( "2d" ) ;
347
360
ctx . strokeStyle = color ;
361
+ ctx . fillStyle = color ;
348
362
ctx . lineJoin = "round" ;
349
363
for ( var zone of pcbdata . zones [ layer ] ) {
364
+ if ( ! zone . path2d ) {
365
+ zone . path2d = getPolygonsPath ( zone . polygons ) ;
366
+ }
350
367
if ( highlight && highlightedNet != zone . net ) continue ;
351
368
ctx . lineWidth = zone . width ;
352
- drawPolygons ( ctx , color , zone . polygons , ctx . stroke . bind ( ctx ) ) ;
353
- drawPolygons ( ctx , color , zone . polygons , ctx . fill . bind ( ctx ) ) ;
369
+ ctx . fill ( zone . path2d ) ;
370
+ ctx . stroke ( zone . path2d ) ;
354
371
}
355
372
}
356
373
@@ -563,35 +580,25 @@ function pointWithinPad(x, y, pad) {
563
580
v [ 0 ] -= pad . offset [ 0 ] ;
564
581
v [ 1 ] -= pad . offset [ 1 ] ;
565
582
}
566
- if ( [ "rect" , "roundrect" , "chamfrect" ] . includes ( pad . shape ) ) {
567
- return - pad . size [ 0 ] / 2 <= v [ 0 ] && v [ 0 ] <= pad . size [ 0 ] / 2 &&
568
- - pad . size [ 1 ] / 2 <= v [ 1 ] && v [ 1 ] <= pad . size [ 1 ] / 2 ;
569
- } else if ( pad . shape == "oval" ) {
570
- var d = ( pad . size [ 0 ] - pad . size [ 1 ] ) / 2 ;
571
- if ( d > 0 ) {
572
- return pointWithinDistanceToSegment ( v [ 0 ] , v [ 1 ] , d , 0 , - d , 0 , pad . size [ 1 ] / 2 ) ;
573
- } else {
574
- return pointWithinDistanceToSegment ( v [ 0 ] , v [ 1 ] , 0 , d , 0 , - d , pad . size [ 0 ] / 2 ) ;
575
- }
576
- } else if ( pad . shape == "circle" ) {
577
- return v [ 0 ] * v [ 0 ] + v [ 1 ] * v [ 1 ] <= pad . size [ 0 ] * pad . size [ 0 ] / 4 ;
578
- }
583
+ return emptyContext2d . isPointInPath ( getCachedPadPath ( pad ) , ...v ) ;
579
584
}
580
585
581
586
function netHitScan ( layer , x , y ) {
582
587
// Check track segments
583
- if ( "tracks" in pcbdata ) {
588
+ if ( renderTracks && pcbdata . tracks ) {
584
589
for ( var track of pcbdata . tracks [ layer ] ) {
585
590
if ( pointWithinDistanceToSegment ( x , y , ...track . start , ...track . end , track . width / 2 ) ) {
586
591
return track . net ;
587
592
}
588
593
}
589
594
}
590
595
// Check pads
591
- for ( var mod of pcbdata . modules ) {
592
- for ( var pad of mod . pads ) {
593
- if ( pad . layers . includes ( layer ) && pointWithinPad ( x , y , pad ) ) {
594
- return pad . net ;
596
+ if ( renderPads ) {
597
+ for ( var mod of pcbdata . modules ) {
598
+ for ( var pad of mod . pads ) {
599
+ if ( pad . layers . includes ( layer ) && pointWithinPad ( x , y , pad ) ) {
600
+ return pad . net ;
601
+ }
595
602
}
596
603
}
597
604
}
0 commit comments