2D Rendering engine clears thermals correctly. Created Thermal object to handle clearing for the pins its attached to. Soft Rock PCB updateded to fix problem with via that was constantly showing wrong thermal type.
2D Rendering engine clears thermals correctly. Created Thermal object to handle clearing for the pins its attached to. Soft Rock PCB updateded to fix problem with via that was constantly showing wrong thermal type.

--- a/src/data/pcb/SoftRockLiteIIRX.pcb
+++ b/src/data/pcb/SoftRockLiteIIRX.pcb
@@ -805,7 +805,7 @@
 Via[108000 85500 4200 2000 0 2600 "" "thermal(5S)"]
 Via[4000 20500 4200 2000 0 2600 "" "thermal(5S)"]
 Via[65500 67000 4200 2000 0 2600 "" ""]
-Via[52000 62500 4700 2000 0 2600 "" "thermal(0-2,5S)"]
+Via[52000 62500 4700 2000 0 2600 "" "thermal(0S,1S,2S,5S)"]
 
 Element["" "HC49U_1" "X1" "rect_100" 22000 9000 -11000 6500 0 100 ""]
 (

--- a/src/js/circuit/PCB/Layer.js
+++ b/src/js/circuit/PCB/Layer.js
@@ -50,12 +50,22 @@
 					for(i = 0; i < pins.parts.length; i++)
 						pins.parts[i].clear(ctx, this.number);
 				ctx.globalCompositeOperation = "source-over";
+
 			}
 
 			// Render non clearing polygons
 			for(i = 0; i < this.polygons.length; i++)
 				if(!this.polygons[i].isClear())
 					this.polygons[i].render(ctx, color);
+
+			// Clear centers
+			ctx.globalCompositeOperation = "destination-out";
+			ctx.strokeStyle = 'rgba(0,0,0,1)';
+			ctx.fillStyle = 'rgba(0,0,0,1)';
+			if(pins)
+				for(i = 0; i < pins.parts.length; i++)
+					pins.parts[i].clearInner(ctx);
+			ctx.globalCompositeOperation = "source-over";
 
 		}
 

--- a/src/js/circuit/PCB/Pin.js
+++ b/src/js/circuit/PCB/Pin.js
@@ -1,8 +1,10 @@
 define(
 	[
+	 	"./Thermal",
 	 	"./parseFlags"
 	],
 	function(
+		Thermal,
 		parseFlags
 	){
 	
@@ -18,7 +20,7 @@
 			this.name = name;
 			this.num = num;
 			this.flags = parseFlags(Pin._defaultFlags, flags);
-	
+
 		};
 	
 		Pin._defaultFlags = {
@@ -64,16 +66,38 @@
 			ctx.fill();
 	
 		};
-	
-		Pin.prototype.clear = function(ctx){
+
+		Pin.prototype.clear = function(ctx, layerNumber){
 	
 			if(!this._cache) this._createCache();
-	
+
+			var thrm, i;
+
+			thrm = this.flags.thermal;
+			if(thrm){
+				thrm = Thermal.findThermal(thrm, layerNumber);
+				if(thrm)
+					thrm.clear(ctx, this._cache.x, this._cache.y, this.clearance, this.thick, this.drill);
+			}
+
+			if(!thrm){
+				ctx.beginPath();
+				ctx.arc(this._cache.x, this._cache.y, (this.clearance + this.thick) / 2.0, 0, Math.PI * 2, true);
+				ctx.closePath();
+				ctx.fill();
+			}
+
+		};
+
+		Pin.prototype.clearInner = function(ctx){
+
+			if(!this._cache) this._createCache();
+
 			ctx.beginPath();
-			ctx.arc(this._cache.x, this._cache.y, (this.clearance + this.thick) / 2.0, 0, Math.PI * 2, true);
+			ctx.arc(this._cache.x, this._cache.y, this.drill / 2.0, 0, Math.PI * 2, true);
 			ctx.closePath();
 			ctx.fill();
-	
+
 		};
 	
 		Pin.prototype.renderGL = function(gl, shaderProgram){

--- /dev/null
+++ b/src/js/circuit/PCB/Thermal.js
@@ -1,1 +1,127 @@
+define(
+	function(){
 
+		var Thermal = function(layerNumber, type){
+
+			this.layerNumber = layerNumber;
+			this.type = type;
+
+		};
+
+		Thermal.findThermal = function(list, layerNumber){
+			for(var i = 0; i < list.length; i++)
+				if(list[i].onLayer(layerNumber))
+					return list[i];
+			return null;
+		};
+
+		Thermal.prototype.onLayer = function(layerNumber){
+			return this.layerNumber == layerNumber - 1;
+		};
+
+		Thermal.prototype.clear = function(ctx, x, y, clearance, outerDiameter, innerDiameter){
+			switch(this.type){
+				case 'S':
+					break;
+				case 't':
+					var radius = ((clearance / 2) + outerDiameter) / 2;
+					var clearanceAngle = clearance / radius / 2;
+
+					ctx.lineCap = 'round';
+					ctx.lineWidth = clearance / 2;
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -clearanceAngle, -Math.PI * 0.5 + clearanceAngle, true);
+					ctx.stroke();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 0.5 - clearanceAngle, -Math.PI * 1.0 + clearanceAngle, true);
+					ctx.stroke();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.0 - clearanceAngle, -Math.PI * 1.5 + clearanceAngle, true);
+					ctx.stroke();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.5 - clearanceAngle, -Math.PI * 2.0 + clearanceAngle, true);
+					ctx.stroke();
+					break;
+				case 'X':
+					var radius = ((clearance / 2) + outerDiameter) / 2;
+					var clearanceAngle = clearance / radius / 2;
+
+					ctx.lineCap = 'round';
+					ctx.lineWidth = clearance / 2;
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 0.25 - clearanceAngle, -Math.PI * 0.75 + clearanceAngle, true);
+					ctx.stroke();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 0.75 - clearanceAngle, -Math.PI * 1.25 + clearanceAngle, true);
+					ctx.stroke();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.25 - clearanceAngle, -Math.PI * 1.75 + clearanceAngle, true);
+					ctx.stroke();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.75 - clearanceAngle, -Math.PI * 2.25 + clearanceAngle, true);
+					ctx.stroke();
+					break;
+				case '+':
+					var radius = (clearance + outerDiameter) / 2;
+					var clearanceAngle = clearance / radius / 4;
+					var clearanceAngle2 = clearance / outerDiameter / 2;
+					ctx.beginPath();
+					ctx.arc(x, y, radius, - clearanceAngle, -Math.PI * 0.5 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 0.5 + clearanceAngle2, - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 0.5 - clearanceAngle, -Math.PI * 1.0 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 1.0 + clearanceAngle2, -Math.PI * 0.5 - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.0 - clearanceAngle, -Math.PI * 1.5 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 1.5 + clearanceAngle2, -Math.PI * 1.0 - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.5 - clearanceAngle, -Math.PI * 2.0 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 2.0 + clearanceAngle2, -Math.PI * 1.5 - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					break;
+				case 'O':
+					var radius = (clearance + outerDiameter) / 2;
+					var clearanceAngle = clearance / radius / 4;
+					var clearanceAngle2 = clearance / outerDiameter / 2;
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 0.25 - clearanceAngle, -Math.PI * 0.75 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 0.75 + clearanceAngle2, -Math.PI * 0.25 - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 0.75 - clearanceAngle, -Math.PI * 1.25 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 1.25 + clearanceAngle2, -Math.PI * 0.75 - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.25 - clearanceAngle, -Math.PI * 1.75 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 1.75 + clearanceAngle2, -Math.PI * 1.25 - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					ctx.beginPath();
+					ctx.arc(x, y, radius, -Math.PI * 1.75 - clearanceAngle, -Math.PI * 2.25 + clearanceAngle, true);
+					ctx.arc(x, y, outerDiameter / 2, -Math.PI * 2.25 + clearanceAngle2, -Math.PI * 1.75 - clearanceAngle2, false);
+					ctx.closePath();
+					ctx.fill();
+					break;
+				default:
+					ctx.beginPath();
+					ctx.arc(x, y, (clearance + outerDiameter) / 2, 0, Math.PI * 2, true);
+					ctx.closePath();
+					ctx.fill();
+					break;
+			}
+
+		};
+
+		return Thermal;
+
+	}
+);

--- a/src/js/circuit/PCB/Via.js
+++ b/src/js/circuit/PCB/Via.js
@@ -1,8 +1,10 @@
 define(
 	[
+	 	"./Thermal",
 	 	"./parseFlags"
 	],
 	function(
+		Thermal,
 		parseFlags
 	){
 
@@ -38,24 +40,31 @@
 	
 		Via.prototype.clear = function(ctx, layerNumber){
 
-			var thrm, i;
-
-			thrm = this.flags.thermal;
-
+			var thrm = this.flags.thermal;
 			if(thrm){
-				for(i = 0; i < thrm.length; i++){
-					if(layerNumber - 1 == thrm[i].number)
-						console.log("thrm");
-				}
+				thrm = Thermal.findThermal(thrm, layerNumber);
+				if(thrm)
+					thrm.clear(ctx, this.x, this.y, this.clearance, this.od, this.id);
 			}
 
+			if(!thrm){
+				ctx.beginPath();
+				ctx.arc(this.x, this.y, (this.clearance + this.od) / 2.0, 0, Math.PI * 2, true);
+				ctx.closePath();
+				ctx.fill();
+			}
+
+		};
+
+		Via.prototype.clearInner = function(ctx){
+
 			ctx.beginPath();
-			ctx.arc(this.x, this.y, (this.clearance + this.od) / 2.0, 0, Math.PI * 2, true);
+			ctx.arc(this.x, this.y, this.id / 2.0, 0, Math.PI * 2, true);
 			ctx.closePath();
 			ctx.fill();
-	
+
 		};
-	
+
 		Via.prototype.renderGL = function(gl, shaderProgram){
 	
 			gl.uniform1f(shaderProgram.roundPointsUniform, true);

--- a/src/js/circuit/PCB/parseFlags.js
+++ b/src/js/circuit/PCB/parseFlags.js
@@ -1,65 +1,72 @@
-define(function(){
+define(
+	[
+	 	"./Thermal"
+	],
+	function(
+		Thermal
+	){
+	
+		var parseFlags = function(defaultFlags, flags){
+	
+			if(!flags) return {};
+	
+			var parsedFlags, split, parts, flag, attr, thrm, i, j, k;
+	
+			split = flags.split("\(.*?\)|(,)");
+	
+			parsedFlags = {};
+	
+			for(attr in defaultFlags)
+	            if(defaultFlags.hasOwnProperty(attr))
+	            	parsedFlags[attr] = defaultFlags[attr];
 
-	var parseFlags = function(defaultFlags, flags){
+			for(i = 0; i < split.length; i++){
+	
+				flag = split[i];
+	
+				if(flag.indexOf("thermal") != -1){
 
-		if(!flags) return {};
+					thrm = [];
+	
+					flag = flag.split('(')[1].split(')')[0].split(',');
+					for(j = 0; j < flag.length; j++){
+						// check for #-#
+						// for each add layer
+						//else layer #
+						parts = flag[j].split('-');
+						if(parts.length == 2){
+							parts = flag[j][flag[j].length-1];
+							if(isNaN(parseInt(parts))){
+								parts = flag[j].substring(0, flag[j].length - 1).split('-');
+								attr = parts;
+							} else {
+								parts = flag[j].split('-');
+								attr = 'O';
+							}
+							
+							for(k = parseInt(parts[0]); k <= parseInt(parts[1]); k++){
+								thrm.push(new Thermal(k, attr));
+							}
+						} else {
+							parts = flag[j][flag[j].length-1];
+							if(isNaN(parseInt(parts)))
+								thrm.push(new Thermal(parseInt(flag[j].substring(0, flag[j].length - 1)), parts));
+							else
+								thrm.push(new Thermal(parseInt(flag[j].substring(0, flag[j].length)), 'O'));
+						}
+					}
+					parsedFlags.thermal = thrm;
+				}
+				else
+					parsedFlags[flag] = true;
+	
+			}
+	
+			return parsedFlags;
+	
+		};
+	
+		return parseFlags;
 
-		var parsedFlags, split, parts, flag, attr, thrm, i, j, k;
-
-		split = flags.split("\(.*?\)|(,)");
-
-		parsedFlags = {};
-
-		for(attr in defaultFlags)
-            if(obj.hasOwnProperty(attr))
-            	parsedFlags[attr] = obj[attr];
-
-		for(i = 0; i < split.length; i++){
-
-			flag = split[i];
-
-			if(flag.indexOf("thermal") == 0){
-
-				thrm = [];
-
-				flag = flag.split('(')[1].split(')')[0].split(',');
-				for(j = 0; j < flag.length; j++){
-					// check for #-#
-					// for each add layer
-					//else layer #
-					parts = flag[j].split('-');
-					if(parts.length == 2){
-						parts = flag[j][flag[j].length-1];
-						if(isNaN(parseInt(parts))){
-							parts = flag[j].substring(0, flag[j].length - 1).split('-');
-							attr = parts;
-						} else {
-							parts = flag[j].split('-');
-							attr = 'O';
-						}
-						
-						for(k = parseInt(parts[0]); k <= parseInt(parts[1]); k++){
-							thrm.push({number: k, type: attr});
-						}
-					} else {
-						parts = flag[j][flag[j].length-1];
-						if(isNaN(parseInt(parts)))
-							thrm.push({number: parseInt(flag[j].substring(0, flag[j].length - 1)), type: parts});
-						else
-							thrm.push({number: parseInt(flag[j].substring(0, flag[j].length)), type: 'O'});
-					}
-				}
-				parsedFlags.thermal = thrm;
-			}
-			else
-				parsedFlags[flag] = true;
-
-		}
-
-		return parsedFlags;
-
-	};
-
-	return parseFlags;
-
-});
+	}
+);