Compare commits
73 Commits
Author | SHA1 | Date | |
---|---|---|---|
04275ee35c | |||
f8d0594eca | |||
5be3b31e00 | |||
84c1079e50 | |||
6320379d02 | |||
b166f6034e | |||
d07f672b28 | |||
363e076f36 | |||
8bf6f265f7 | |||
217958aec3 | |||
367b1b0d1a | |||
6836852122 | |||
944098b9f9 | |||
539cf3d73e | |||
4b3e7cfb7d | |||
b144744509 | |||
e591bed6ad | |||
6a4e64eac0 | |||
f7dd14ff7b | |||
bfd34cedd6 | |||
8e1c075911 | |||
a02f364a4c | |||
48fee2c215 | |||
5780d1982c | |||
6fb08f0f7b | |||
13f8659b98 | |||
edc9d17a8c | |||
c7a3f5bbd0 | |||
41d5052583 | |||
07ddec343a | |||
5a9a5e997a | |||
55b6549999 | |||
fcdc350e40 | |||
9dedbeae1b | |||
124d8a0fd8 | |||
81fcbb6916 | |||
d436bd1227 | |||
cb648019bb | |||
11a88a9d94 | |||
92178f3371 | |||
3c86ae286f | |||
1b6d84a9b8 | |||
2d81be3b24 | |||
14f57f54bf | |||
e7c697c24d | |||
7ac63f038c | |||
557926d631 | |||
da62d51615 | |||
3918857fcc | |||
f1dcebdd88 | |||
1d35c78737 | |||
d17326ad7a | |||
4948a88833 | |||
b73b924ec4 | |||
641d292c33 | |||
223275fd65 | |||
6e42e816d3 | |||
5678cf5df9 | |||
67ec4accb9 | |||
fa867c3a34 | |||
7865876e64 | |||
113b42656c | |||
7557380722 | |||
3e2a1ec9e1 | |||
09db613620 | |||
bacb4673c9 | |||
e649a167cd | |||
997e8efb20 | |||
1f380ce959 | |||
fbc6fc30a7 | |||
fee2329ca7 | |||
5768fcaf35 | |||
0886a5d4e1 |
BIN
docs/static/MC-LEGO-loader-eyes.gif
vendored
Normal file
After Width: | Height: | Size: 69 KiB |
30
docs/static/fonts/icons/iconfont.css
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
@font-face {
|
||||
font-family: "iconfont";
|
||||
src: url("iconfont.eot?e05611aaee246c1da118a83eaf515de9?#iefix") format("embedded-opentype"),
|
||||
url("iconfont.woff2?e05611aaee246c1da118a83eaf515de9") format("woff2"),
|
||||
url("iconfont.woff?e05611aaee246c1da118a83eaf515de9") format("woff");
|
||||
}
|
||||
|
||||
.icon {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.icon:before {
|
||||
font-family: iconfont !important;
|
||||
font-style: normal;
|
||||
font-weight: normal !important;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.icon-ultrasonic:before {
|
||||
content: "\f101";
|
||||
}
|
||||
.icon-color:before {
|
||||
content: "\f102";
|
||||
}
|
||||
.icon-touch:before {
|
||||
content: "\f103";
|
||||
}
|
||||
.icon-gyro:before {
|
||||
content: "\f104";
|
||||
}
|
BIN
docs/static/fonts/icons/iconfont.eot
vendored
Normal file
24
docs/static/fonts/icons/iconfont.svg
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<font id="iconfont" horiz-adv-x="40">
|
||||
<font-face font-family="iconfont"
|
||||
units-per-em="40" ascent="40"
|
||||
descent="0" />
|
||||
<missing-glyph horiz-adv-x="0" />
|
||||
<glyph glyph-name="ultrasonic"
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M26.8 13H13.1C15.6 14.6 17 17.3 17 20.2C17 21.8 16.6 23.3 15.8 24.7S13.8 27 12.4 27.8H27.6C26.2 27 25.1 26.1 24.2 24.7S23 21.8 23 20.2C22.9 17.3 24.3 14.6 26.8 13L26.8 13L26.8 13z M8.6 12C4.1 12 0.4 15.7 0.4 20.2S4.1 28.4 8.6 28.4S16.8 24.7 16.8 20.2C16.7 15.7 13.1 12 8.6 12zM8.6 23.4C6.8 23.4 5.4 22 5.4 20.2S6.8 16.9 8.6 16.9S11.9 18.4 11.9 20.2S10.4 23.4 8.6 23.4z M31.4 12C26.9 12 23.2 15.7 23.2 20.2S26.9 28.4 31.4 28.4S39.6 24.7 39.6 20.2C39.5 15.7 35.9 12 31.4 12zM31.4 23.4C29.6 23.4 28.1 22 28.1 20.2S29.6 16.9 31.4 16.9S34.6 18.4 34.6 20.2S33.2 23.4 31.4 23.4z" />
|
||||
<glyph glyph-name="color"
|
||||
unicode=""
|
||||
horiz-adv-x="43.35195530726257" d=" M38.7 -0.1H4.7C3.4 -0.1 2.5 0.6 2.5 1.5V6.8H0.9A0.9608938547486034 0.9608938547486034 0 0 0 0 7.7V31.5A0.9608938547486034 0.9608938547486034 0 0 0 0.9 32.4H2.5V38.4C2.5 39.3 3.6 40 4.7 40H38.7C40 40 40.9 39.3 40.9 38.4V32.4H42.5A0.9608938547486034 0.9608938547486034 0 0 0 43.4 31.5V7.8A0.9608938547486034 0.9608938547486034 0 0 0 42.5 6.9H40.9V1.6C41.1 0.7 40 -0.1 38.7 -0.1zM21.7 35.1A11.374301675977657 11.374301675977657 0 0 1 13.6 15.5A4.916201117318437 4.916201117318437 0 0 1 13.4 13.7A8.268156424581006 8.268156424581006 0 0 1 29.9 13.7A4.916201117318437 4.916201117318437 0 0 1 29.7 15.5A12.379888268156424 12.379888268156424 0 0 1 33.1 23.6A11.1731843575419 11.1731843575419 0 0 1 21.7 35.1zM41.6 18.3V10.9H42.5V18.3zM1.1 18.3V10.9H2V18.3zM41.6 28.6V21.2H42.5V28.6zM1.1 28.6V21.2H2V28.6z M21.9 7.4A6.480446927374302 6.480446927374302 0 0 0 15.4 13.9A9.497206703910615 9.497206703910615 0 0 0 15.9 16.3A9.87709497206704 9.87709497206704 0 0 0 12.3 23.9A9.608938547486035 9.608938547486035 0 0 0 31.5 23.9A9.87709497206704 9.87709497206704 0 0 0 27.9 16.3A8.022346368715086 8.022346368715086 0 0 0 28.4 13.9A6.703910614525141 6.703910614525141 0 0 0 21.9 7.4zM21.9 16.3A2.4581005586592184 2.4581005586592184 0 1 1 24.4 13.9A2.837988826815643 2.837988826815643 0 0 1 21.9 16.3zM21.9 27.7A4.46927374301676 4.46927374301676 0 1 1 26.4 23.2A4.804469273743018 4.804469273743018 0 0 1 21.9 27.7z" />
|
||||
<glyph glyph-name="touch"
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M34.3 3.3H4.9C3.8 3.3 2.8 3.9 2.8 4.8V9.3H1.5C1.1 9.3 0.7 9.7 0.7 10.1V30.5C0.7 30.9 1.1 31.3 1.5 31.3H2.8V36.6C2.8 37.4 3.7 38.1 4.9 38.1H16V36.6H22.7V38.1H34.2C35.3 38.1 36.3 37.5 36.3 36.6V31.3H37.6C37.9 31.3 38.3 30.9 38.3 30.5V10.1C38.3 9.7 37.9 9.3 37.6 9.3H36.3V4.8C36.3 3.9 35.3 3.3 34.3 3.3L34.3 3.3zM14.1 16.2C14.7 15.3 15.4 14.7 16.2 14.1V5.6H22.6V14.1C23.5 14.7 24.1 15.4 24.7 16.2H33.4V22.6H24.9C24.3 23.5 23.6 24.3 22.6 24.9V33.6H16.2V24.9C15.3 24.3 14.5 23.6 13.9 22.6H5.4V16.2H14.1L14.1 16.2zM36.6 19.2V13H37.4V19.2H36.6zM1.8 19.2V13H2.6V19.2H1.8zM36.6 28.1V21.9H37.4V28.1H36.6zM1.8 28.1V21.9H2.6V28.1H1.8zM19.4 15.4C18.8 15.4 18.5 15.4 18.1 15.6V17.1C18.1 17.5 17.9 17.7 17.5 17.7L17.5 17.7H16C15.8 18.1 15.6 18.6 15.6 19.2C15.6 19.8 15.6 20.3 16 20.7H17.3C18.1 20.7 18.1 21.6 18.1 21.6L18.1 21.6C18.1 21.8 18.1 22.4 18.1 22.9C18.5 23.1 19 23.1 19.4 23.1C20 23.1 20.5 23.1 21.1 22.9C21.1 22.5 21.1 22 21.1 21.6L21.1 21.6V21.4C21.1 21 21.3 20.8 21.7 20.8C21.7 20.8 21.7 20.8 21.9 20.8L21.9 20.8H23.4C23.8 20.4 23.8 19.9 23.8 19.3S23.6 18.2 23.4 17.8L23.4 17.8C23 17.8 22.5 17.6 22.1 17.6C21.7 17.6 21.3 17.4 21.3 17V15.5C20.7 15.3 20.4 15.3 19.8 15.3C19.4 15.4 19.4 15.4 19.4 15.4z" />
|
||||
<glyph glyph-name="gyro"
|
||||
unicode=""
|
||||
horiz-adv-x="23.578015492438215" d=" M17 0H6.4A5.901881224640355 5.901881224640355 0 0 0 5.1 0.3H2.3A1.283659166359277 1.283659166359277 0 0 0 1 1.6V4.5H0.5A0.5016599040944301 0.5016599040944301 0 0 0 0 5V35.4A0.5016599040944301 0.5016599040944301 0 0 0 0.5 35.9H1V38.7A1.283659166359277 1.283659166359277 0 0 0 2.3 40H10.6V39.6H12.8V40H21.2A1.283659166359277 1.283659166359277 0 0 0 22.5 38.7V35.9H23.1A0.5016599040944301 0.5016599040944301 0 0 0 23.6 35.4V5.1A0.5016599040944301 0.5016599040944301 0 0 0 23.1 4.6H22.5V1.6A1.283659166359277 1.283659166359277 0 0 0 21.2 0.4H18.5C18.4 0.1 17.2 0 17 0zM6.2 34.5L3.7 33.8A1.0033198081888601 1.0033198081888601 0 0 1 3.4 33.7A0.2360752489856142 0.2360752489856142 0 0 1 3.3 33.5A0.20656584286241245 0.20656584286241245 0 0 1 3.4 33.3L4.1 32.8A7.657690888970861 7.657690888970861 0 0 1 3.1 30A8.51346366654371 8.51346366654371 0 0 1 4.8 23.5C5.8 24.2 6.5 24.7 6.5 24.7A7.377351530800443 7.377351530800443 0 0 0 5.4 26.9A6.300258207303577 6.300258207303577 0 0 0 6 31.8L6.5 31.5H6.5L6.6 31.5A0.3541128734784213 0.3541128734784213 0 0 1 6.8 31.4A0.17705643673921065 0.17705643673921065 0 0 1 7 31.5A0.6344522316488379 0.6344522316488379 0 0 1 7 32L6.2 34.5zM17.5 31.8H17.5A6.300258207303577 6.300258207303577 0 0 0 18 26.9A7.510143858354851 7.510143858354851 0 0 0 17 24.7L17.1 24.6L18.6 23.5A8.631501291036518 8.631501291036518 0 0 1 20.3 30A7.657690888970861 7.657690888970861 0 0 1 19.3 32.8L19.8 33.1L20 33.2A0.22132054592401326 0.22132054592401326 0 0 1 20.1 33.4A0.26558465510881596 0.26558465510881596 0 0 1 20 33.6A1.0033198081888601 1.0033198081888601 0 0 1 19.7 33.7L17.2 34.5S17.1 34.1 17 33.6S16.6 32.3 16.5 32A0.619697528587237 0.619697528587237 0 0 1 16.5 31.5A0.17705643673921065 0.17705643673921065 0 0 1 16.6 31.4A0.48690520103282936 0.48690520103282936 0 0 1 16.8 31.4L16.8 31.4L17.4 31.7zM11.7 30.6A1.9918849133161198 1.9918849133161198 0 1 1 13.7 28.6A1.9918849133161198 1.9918849133161198 0 0 1 11.7 30.6H11.7z" />
|
||||
</font>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
BIN
docs/static/fonts/icons/iconfont.ttf
vendored
Normal file
BIN
docs/static/fonts/icons/iconfont.woff
vendored
Normal file
BIN
docs/static/fonts/icons/iconfont.woff2
vendored
Normal file
66
docs/tests/motors.ts
Normal file
@ -0,0 +1,66 @@
|
||||
let errors: string[] = [];
|
||||
let tachoB = 0;
|
||||
let tachoC = 0;
|
||||
|
||||
function assert(name: string, condition: boolean) {
|
||||
if (!condition) {
|
||||
errors.push(name)
|
||||
}
|
||||
}
|
||||
|
||||
function assertClose(name: string, expected: number, actual: number, tolerance = 10) {
|
||||
assert(name + ` ${expected}/${actual}`, Math.abs(expected - actual) < tolerance);
|
||||
}
|
||||
|
||||
function test(name: string, f: () => void, check?: () => void) {
|
||||
motors.stopAllMotors();
|
||||
loops.pause(500);
|
||||
tachoB = motors.largeB.tachoCount()
|
||||
tachoC = motors.largeB.tachoCount()
|
||||
brick.clearScreen()
|
||||
brick.print(name, 0, 0)
|
||||
f();
|
||||
loops.pause(3000);
|
||||
motors.stopAllMotors();
|
||||
motors.largeB.setReversed(false);
|
||||
motors.largeC.setReversed(false);
|
||||
motors.mediumA.setReversed(false);
|
||||
loops.pause(1000);
|
||||
if (check)
|
||||
check()
|
||||
}
|
||||
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
test("lgB set speed 100", () => {
|
||||
motors.largeB.setSpeed(100)
|
||||
});
|
||||
test("lgB set speed (reversed)", () => {
|
||||
motors.largeB.setReversed(true)
|
||||
motors.largeB.setSpeed(100)
|
||||
})
|
||||
test("lgBC set speed 100", () => {
|
||||
motors.largeBC.setSpeed(100)
|
||||
})
|
||||
test("lgBC steer 50% 2x", () => {
|
||||
motors.largeBC.steer(50, 50, 2, MoveUnit.Rotations)
|
||||
}, () => {
|
||||
assertClose("largeB", 720, motors.largeB.tachoCount() - tachoB)
|
||||
});
|
||||
test("lgBC steer 50% 500deg", () => {
|
||||
motors.largeBC.steer(50, 50, 500, MoveUnit.Degrees)
|
||||
}, () => {
|
||||
assertClose("largeB", 500, motors.largeB.tachoCount() - tachoB)
|
||||
});
|
||||
test("lgBC steer 50% 2s", () => {
|
||||
motors.largeBC.steer(50, 50, 2, MoveUnit.Seconds)
|
||||
})
|
||||
test("lgBC tank 50% 2s", () => {
|
||||
motors.largeBC.tank(50, 50, 720, MoveUnit.Degrees)
|
||||
})
|
||||
|
||||
brick.clearScreen()
|
||||
brick.print(`${errors.length} errors`, 0, 0)
|
||||
let l = 1;
|
||||
for(const error of errors)
|
||||
brick.print(`error: ${error}`, 0, l++ * 12)
|
||||
})
|
BIN
legoresources/SVGassets/.DS_Store
vendored
@ -79,7 +79,9 @@ namespace sensors {
|
||||
}
|
||||
|
||||
_query() {
|
||||
if (this.mode == ColorSensorMode.Color)
|
||||
if (this.mode == ColorSensorMode.Color
|
||||
|| this.mode == ColorSensorMode.AmbientLightIntensity
|
||||
|| this.mode == ColorSensorMode.ReflectedLightIntensity)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
return 0
|
||||
}
|
||||
@ -106,9 +108,9 @@ namespace sensors {
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
const v = this._colorEventValue(<number>color);
|
||||
control.onEvent(this._id, v, handler);
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
if (this.color() == color)
|
||||
control.raiseEvent(this._id, v);
|
||||
}
|
||||
@ -182,12 +184,12 @@ namespace sensors {
|
||||
//% whenUsed block="1" weight=95 fixedInstance jres=icons.port1
|
||||
export const color1: ColorSensor = new ColorSensor(1)
|
||||
|
||||
//% whenUsed block="3" weight=90 fixedInstance jres=icons.port3
|
||||
export const color3: ColorSensor = new ColorSensor(3)
|
||||
|
||||
//% whenUsed block="2" weight=90 fixedInstance jres=icons.port2
|
||||
export const color2: ColorSensor = new ColorSensor(2)
|
||||
|
||||
//% whenUsed block="3" weight=90 fixedInstance jres=icons.port3
|
||||
export const color3: ColorSensor = new ColorSensor(3)
|
||||
|
||||
//% whenUsed block="4" weight=90 fixedInstance jres=icons.port4
|
||||
export const color4: ColorSensor = new ColorSensor(4)
|
||||
}
|
||||
|
@ -18,8 +18,8 @@
|
||||
"brick.Button.isPressed": "Check if button is currently pressed or not.",
|
||||
"brick.Button.onEvent": "Do something when a button or sensor is clicked, up or down.",
|
||||
"brick.Button.onEvent|param|body": "code to run when the event is raised",
|
||||
"brick.Button.waitUntil": "Waits until the event is raised",
|
||||
"brick.Button.waitUntil|param|ev": "the event to wait for",
|
||||
"brick.Button.pauseUntil": "Waits until the event is raised",
|
||||
"brick.Button.pauseUntil|param|ev": "the event to wait for",
|
||||
"brick.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
|
||||
"brick._imagePicker": "An image",
|
||||
"brick._imagePicker|param|image": "the image",
|
||||
@ -28,6 +28,7 @@
|
||||
"brick.buttonLeft": "Left button on the EV3 Brick.",
|
||||
"brick.buttonRight": "Right button on the EV3 Brick.",
|
||||
"brick.buttonUp": "Up button on the EV3 Brick.",
|
||||
"brick.clearScreen": "Clears the screen",
|
||||
"brick.lightPattern": "Pattern block.",
|
||||
"brick.lightPattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
||||
"brick.print": "Show text on the screen.",
|
||||
@ -50,20 +51,30 @@
|
||||
"control.raiseEvent": "Announce that an event happened to registered handlers.",
|
||||
"control.raiseEvent|param|src": "ID of the Component that generated the event",
|
||||
"control.raiseEvent|param|value": "Component specific code indicating the cause of the event.",
|
||||
"motors.Motor.clearCount": "Clears the motor count",
|
||||
"motors.Motor.count": "Gets motor step count.",
|
||||
"motors.Motor.move": "Moves the motor by a number of degrees",
|
||||
"motors.Motor.move|param|angle": "the degrees to rotate, eg: 360",
|
||||
"motors.Motor.move|param|power": "the power from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.Motor.reset": "Resets the motor.",
|
||||
"motors.Motor.move": "Moves the motor by a number of rotations, degress or seconds",
|
||||
"motors.Motor.move|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.Motor.move|param|unit": "the meaning of the value",
|
||||
"motors.Motor.move|param|value": "the move quantity, eg: 2",
|
||||
"motors.Motor.reset": "Resets the motor(s).",
|
||||
"motors.Motor.setBrake": "Sets the automatic brake on or off when the motor is off",
|
||||
"motors.Motor.setBrake|param|brake": "a value indicating if the motor should break when off",
|
||||
"motors.Motor.setReversed": "Reverses the motor polarity",
|
||||
"motors.Motor.setSpeed": "Sets the motor speed level from ``-100`` to ``100``.",
|
||||
"motors.Motor.setSpeed|param|speed": "the power from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.Motor.speed": "Gets motor actual speed.",
|
||||
"motors.Motor.stop": "Stops the motor",
|
||||
"motors.Motor.tachoCount": "Gets motor tacho count.",
|
||||
"motors.Motor.setSpeed": "Sets the speed of the motor.",
|
||||
"motors.Motor.setSpeed|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.Motor.stop": "Stops the motor(s).",
|
||||
"motors.SingleMotor.clearCount": "Clears the motor count",
|
||||
"motors.SingleMotor.count": "Gets motor step count.",
|
||||
"motors.SingleMotor.speed": "Gets motor actual speed.",
|
||||
"motors.SingleMotor.tachoCount": "Gets motor tacho count.",
|
||||
"motors.SynchedMotorPair.steer": "Turns the motor and the follower motor by a number of rotations",
|
||||
"motors.SynchedMotorPair.steer|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.SynchedMotorPair.steer|param|steering": "the ratio of power sent to the follower motor, from ``-100`` to ``100``",
|
||||
"motors.SynchedMotorPair.steer|param|unit": "the meaning of the value",
|
||||
"motors.SynchedMotorPair.steer|param|value": "the move quantity, eg: 2",
|
||||
"motors.SynchedMotorPair.tank": "The Move Tank block can make a robot drive forward, backward, turn, or stop. \nUse the Move Tank block for robot vehicles that have two Large Motors, \nwith one motor driving the left side of the vehicle and the other the right side. \nYou can make the two motors go at different speeds or in different directions \nto make your robot turn.",
|
||||
"motors.SynchedMotorPair.tank|param|speedRight": "the speed on the right motor, eg: 50",
|
||||
"motors.SynchedMotorPair.tank|param|unit": "@param speedLeft the speed on the left motor, eg: 50",
|
||||
"motors.SynchedMotorPair.tank|param|value": "the amount of movement, eg: 2",
|
||||
"motors.stopAllMotors": "Stops all motors",
|
||||
"output.createBuffer": "Create a new zero-initialized buffer.",
|
||||
"output.createBuffer|param|size": "number of bytes in the buffer",
|
||||
|
@ -12,14 +12,21 @@
|
||||
"LightsPattern.RedFlash|block": "Flashing Red",
|
||||
"LightsPattern.RedPulse|block": "Pulsing Red",
|
||||
"LightsPattern.Red|block": "Red",
|
||||
"MoveUnit.Degrees|block": "degrees",
|
||||
"MoveUnit.Rotations|block": "rotations",
|
||||
"MoveUnit.Seconds|block": "seconds",
|
||||
"Output.AB|block": "A+B",
|
||||
"Output.AD|block": "A+D",
|
||||
"Output.ALL|block": "All",
|
||||
"Output.A|block": "A",
|
||||
"Output.BC|block": "B+C",
|
||||
"Output.B|block": "B",
|
||||
"Output.CD|block": "C+D",
|
||||
"Output.C|block": "C",
|
||||
"Output.D|block": "D",
|
||||
"brick.Button.isPressed|block": "`icons.brickButtons` %button|is pressed",
|
||||
"brick.Button.onEvent|block": "on `icons.brickButtons` %button|%event",
|
||||
"brick.Button.waitUntil|block": "wait until `icons.brickButtons` %button|%event",
|
||||
"brick.Button.pauseUntil|block": "pause until `icons.brickButtons` %button|%event",
|
||||
"brick.Button.wasPressed|block": "`icons.brickButtons` %button|was pressed",
|
||||
"brick._imagePicker|block": "%image",
|
||||
"brick.buttonDown|block": "down",
|
||||
@ -27,34 +34,41 @@
|
||||
"brick.buttonLeft|block": "left",
|
||||
"brick.buttonRight|block": "right",
|
||||
"brick.buttonUp|block": "up",
|
||||
"brick.clearScreen|block": "`icons.brickDisplay` clear screen",
|
||||
"brick.lightPattern|block": "%pattern",
|
||||
"brick.print|block": "`icons.brickDisplay` print %text| at x: %x| y: %y",
|
||||
"brick.setPixel|block": "`icons.brickDisplay` set pixel %on| at x: %x| y: %y",
|
||||
"brick.setStatusLight|block": "set `icons.brickButtons` to %pattern=led_pattern",
|
||||
"brick.showImage|block": "`icons.brickDisplay` show image %image=scren_image_picker",
|
||||
"brick.showImage|block": "`icons.brickDisplay` show image %image=screen_image_picker",
|
||||
"brick|block": "brick",
|
||||
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
||||
"control|block": "control",
|
||||
"motors.Motor.count|block": "`icons.motorLarge` %motor|count",
|
||||
"motors.Motor.move|block": "move `icons.motorLarge` %motor|by %angle|degrees at %power|%",
|
||||
"motors.Motor.move|block": "move `icons.motorLarge` %motor|for %value|%unit|at %speed|%",
|
||||
"motors.Motor.setBrake|block": "set `icons.motorLarge` %motor|brake %brake",
|
||||
"motors.Motor.setReversed|block": "set `icons.motorLarge` %motor|reversed %reversed",
|
||||
"motors.Motor.setSpeed|block": "set speed `icons.motorLarge` %motor|to %speed|%",
|
||||
"motors.Motor.speed|block": "`icons.motorLarge` %motor|speed",
|
||||
"motors.Motor.stop|block": "stop `icons.motorLarge` %motor",
|
||||
"motors.Motor.tachoCount|block": "`icons.motorLarge` %motor|tacho count",
|
||||
"motors.largeMotorA|block": "large A",
|
||||
"motors.largeMotorB|block": "large B",
|
||||
"motors.largeMotorC|block": "large C",
|
||||
"motors.largeMotorD|block": "large D",
|
||||
"motors.mediumMotorA|block": "medium A",
|
||||
"motors.mediumMotorB|block": "medium B",
|
||||
"motors.mediumMotorC|block": "medium C",
|
||||
"motors.mediumMotorD|block": "medium D",
|
||||
"motors.stopAllMotors|block": "stop all `icons.motorLarge`",
|
||||
"motors.Motor.setSpeed|block": "set speed of `icons.motorLarge` %motor|to %speed|%",
|
||||
"motors.SingleMotor.count|block": "`icons.motorLarge` %motor|count",
|
||||
"motors.SingleMotor.speed|block": "`icons.motorLarge` %motor|speed",
|
||||
"motors.SingleMotor.tachoCount|block": "`icons.motorLarge` %motor|tacho count",
|
||||
"motors.SynchedMotorPair.steer|block": "steer %chassis|%steering|%|at speed %speed|%|by %value|%unit",
|
||||
"motors.SynchedMotorPair.tank|block": "tank %chassis|left %speedLeft|%|right %speedRight|%|by %value|%unit",
|
||||
"motors.largeAB|block": "large A+B",
|
||||
"motors.largeAD|block": "large A+D",
|
||||
"motors.largeA|block": "large A",
|
||||
"motors.largeBC|block": "large B+C",
|
||||
"motors.largeB|block": "large B",
|
||||
"motors.largeCD|block": "large C+D",
|
||||
"motors.largeC|block": "large C",
|
||||
"motors.largeD|block": "large D",
|
||||
"motors.mediumA|block": "medium A",
|
||||
"motors.mediumB|block": "medium B",
|
||||
"motors.mediumC|block": "medium C",
|
||||
"motors.mediumD|block": "medium D",
|
||||
"motors.stopAllMotors|block": "stop all motors",
|
||||
"motors|block": "motors",
|
||||
"output|block": "output",
|
||||
"screen|block": "screen",
|
||||
"sensors|block": "sensors",
|
||||
"serial|block": "serial",
|
||||
"{id:category}Brick": "Brick",
|
||||
"{id:category}Control": "Control",
|
||||
@ -66,7 +80,9 @@
|
||||
"{id:category}Screen": "Screen",
|
||||
"{id:category}Serial": "Serial",
|
||||
"{id:group}Buttons": "Buttons",
|
||||
"{id:group}Chassis": "Chassis",
|
||||
"{id:group}Light": "Light",
|
||||
"{id:group}Motors": "Motors",
|
||||
"{id:group}Screen": "Screen"
|
||||
"{id:group}Motion": "Motion",
|
||||
"{id:group}Screen": "Screen",
|
||||
"{id:group}Sensors": "Sensors"
|
||||
}
|
@ -132,13 +132,13 @@ namespace brick {
|
||||
* Waits until the event is raised
|
||||
* @param ev the event to wait for
|
||||
*/
|
||||
//% help=input/button/wait-until
|
||||
//% blockId=buttonWaitUntil block="wait until `icons.brickButtons` %button|%event"
|
||||
//% help=input/button/pause-until
|
||||
//% blockId=buttonWaitUntil block="pause until `icons.brickButtons` %button|%event"
|
||||
//% parts="brick"
|
||||
//% blockNamespace=brick
|
||||
//% weight=98 blockGap=8
|
||||
//% group="Buttons"
|
||||
waitUntil(ev: ButtonEvent) {
|
||||
pauseUntil(ev: ButtonEvent) {
|
||||
control.waitForEvent(this._id, ev);
|
||||
}
|
||||
}
|
||||
|
@ -1,260 +1,260 @@
|
||||
namespace images {
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsBigSmile = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsHeartLarge = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsHeartSmall = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsMouth1open = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsMouth1shut = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsMouth2open = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsMouth2shut = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsSad = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsSick = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsSmile = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsSwearing = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsTalking = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsWink = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const expressionsZzz = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesAngry = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesAwake = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesBlackEye = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesBottomLeft = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesBottomRight = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesCrazy1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesCrazy2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesDisappointed = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesDizzy = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesDown = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesEvil = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesHurt = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesKnockedOut = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesLove = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesMiddleLeft = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesMiddleRight = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesNeutral = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesNuclear = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesPinchLeft = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesPinchMiddle = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesPinchRight = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesSleeping = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesTear = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesTiredLeft = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesTiredMiddle = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesTiredRight = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesToxic = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesUp = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const eyesWinking = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationAccept = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationBackward = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationDecline = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationForward = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationLeft = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationNoGo = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationQuestionMark = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationRight = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationStop1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationStop2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationThumbsDown = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationThumbsUp = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const informationWarning = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoColorSensor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoEv3icon = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoEv3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoGyroSensor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoIrBeacon = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoIrSensor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoLego = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoLargeMotor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoMindstorms = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoMediumMotor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoSoundSensor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoTempSensor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoTouchSensor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const legoUsSensor = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsBomb = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsBoom = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsFire = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsFlowers = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsForest = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsLightOff = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsLightOn = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsLightning = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsNight = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsPirate = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsSnow = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const objectsTarget = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressBar0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressBar1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressBar2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressBar3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressBar4 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDial0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDial1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDial2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDial3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDial4 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDots0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDots1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDots2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressDots3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressHourglass0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressHourglass1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressHourglass2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressTimer0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressTimer1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressTimer2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressTimer3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressTimer4 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressWaterLevel0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressWaterLevel1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressWaterLevel2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const progressWaterLevel3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemAccept1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemAccept2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemAlert = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemBox = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemBusy0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemBusy1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemDecline1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemDecline2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemDotEmpty = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemDotFull = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemEv3small = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemPlay = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider4 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider5 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider6 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider7 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres
|
||||
//% fixedInstance jres blockIdentity=brick._imagePicker
|
||||
export const systemSlider8 = screen.unpackPNG(hex``);
|
||||
}
|
||||
|
11
libs/core/input.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "pxt.h"
|
||||
|
||||
namespace sensors {
|
||||
|
||||
/**
|
||||
* Mark a sensor as used
|
||||
*/
|
||||
//%
|
||||
void __sensorUsed(int port, int type) {
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ namespace sensors.internal {
|
||||
|
||||
control.runInBackground(() => {
|
||||
let prev = query()
|
||||
changeHandler(prev, prev)
|
||||
while (true) {
|
||||
loops.pause(periodMs)
|
||||
let curr = query()
|
||||
@ -141,6 +142,11 @@ namespace sensors.internal {
|
||||
this._port = port_ - 1
|
||||
init()
|
||||
sensorInfos[this._port].sensors.push(this)
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
markUsed() {
|
||||
sensors.__sensorUsed(this._port, this._deviceType());
|
||||
}
|
||||
|
||||
_activated() { }
|
||||
@ -183,7 +189,7 @@ namespace sensors.internal {
|
||||
Low = 3,
|
||||
}
|
||||
|
||||
export class ThresholdDetector {
|
||||
export class ThresholdDetector {
|
||||
public id: number;
|
||||
private min: number;
|
||||
private max: number;
|
||||
|
@ -13,14 +13,35 @@
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#define THREAD_DBG(...)
|
||||
|
||||
#define MALLOC_LIMIT (8 * 1024 * 1024)
|
||||
#define MALLOC_CHECK_PERIOD (1024 * 1024)
|
||||
|
||||
void *xmalloc(size_t sz) {
|
||||
static size_t allocBytes = 0;
|
||||
allocBytes += sz;
|
||||
if (allocBytes >= MALLOC_CHECK_PERIOD) {
|
||||
allocBytes = 0;
|
||||
auto info = mallinfo();
|
||||
DMESG("malloc used: %d kb", info.uordblks / 1024);
|
||||
if (info.uordblks > MALLOC_LIMIT) {
|
||||
target_panic(904);
|
||||
}
|
||||
}
|
||||
auto r = malloc(sz);
|
||||
if (r == NULL)
|
||||
target_panic(905); // shouldn't happen
|
||||
return r;
|
||||
}
|
||||
|
||||
void *operator new(size_t size) {
|
||||
return malloc(size);
|
||||
return xmalloc(size);
|
||||
}
|
||||
void *operator new[](size_t size) {
|
||||
return malloc(size);
|
||||
return xmalloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *p) {
|
||||
@ -200,10 +221,6 @@ int current_time_ms() {
|
||||
return currTime() - startTime;
|
||||
}
|
||||
|
||||
int getSerialNumber() {
|
||||
return 42; // TODO
|
||||
}
|
||||
|
||||
void disposeThread(Thread *t) {
|
||||
if (allThreads == t) {
|
||||
allThreads = t->next;
|
||||
@ -376,6 +393,10 @@ static void runPoller(Thread *thr) {
|
||||
// note that this is run without the user mutex held - it should not modify any state!
|
||||
TValue prev = pxt::runAction0(query);
|
||||
|
||||
startUser();
|
||||
pxt::runAction2(thr->act, prev, prev);
|
||||
stopUser();
|
||||
|
||||
while (true) {
|
||||
sleep_core_us(us);
|
||||
if (paniced)
|
||||
|
@ -1,9 +1 @@
|
||||
//% weight=100
|
||||
namespace brick {
|
||||
|
||||
}
|
||||
|
||||
//% color="#B4009E" weight=98 icon="\uf192"
|
||||
//% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
||||
namespace sensors {
|
||||
}
|
||||
|
@ -20,3 +20,13 @@ void target_init() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace motors {
|
||||
|
||||
/**
|
||||
* Mark a motor as used
|
||||
*/
|
||||
//%
|
||||
void __motorUsed(int port, bool large) {
|
||||
}
|
||||
}
|
@ -7,6 +7,14 @@ enum Output {
|
||||
C = 0x04,
|
||||
//% block="D"
|
||||
D = 0x08,
|
||||
//% block="B+C"
|
||||
BC = Output.B | Output.C,
|
||||
//% block="A+B"
|
||||
AB = Output.A | Output.B,
|
||||
//% block="C+D"
|
||||
CD = Output.C | Output.D,
|
||||
//% block="A+D"
|
||||
AD = Output.B | Output.C,
|
||||
//% block="All"
|
||||
ALL = 0x0f
|
||||
}
|
||||
@ -17,6 +25,15 @@ enum OutputType {
|
||||
MiniTacho = 8,
|
||||
}
|
||||
|
||||
enum MoveUnit {
|
||||
//% block="rotations"
|
||||
Rotations,
|
||||
//% block="degrees"
|
||||
Degrees,
|
||||
//% block="seconds"
|
||||
Seconds
|
||||
}
|
||||
|
||||
namespace motors {
|
||||
let pwmMM: MMap
|
||||
let motorMM: MMap
|
||||
@ -34,6 +51,7 @@ namespace motors {
|
||||
pwmMM = control.mmap("/dev/lms_pwm", 0, 0)
|
||||
if (!pwmMM) control.fail("no PWM file")
|
||||
motorMM = control.mmap("/dev/lms_motor", MotorDataOff.Size * DAL.NUM_OUTPUTS, 0)
|
||||
if (!motorMM) control.fail("no motor file")
|
||||
|
||||
resetMotors()
|
||||
|
||||
@ -66,8 +84,9 @@ namespace motors {
|
||||
/**
|
||||
* Stops all motors
|
||||
*/
|
||||
//% blockId=motorStopAll block="stop all `icons.motorLarge`"
|
||||
//% weight=10 group="Motors" blockGap=8
|
||||
//% blockId=motorStopAll block="stop all motors"
|
||||
//% weight=97
|
||||
//% group="Motion"
|
||||
export function stopAllMotors() {
|
||||
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
||||
writePWM(b)
|
||||
@ -75,83 +94,44 @@ namespace motors {
|
||||
|
||||
//% fixedInstances
|
||||
export class Motor extends control.Component {
|
||||
private port: Output;
|
||||
private large: boolean;
|
||||
private brake: boolean;
|
||||
protected _port: Output;
|
||||
protected _brake: boolean;
|
||||
private _initialized: boolean;
|
||||
private _init: () => void;
|
||||
private _setSpeed: (speed: number) => void;
|
||||
private _move: (steps: boolean, stepsOrTime: number, speed: number) => void;
|
||||
|
||||
constructor(port: Output, large: boolean) {
|
||||
constructor(port: Output, init: () => void, setSpeed: (speed: number) => void, move: (steps: boolean, stepsOrTime: number, speed: number) => void) {
|
||||
super();
|
||||
this.port = port;
|
||||
this.large = large;
|
||||
this.brake = false;
|
||||
this._port = port;
|
||||
this._brake = false;
|
||||
this._initialized = false;
|
||||
this._init = init;
|
||||
this._setSpeed = setSpeed;
|
||||
this._move = move;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the motor speed level from ``-100`` to ``100``.
|
||||
* @param motor the output connection that the motor is connected to
|
||||
* @param speed the power from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
* Lazy initialization code
|
||||
*/
|
||||
//% blockId=motorSetSpeed block="set speed `icons.motorLarge` %motor|to %speed|%"
|
||||
//% weight=99 group="Motors" blockGap=8
|
||||
//% power.min=-100 power.max=100
|
||||
setSpeed(speed: number) {
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
|
||||
// per LEGO: call it power, use speed
|
||||
const b = mkCmd(this.port, DAL.opOutputSpeed, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, speed)
|
||||
writePWM(b)
|
||||
if (speed) {
|
||||
const b = mkCmd(this.port, DAL.opOutputStart, 0)
|
||||
writePWM(b);
|
||||
} else {
|
||||
this.stop();
|
||||
protected init() {
|
||||
if (!this._initialized) {
|
||||
this._initialized = true;
|
||||
this._init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the motor by a number of degrees
|
||||
* @param degrees the angle to turn the motor
|
||||
* @param angle the degrees to rotate, eg: 360
|
||||
* @param power the power from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
*/
|
||||
//% blockId=motorMove block="move `icons.motorLarge` %motor|by %angle|degrees at %power|%"
|
||||
//% weight=98 group="Motors" blockGap=8
|
||||
//% power.min=-100 power.max=100
|
||||
move(angle: number, power: number) {
|
||||
angle = angle >> 0;
|
||||
power = Math.clamp(-100, 100, power >> 0);
|
||||
|
||||
step(this.port, {
|
||||
speed: power,
|
||||
step1: 0,
|
||||
step2: angle,
|
||||
step3: 0,
|
||||
useSteps: true,
|
||||
useBrake: this.brake
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the motor
|
||||
*/
|
||||
//% blockId=motorStop block="stop `icons.motorLarge` %motor"
|
||||
//% weight=97 group="Motors"
|
||||
stop() {
|
||||
const b = mkCmd(this.port, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, this.brake ? 1 : 0)
|
||||
writePWM(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the automatic brake on or off when the motor is off
|
||||
* @param brake a value indicating if the motor should break when off
|
||||
*/
|
||||
//% blockId=outputMotorSetBrakeMode block="set `icons.motorLarge` %motor|brake %brake"
|
||||
//% brake.fieldEditor=toggleonoff
|
||||
//% weight=60 group="Motors" blockGap=8
|
||||
//% weight=60 blockGap=8
|
||||
//% group="Motion"
|
||||
setBrake(brake: boolean) {
|
||||
this.brake = brake;
|
||||
this.init();
|
||||
this._brake = brake;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,21 +139,140 @@ namespace motors {
|
||||
*/
|
||||
//% blockId=motorSetReversed block="set `icons.motorLarge` %motor|reversed %reversed"
|
||||
//% reversed.fieldEditor=toggleonoff
|
||||
//% weight=59 group="Motors"
|
||||
//% weight=59
|
||||
//% group="Motion"
|
||||
setReversed(reversed: boolean) {
|
||||
const b = mkCmd(this.port, DAL.opOutputPolarity, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, reversed ? -1 : 1);
|
||||
this.init();
|
||||
const b = mkCmd(this._port, DAL.opOutputPolarity, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, reversed ? 0 : 1);
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the motor(s).
|
||||
*/
|
||||
//%
|
||||
stop() {
|
||||
this.init();
|
||||
stop(this._port, this._brake);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the motor(s).
|
||||
*/
|
||||
//%
|
||||
reset() {
|
||||
this.init();
|
||||
reset(this._port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speed of the motor.
|
||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
*/
|
||||
//% blockId=motorSetSpeed block="set speed of `icons.motorLarge` %motor|to %speed|%"
|
||||
//% on.fieldEditor=toggleonoff
|
||||
//% weight=99 blockGap=8
|
||||
//% speed.min=-100 speed.max=100
|
||||
//% group="Motion"
|
||||
setSpeed(speed: number) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
if (!speed) // always stop
|
||||
this.stop();
|
||||
else
|
||||
this._setSpeed(speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the motor by a number of rotations, degress or seconds
|
||||
* @param value the move quantity, eg: 2
|
||||
* @param unit the meaning of the value
|
||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
*/
|
||||
//% blockId=motorMove block="move `icons.motorLarge` %motor|for %value|%unit|at %speed|%"
|
||||
//% weight=98 blockGap=8
|
||||
//% speed.min=-100 speed.max=100
|
||||
//% group="Motion"
|
||||
move(value: number, unit: MoveUnit, speed: number) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
if (!speed) {
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
let useSteps: boolean;
|
||||
let stepsOrTime: number;
|
||||
switch (unit) {
|
||||
case MoveUnit.Rotations:
|
||||
stepsOrTime = (value * 360) >> 0;
|
||||
useSteps = true;
|
||||
break;
|
||||
case MoveUnit.Degrees:
|
||||
stepsOrTime = value >> 0;
|
||||
useSteps = true;
|
||||
break;
|
||||
default:
|
||||
stepsOrTime = value;
|
||||
useSteps = false;
|
||||
break;
|
||||
}
|
||||
|
||||
this._move(useSteps, stepsOrTime, speed);
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class SingleMotor extends Motor {
|
||||
private _large: boolean;
|
||||
|
||||
constructor(port: Output, large: boolean) {
|
||||
super(port, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
||||
this._large = large;
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
markUsed() {
|
||||
motors.__motorUsed(this._port, this._large);
|
||||
}
|
||||
|
||||
private __init() {
|
||||
// specify motor size on this port
|
||||
const b = mkCmd(outOffset(this._port), DAL.opOutputSetType, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, this._large ? 0x07 : 0x08)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
private __setSpeed(speed: number) {
|
||||
const b = mkCmd(this._port, DAL.opOutputSpeed, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, speed)
|
||||
writePWM(b)
|
||||
if (speed) {
|
||||
writePWM(mkCmd(this._port, DAL.opOutputStart, 0))
|
||||
}
|
||||
}
|
||||
|
||||
private __move(steps: boolean, stepsOrTime: number, speed: number) {
|
||||
step(this._port, {
|
||||
useSteps: steps,
|
||||
step1: 0,
|
||||
step2: stepsOrTime,
|
||||
step3: 0,
|
||||
speed: speed,
|
||||
useBrake: this._brake
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor actual speed.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorSpeed block="`icons.motorLarge` %motor|speed"
|
||||
//% weight=72 group="Motors" blockGap=8
|
||||
//% weight=72 blockGap=8
|
||||
//% group="Sensors"
|
||||
speed(): number {
|
||||
return getMotorData(this.port).actualSpeed;
|
||||
this.init();
|
||||
return getMotorData(this._port).actualSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,9 +280,11 @@ namespace motors {
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorCount block="`icons.motorLarge` %motor|count"
|
||||
//% weight=71 group="Motors" blockGap=8
|
||||
//% weight=71 blockGap=8
|
||||
//% group="Sensors"
|
||||
count(): number {
|
||||
return getMotorData(this.port).count;
|
||||
this.init();
|
||||
return getMotorData(this._port).count;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,55 +292,176 @@ namespace motors {
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorTachoCount block="`icons.motorLarge` %motor|tacho count"
|
||||
//% weight=70 group="Motors"
|
||||
//% weight=70
|
||||
//% group="Sensors"
|
||||
tachoCount(): number {
|
||||
return getMotorData(this.port).tachoCount;
|
||||
this.init();
|
||||
return getMotorData(this._port).tachoCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the motor count
|
||||
*/
|
||||
//% group="Motion"
|
||||
clearCount() {
|
||||
const b = mkCmd(this.port, DAL.opOutputClearCount, 0)
|
||||
this.init();
|
||||
const b = mkCmd(this._port, DAL.opOutputClearCount, 0)
|
||||
writePWM(b)
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (this.port & (1 << i)) {
|
||||
if (this._port & (1 << i)) {
|
||||
motorMM.setNumber(NumberFormat.Int32LE, i * MotorDataOff.Size + MotorDataOff.TachoSensor, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the motor.
|
||||
*/
|
||||
reset() {
|
||||
reset(this.port);
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed fixedInstance block="large A"
|
||||
export const largeMotorA = new Motor(Output.A, true);
|
||||
export const largeA = new SingleMotor(Output.A, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large B"
|
||||
export const largeMotorB = new Motor(Output.B, true);
|
||||
export const largeB = new SingleMotor(Output.B, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large C"
|
||||
export const largeMotorC = new Motor(Output.C, true);
|
||||
export const largeC = new SingleMotor(Output.C, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large D"
|
||||
export const largeMotorD = new Motor(Output.D, true);
|
||||
export const largeD = new SingleMotor(Output.D, true);
|
||||
|
||||
//% whenUsed fixedInstance block="medium A"
|
||||
export const mediumMotorA = new Motor(Output.A, false);
|
||||
export const mediumA = new SingleMotor(Output.A, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium B"
|
||||
export const mediumMotorB = new Motor(Output.B, false);
|
||||
export const mediumB = new SingleMotor(Output.B, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium C"
|
||||
export const mediumMotorC = new Motor(Output.C, false);
|
||||
export const mediumC = new SingleMotor(Output.C, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium D"
|
||||
export const mediumMotorD = new Motor(Output.D, false);
|
||||
export const mediumD = new SingleMotor(Output.D, false);
|
||||
|
||||
//% fixedInstances
|
||||
export class SynchedMotorPair extends Motor {
|
||||
|
||||
constructor(ports: Output) {
|
||||
super(ports, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
markUsed() {
|
||||
motors.__motorUsed(this._port, true);
|
||||
}
|
||||
|
||||
private __init() {
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (this._port & (1 << i)) {
|
||||
const b = mkCmd(outOffset(1 << i), DAL.opOutputSetType, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, 0x07) // large motor
|
||||
writePWM(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private __setSpeed(speed: number) {
|
||||
syncMotors(this._port, {
|
||||
speed: speed,
|
||||
turnRatio: 0,
|
||||
useBrake: !!this._brake
|
||||
})
|
||||
}
|
||||
|
||||
private __move(steps: boolean, stepsOrTime: number, speed: number) {
|
||||
syncMotors(this._port, {
|
||||
useSteps: steps,
|
||||
speed: speed,
|
||||
turnRatio: 100, // same speed
|
||||
stepsOrTime: stepsOrTime,
|
||||
useBrake: this._brake
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the motor and the follower motor by a number of rotations
|
||||
* @param value the move quantity, eg: 2
|
||||
* @param unit the meaning of the value
|
||||
* @param steering the ratio of power sent to the follower motor, from ``-100`` to ``100``
|
||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
*/
|
||||
//% blockId=motorPairTurn block="steer %chassis|%steering|%|at speed %speed|%|by %value|%unit"
|
||||
//% weight=9 blockGap=8
|
||||
//% steering.min=-100 steering=100
|
||||
//% inlineInputMode=inline
|
||||
//% group="Chassis"
|
||||
steer(steering: number, speed: number, value: number, unit: MoveUnit) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
if (!speed) {
|
||||
stop(this._port, this._brake);
|
||||
return;
|
||||
}
|
||||
|
||||
const turnRatio = Math.clamp(-200, 200, steering + 100 >> 0);
|
||||
let useSteps: boolean;
|
||||
let stepsOrTime: number;
|
||||
switch (unit) {
|
||||
case MoveUnit.Rotations:
|
||||
stepsOrTime = (value * 360) >> 0;
|
||||
useSteps = true;
|
||||
break;
|
||||
case MoveUnit.Degrees:
|
||||
stepsOrTime = value >> 0;
|
||||
useSteps = true;
|
||||
break;
|
||||
default:
|
||||
stepsOrTime = value;
|
||||
useSteps = false;
|
||||
break;
|
||||
}
|
||||
|
||||
syncMotors(this._port, {
|
||||
useSteps: useSteps,
|
||||
speed: speed,
|
||||
turnRatio: turnRatio,
|
||||
stepsOrTime: stepsOrTime,
|
||||
useBrake: this._brake
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The Move Tank block can make a robot drive forward, backward, turn, or stop.
|
||||
* Use the Move Tank block for robot vehicles that have two Large Motors,
|
||||
* with one motor driving the left side of the vehicle and the other the right side.
|
||||
* You can make the two motors go at different speeds or in different directions
|
||||
* to make your robot turn.
|
||||
* @param value the amount of movement, eg: 2
|
||||
* @param unit
|
||||
* @param speedLeft the speed on the left motor, eg: 50
|
||||
* @param speedRight the speed on the right motor, eg: 50
|
||||
*/
|
||||
//% blockId=motorPairTank block="tank %chassis|left %speedLeft|%|right %speedRight|%|by %value|%unit"
|
||||
//% weight=9 blockGap=8
|
||||
//% speedLeft.min=-100 speedLeft=100
|
||||
//% speedRight.min=-100 speedRight=100
|
||||
//% inlineInputMode=inline
|
||||
//% group="Chassis"
|
||||
tank(speedLeft: number, speedRight: number, value: number, unit: MoveUnit) {
|
||||
speedLeft = Math.clamp(speedLeft >> 0, -100, 100);
|
||||
speedRight = Math.clamp(speedRight >> 0, -100, 100);
|
||||
const steering = (speedRight * 100 / speedLeft) >> 0;
|
||||
this.steer(speedLeft, steering, value, unit);
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed fixedInstance block="large B+C"
|
||||
export const largeBC = new SynchedMotorPair(Output.BC);
|
||||
|
||||
//% whenUsed fixedInstance block="large A+D"
|
||||
export const largeAD = new SynchedMotorPair(Output.AD);
|
||||
|
||||
//% whenUsed fixedInstance block="large A+B"
|
||||
export const largeAB = new SynchedMotorPair(Output.AB);
|
||||
|
||||
//% whenUsed fixedInstance block="large C+D"
|
||||
export const largeCD = new SynchedMotorPair(Output.CD);
|
||||
|
||||
function reset(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputReset, 0)
|
||||
@ -262,6 +484,7 @@ namespace motors {
|
||||
|
||||
// only a single output at a time
|
||||
function getMotorData(out: Output): MotorData {
|
||||
init()
|
||||
let buf = motorMM.slice(outOffset(out), MotorDataOff.Size)
|
||||
return {
|
||||
actualSpeed: buf.getNumber(NumberFormat.Int8LE, MotorDataOff.Speed),
|
||||
@ -270,6 +493,29 @@ namespace motors {
|
||||
}
|
||||
}
|
||||
|
||||
interface SyncOptions {
|
||||
useSteps?: boolean;
|
||||
speed: number;
|
||||
turnRatio: number;
|
||||
stepsOrTime?: number;
|
||||
useBrake?: boolean;
|
||||
}
|
||||
|
||||
function syncMotors(out: Output, opts: SyncOptions) {
|
||||
const cmd = opts.useSteps ? DAL.opOutputStepSync : DAL.opOutputTimeSync;
|
||||
const b = mkCmd(out, cmd, 11);
|
||||
const speed = Math.clamp(-100, 100, opts.speed);
|
||||
const turnRatio = Math.clamp(-200, 200, opts.turnRatio);
|
||||
|
||||
b.setNumber(NumberFormat.Int8LE, 2, speed)
|
||||
// note that b[3] is padding
|
||||
b.setNumber(NumberFormat.Int16LE, 4 + 4 * 0, turnRatio)
|
||||
// b[6], b[7] is padding
|
||||
b.setNumber(NumberFormat.Int32LE, 4 + 4 * 1, opts.stepsOrTime || 0)
|
||||
b.setNumber(NumberFormat.Int8LE, 4 + 4 * 2, opts.useBrake ? 1 : 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
interface StepOptions {
|
||||
power?: number;
|
||||
speed?: number; // either speed or power has to be present
|
||||
@ -280,6 +526,17 @@ namespace motors {
|
||||
useBrake?: boolean;
|
||||
}
|
||||
|
||||
function start(out: Output) {
|
||||
const b = mkCmd(out, DAL.opOutputStart, 0)
|
||||
writePWM(b);
|
||||
}
|
||||
|
||||
function stop(out: Output, brake: boolean) {
|
||||
const b = mkCmd(out, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, brake ? 1 : 0)
|
||||
writePWM(b);
|
||||
}
|
||||
|
||||
function step(out: Output, opts: StepOptions) {
|
||||
let op = opts.useSteps ? DAL.opOutputStepSpeed : DAL.opOutputTimeSpeed
|
||||
let speed = opts.speed
|
||||
|
@ -88,7 +88,7 @@ Image unpackPNG(Buffer png) {
|
||||
uint32_t byteW = (hd.width + 7) >> 3;
|
||||
uint32_t expSize = (byteW + 1) * hd.height;
|
||||
unsigned long sz = expSize;
|
||||
uint8_t *tmp = (uint8_t *)malloc(sz);
|
||||
uint8_t *tmp = (uint8_t *)xmalloc(sz);
|
||||
int code = uncompress(tmp, &sz, png->data + sizeof(hd), hd.lenIDAT);
|
||||
if (code != 0) {
|
||||
DMESG("PNG: zlib failed: %d", code);
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "pxtbase.h"
|
||||
|
||||
void *xmalloc(size_t sz);
|
||||
|
||||
namespace pxt {
|
||||
void raiseEvent(int id, int event);
|
||||
int allocateNotifyEvent();
|
||||
|
@ -10,6 +10,7 @@
|
||||
"linux.cpp",
|
||||
"mmap.cpp",
|
||||
"control.cpp",
|
||||
"serialnumber.cpp",
|
||||
"buttons.ts",
|
||||
"png.cpp",
|
||||
"screen.cpp",
|
||||
@ -17,6 +18,7 @@
|
||||
"output.cpp",
|
||||
"output.ts",
|
||||
"core.ts",
|
||||
"input.cpp",
|
||||
"input.ts",
|
||||
"shims.d.ts",
|
||||
"enums.d.ts",
|
||||
|
@ -63,16 +63,16 @@ namespace brick {
|
||||
firstChar: 32,
|
||||
// source https://github.com/lancaster-university/microbit-dal/blob/master/source/core/MicroBitFont.cpp
|
||||
data: hex`
|
||||
0000000000 0202020002 0a0a000000 0a1f0a1f0a 0e130e190e 1309041219 0609060916 0202000000 0402020204
|
||||
0204040402 000a040a00 00040e0400 0000000402 00000e0000 0000000200 1008040201 0609090906 040604040e
|
||||
070806010f 0f08040906 0c0a091f08 1f010f100f 08040e110e 1f08040201 0e110e110e 0e110e0402 0002000200
|
||||
0004000402 0804020408 000e000e00 0204080402 0e110c0004 0e11151906 06090f0909 0709070907 0e0101010e
|
||||
0709090907 0f0107010f 0f01070101 0e0119110e 09090f0909 0702020207 1f08080906 0905030509 010101010f
|
||||
111b151111 1113151911 0609090906 0709070101 060909060c 0709070911 0e01060807 1f04040404 0909090906
|
||||
1111110a04 1111151b11 0909060909 110a040404 0f0402010f 0e0202020e 0102040810 0e0808080e 040a000000
|
||||
000000001f 0204000000 000e09091e 0101070907 000e01010e 08080e090e 060907010e 0c02070202 0e090e0806
|
||||
0101070909 0200020202 0800080806 0105030509 020202020c 001b151111 0007090909 0006090906 0007090701
|
||||
000e090e08 000e010101 000c020403 02020e021c 000909091e 0011110a04 001111151b 0009060609 00110a0403
|
||||
0000000000 0202020002 0a0a000000 0a1f0a1f0a 0e130e190e 1309041219 0609060916 0202000000 0402020204
|
||||
0204040402 000a040a00 00040e0400 0000000402 00000e0000 0000000200 1008040201 0609090906 040604040e
|
||||
070806010f 0f08040906 0c0a091f08 1f010f100f 08040e110e 1f08040201 0e110e110e 0e110e0402 0002000200
|
||||
0004000402 0804020408 000e000e00 0204080402 0e110c0004 0e11151906 06090f0909 0709070907 0e0101010e
|
||||
0709090907 0f0107010f 0f01070101 0e0119110e 09090f0909 0702020207 1f08080906 0905030509 010101010f
|
||||
111b151111 1113151911 0609090906 0709070101 060909060c 0709070911 0e01060807 1f04040404 0909090906
|
||||
1111110a04 1111151b11 0909060909 110a040404 0f0402010f 0e0202020e 0102040810 0e0808080e 040a000000
|
||||
000000001f 0204000000 000e09091e 0101070907 000e01010e 08080e090e 060907010e 0c02070202 0e090e0806
|
||||
0101070909 0200020202 0800080806 0105030509 020202020c 001b151111 0007090909 0006090906 0007090701
|
||||
000e090e08 000e010101 000c020403 02020e021c 000909091e 0011110a04 001111151b 0009060609 00110a0403
|
||||
000f04020f 0c0406040c 0202020202 0302060203 0000061800
|
||||
`
|
||||
}
|
||||
@ -137,7 +137,7 @@ namespace brick {
|
||||
* Shows an image on screen
|
||||
* @param image image to draw
|
||||
*/
|
||||
//% blockId=screen_show_image block="`icons.brickDisplay` show image %image=scren_image_picker"
|
||||
//% blockId=screen_show_image block="`icons.brickDisplay` show image %image=screen_image_picker"
|
||||
//% weight=95 group="Screen" blockGap=8
|
||||
export function showImage(image: Image, delay: number = 400) {
|
||||
if (!image) return;
|
||||
@ -151,7 +151,7 @@ namespace brick {
|
||||
* An image
|
||||
* @param image the image
|
||||
*/
|
||||
//% blockId=scren_image_picker block="%image" shim=TD_ID
|
||||
//% blockId=screen_image_picker block="%image" shim=TD_ID
|
||||
//% image.fieldEditor="imagedropdown"
|
||||
//% image.fieldOptions.columns=6
|
||||
//% image.fieldOptions.hasSearchBar=true
|
||||
@ -159,7 +159,16 @@ namespace brick {
|
||||
export function _imagePicker(image: Image): Image {
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the screen
|
||||
*/
|
||||
//% blockId=screen_clear_screen block="`icons.brickDisplay` clear screen"
|
||||
//% weight=94 group="Screen" blockGap=8
|
||||
export function clearScreen() {
|
||||
screen.clear();
|
||||
}
|
||||
|
||||
export function drawRect(x: number, y: number, w: number, h: number, mode = Draw.Normal) {
|
||||
x |= 0;
|
||||
y |= 0;
|
||||
|
77
libs/core/serialnumber.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include "pxt.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BTPROTO_HCI 1
|
||||
#define HCIGETDEVLIST _IOR('H', 210, int)
|
||||
#define HCIGETDEVINFO _IOR('H', 211, int)
|
||||
|
||||
struct hci_dev_info {
|
||||
uint16_t dev_id;
|
||||
char name[8];
|
||||
uint8_t bdaddr[6];
|
||||
uint32_t padding[32];
|
||||
};
|
||||
|
||||
struct hci_dev_req {
|
||||
uint16_t dev_id;
|
||||
uint32_t dev_opt;
|
||||
};
|
||||
|
||||
struct hci_dev_list_req {
|
||||
uint16_t dev_num;
|
||||
hci_dev_req dev_req[2];
|
||||
};
|
||||
|
||||
static uint32_t bt_addr() {
|
||||
uint32_t res = -1;
|
||||
|
||||
int fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
|
||||
if (fd < 0) {
|
||||
DMESG("BT_ADDR: can't open HCI socket");
|
||||
return res;
|
||||
}
|
||||
|
||||
hci_dev_list_req dl;
|
||||
dl.dev_num = 1;
|
||||
|
||||
if (ioctl(fd, HCIGETDEVLIST, (void *)&dl) < 0) {
|
||||
DMESG("BT_ADDR: can't get HCI device list");
|
||||
goto done;
|
||||
}
|
||||
|
||||
hci_dev_info di;
|
||||
di.dev_id = dl.dev_req[0].dev_id;
|
||||
|
||||
if (ioctl(fd, HCIGETDEVINFO, (void *)&di) < 0) {
|
||||
DMESG("BT_ADDR: can't get HCI device info");
|
||||
goto done;
|
||||
}
|
||||
|
||||
memcpy(&res, di.bdaddr, 4);
|
||||
res *= 0x1000193;
|
||||
res += di.bdaddr[4];
|
||||
res *= 0x1000193;
|
||||
res += di.bdaddr[5];
|
||||
|
||||
done:
|
||||
close(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
namespace pxt {
|
||||
|
||||
int getSerialNumber() {
|
||||
static int serial;
|
||||
|
||||
if (serial != 0)
|
||||
return serial;
|
||||
|
||||
serial = bt_addr() & 0x7fffffff;
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
} // namespace pxt
|
16
libs/core/shims.d.ts
vendored
@ -120,5 +120,21 @@ declare namespace output {
|
||||
//% shim=output::createBuffer
|
||||
function createBuffer(size: int32): Buffer;
|
||||
}
|
||||
declare namespace motors {
|
||||
|
||||
/**
|
||||
* Mark a motor as used
|
||||
*/
|
||||
//% shim=motors::__motorUsed
|
||||
function __motorUsed(port: int32, large: boolean): void;
|
||||
}
|
||||
declare namespace sensors {
|
||||
|
||||
/**
|
||||
* Mark a sensor as used
|
||||
*/
|
||||
//% shim=sensors::__sensorUsed
|
||||
function __sensorUsed(port: int32, type: int32): void;
|
||||
}
|
||||
|
||||
// Auto-generated. Do not edit. Really.
|
||||
|
@ -1,81 +0,0 @@
|
||||
namespace pxsim {
|
||||
enum ThresholdState {
|
||||
High,
|
||||
Low,
|
||||
Normal
|
||||
}
|
||||
|
||||
export class AnalogSensorState {
|
||||
public sensorUsed: boolean = false;
|
||||
|
||||
private level: number;
|
||||
private state = ThresholdState.Normal;
|
||||
|
||||
constructor(public id: number, private min = 0, private max = 255, private lowThreshold = 64, private highThreshold = 192) {
|
||||
this.level = Math.ceil((max - min) / 2);
|
||||
}
|
||||
|
||||
public setUsed() {
|
||||
if (!this.sensorUsed) {
|
||||
this.sensorUsed = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public setLevel(level: number) {
|
||||
this.level = this.clampValue(level);
|
||||
|
||||
if (this.level >= this.highThreshold) {
|
||||
this.setState(ThresholdState.High);
|
||||
}
|
||||
else if (this.level <= this.lowThreshold) {
|
||||
this.setState(ThresholdState.Low);
|
||||
}
|
||||
else {
|
||||
this.setState(ThresholdState.Normal);
|
||||
}
|
||||
}
|
||||
|
||||
public getLevel(): number {
|
||||
return this.level;
|
||||
}
|
||||
|
||||
public setLowThreshold(value: number) {
|
||||
this.lowThreshold = this.clampValue(value);
|
||||
this.highThreshold = Math.max(this.lowThreshold + 1, this.highThreshold);
|
||||
}
|
||||
|
||||
public setHighThreshold(value: number) {
|
||||
this.highThreshold = this.clampValue(value);
|
||||
this.lowThreshold = Math.min(this.highThreshold - 1, this.lowThreshold);
|
||||
}
|
||||
|
||||
private clampValue(value: number) {
|
||||
if (value < this.min) {
|
||||
return this.min;
|
||||
}
|
||||
else if (value > this.max) {
|
||||
return this.max;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private setState(state: ThresholdState) {
|
||||
if (this.state === state) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
switch (state) {
|
||||
case ThresholdState.High:
|
||||
board().bus.queue(this.id, DAL.ANALOG_THRESHOLD_HIGH);
|
||||
break;
|
||||
case ThresholdState.Low:
|
||||
board().bus.queue(this.id, DAL.ANALOG_THRESHOLD_LOW);
|
||||
break;
|
||||
case ThresholdState.Normal:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
|
||||
namespace pxsim.pins {
|
||||
export class CommonPin extends Pin {
|
||||
used: boolean;
|
||||
}
|
||||
|
||||
export class DigitalPin extends CommonPin {
|
||||
}
|
||||
|
||||
export class AnalogPin extends CommonPin {
|
||||
|
||||
}
|
||||
|
||||
export function markUsed(name: CommonPin) {
|
||||
if (!name.used) {
|
||||
name.used = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.DigitalPinMethods {
|
||||
export function digitalRead(name: pins.DigitalPin): number {
|
||||
return name.digitalReadPin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a pin or connector value to either 0 or 1.
|
||||
* @param value value to set on the pin, 1 eg,0
|
||||
*/
|
||||
export function digitalWrite(name: pins.DigitalPin, value: number): void {
|
||||
name.digitalWritePin(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this pin to a digital input, and generates events where the timestamp is the duration
|
||||
* that this pin was either ``high`` or ``low``.
|
||||
*/
|
||||
export function onPulsed(name: pins.DigitalPin, pulse: number, body: RefAction): void {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the duration of a pulse in microseconds
|
||||
* @param value the value of the pulse (default high)
|
||||
* @param maximum duration in micro-seconds
|
||||
*/
|
||||
export function pulseIn(name: pins.DigitalPin, pulse: number, maxDuration = 2000000): number {
|
||||
// TODO
|
||||
return 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the pull of this pin.
|
||||
* @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone
|
||||
*/
|
||||
export function setPull(name: pins.DigitalPin, pull: number): void {
|
||||
name.setPull(pull);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a pin is pressed.
|
||||
* @param body the code to run when the pin is pressed
|
||||
*/
|
||||
export function onPressed(name: pins.DigitalPin, body: RefAction): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a pin is released.
|
||||
* @param body the code to run when the pin is released
|
||||
*/
|
||||
export function onReleased(name: pins.DigitalPin, body: RefAction): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pin state (pressed or not). Requires to hold the ground to close the circuit.
|
||||
* @param name pin used to detect the touch
|
||||
*/
|
||||
export function isPressed(name: pins.DigitalPin): boolean {
|
||||
return name.isTouched();
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.AnalogPinMethods {
|
||||
/**
|
||||
* Read the connector value as analog, that is, as a value comprised between 0 and 1023.
|
||||
*/
|
||||
export function analogRead(name: pins.AnalogPin): number {
|
||||
pins.markUsed(name);
|
||||
return name.analogReadPin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connector value as analog. Value must be comprised between 0 and 1023.
|
||||
* @param value value to write to the pin between ``0`` and ``1023``. eg:1023,0
|
||||
*/
|
||||
export function analogWrite(name: pins.AnalogPin, value: number): void {
|
||||
pins.markUsed(name);
|
||||
name.analogWritePin(value);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the Pulse-width modulation (PWM) of the analog output to the given value in
|
||||
* **microseconds** or `1/1000` milliseconds.
|
||||
* If this pin is not configured as an analog output (using `analog write pin`), the operation has
|
||||
* no effect.
|
||||
* @param micros period in micro seconds. eg:20000
|
||||
*/
|
||||
export function analogSetPeriod(name: pins.AnalogPin, micros: number): void {
|
||||
pins.markUsed(name);
|
||||
name.analogSetPeriod(micros);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a value to the servo, controlling the shaft accordingly. On a standard servo, this will
|
||||
* set the angle of the shaft (in degrees), moving the shaft to that orientation. On a continuous
|
||||
* rotation servo, this will set the speed of the servo (with ``0`` being full-speed in one
|
||||
* direction, ``180`` being full speed in the other, and a value near ``90`` being no movement).
|
||||
* @param value angle or rotation speed, eg:180,90,0
|
||||
*/
|
||||
export function servoWrite(name: pins.AnalogPin, value: number): void {
|
||||
pins.markUsed(name);
|
||||
name.servoWritePin(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analog/pwm output, configures the period to be 20 ms, and sets the
|
||||
* pulse width, based on the value it is given **microseconds** or `1/1000` milliseconds.
|
||||
* @param micros pulse duration in micro seconds, eg:1500
|
||||
*/
|
||||
export function servoSetPulse(name: pins.AnalogPin, micros: number): void {
|
||||
pins.markUsed(name);
|
||||
// TODO fix pxt
|
||||
// name.servoSetPulse(micros);
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.PwmPinMethods {
|
||||
export function analogSetPeriod(name: pins.AnalogPin, micros: number): void {
|
||||
name.analogSetPeriod(micros);
|
||||
}
|
||||
|
||||
export function servoWrite(name: pins.AnalogPin, value: number): void {
|
||||
name.servoWritePin(value);
|
||||
}
|
||||
|
||||
export function servoSetPulse(name: pins.AnalogPin, micros: number): void {
|
||||
name.servoSetPulse(name.id, micros);
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.pins {
|
||||
export function pulseDuration(): number {
|
||||
// bus last event timestamp
|
||||
return 500;
|
||||
}
|
||||
|
||||
export function createBuffer(sz: number) {
|
||||
return pxsim.BufferMethods.createBuffer(sz)
|
||||
}
|
||||
|
||||
export function spiWrite(value: number): number {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function i2cReadBuffer(address: number, size: number, repeat?: boolean): RefBuffer {
|
||||
// fake reading zeros
|
||||
return createBuffer(size)
|
||||
}
|
||||
|
||||
export function i2cWriteBuffer(address: number, buf: RefBuffer, repeat?: boolean): void {
|
||||
// fake - noop
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +1,36 @@
|
||||
screen.clear()
|
||||
screen.print("PXT!", 10, 30, Draw.Quad)
|
||||
brick.print("PXT!", 10, 30, Draw.Quad)
|
||||
|
||||
screen.drawRect(40, 40, 20, 10, Draw.Fill)
|
||||
motors.setStatusLight(LightsPattern.Orange)
|
||||
brick.drawRect(40, 40, 20, 10, Draw.Fill)
|
||||
brick.setStatusLight(LightsPattern.Orange)
|
||||
|
||||
screen.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent)
|
||||
brick.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent)
|
||||
|
||||
sensors.buttonEnter.onEvent(ButtonEvent.Click, () => {
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, () => {
|
||||
screen.clear()
|
||||
})
|
||||
|
||||
sensors.buttonLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.drawRect(10, 70, 20, 10, Draw.Fill)
|
||||
motors.setStatusLight(LightsPattern.Red)
|
||||
screen.setFont(screen.microbitFont())
|
||||
brick.buttonLeft.onEvent(ButtonEvent.Click, () => {
|
||||
brick.drawRect(10, 70, 20, 10, Draw.Fill)
|
||||
brick.setStatusLight(LightsPattern.Red)
|
||||
brick.setFont(brick.microbitFont())
|
||||
})
|
||||
|
||||
sensors.buttonRight.onEvent(ButtonEvent.Click, () => {
|
||||
screen.print("Right!", 10, 60)
|
||||
brick.buttonRight.onEvent(ButtonEvent.Click, () => {
|
||||
brick.print("Right!", 10, 60)
|
||||
})
|
||||
|
||||
sensors.buttonDown.onEvent(ButtonEvent.Click, () => {
|
||||
screen.print("Down! ", 10, 60)
|
||||
brick.buttonDown.onEvent(ButtonEvent.Click, () => {
|
||||
brick.print("Down! ", 10, 60)
|
||||
})
|
||||
|
||||
sensors.buttonUp.onEvent(ButtonEvent.Click, () => {
|
||||
screen.print("Up! ", 10, 60)
|
||||
brick.buttonUp.onEvent(ButtonEvent.Click, () => {
|
||||
brick.print("Up! ", 10, 60)
|
||||
})
|
||||
|
||||
|
||||
let num = 0
|
||||
|
||||
sensors.touchSensor1.onEvent(TouchSensorEvent.Bumped, () => {
|
||||
screen.print("Click! " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
sensors.remoteButtonTopLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.print("TOPLEFT " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
sensors.remoteButtonTopRight.onEvent(ButtonEvent.Down, () => {
|
||||
screen.print("TOPRIGH " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
loops.forever(() => {
|
||||
serial.writeDmesg()
|
||||
loops.pause(100)
|
||||
|
@ -1,15 +1,21 @@
|
||||
|
||||
//% color="#68C3E2" weight=100
|
||||
//% groups='["Light", "Buttons", "Screen"]'
|
||||
//% labelLineWidth=0
|
||||
namespace brick {
|
||||
}
|
||||
|
||||
|
||||
//% color="#C8509B" weight=95
|
||||
//% color="#C8509B" weight=95 icon="\uf192"
|
||||
//% labelLineWidth=0
|
||||
//% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
||||
//% groupIcons='["\uf101","\uf103","\uf102","","","\uf104"]'
|
||||
namespace sensors {
|
||||
}
|
||||
|
||||
//% color="#A5CA18" weight=90 icon="\uf185"
|
||||
//% groups='["Motion", "Sensors", "Chassis"]'
|
||||
//% labelLineWidth=0
|
||||
namespace motors {
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,8 @@
|
||||
"description": "The EV3 library",
|
||||
"files": [
|
||||
"README.md",
|
||||
"ns.ts"
|
||||
"ns.ts",
|
||||
"startup.ts"
|
||||
],
|
||||
"dependencies": {
|
||||
"base": "file:../base",
|
||||
|
4
libs/ev3/startup.ts
Normal file
@ -0,0 +1,4 @@
|
||||
// This is the last thing executed before user code
|
||||
|
||||
// We pause for 100ms to give time to read sensor values, so they work in on_start block
|
||||
loops.pause(100)
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"sensors.InfraredSensor.onEvent": "Registers code to run when an object is getting near.",
|
||||
"sensors.InfraredSensor.onEvent|param|handler": "the code to run when detected",
|
||||
"sensors.InfraredSensor.pauseUntil": "Waits for the event to occur",
|
||||
"sensors.InfraredSensor.proximity": "Get the promixity measured by the infrared sensor, from ``0`` (close) to ``100`` (far)",
|
||||
"sensors.InfraredSensor.remoteCommand": "Get the remote commandreceived the infrared sensor.",
|
||||
"sensors.InfraredSensor.waitUntil": "Waits for the event to occur",
|
||||
"sensors.RemoteInfraredBeaconButton.isPressed": "Check if a remote button is currently pressed or not.",
|
||||
"sensors.RemoteInfraredBeaconButton.onEvent": "Do something when a button or sensor is clicked, up or down",
|
||||
"sensors.RemoteInfraredBeaconButton.onEvent|param|body": "code to run when the event is raised",
|
||||
|
@ -2,9 +2,9 @@
|
||||
"InfraredSensorEvent.ObjectDetected|block": "object detected",
|
||||
"InfraredSensorEvent.ObjectNear|block": "object near",
|
||||
"sensors.InfraredSensor.onEvent|block": "on `icons.infraredSensor` %sensor|%event",
|
||||
"sensors.InfraredSensor.pauseUntil|block": "pause until `icons.infraredSensor` %sensor| %event",
|
||||
"sensors.InfraredSensor.proximity|block": "`icons.infraredSensor` %sensor|proximity",
|
||||
"sensors.InfraredSensor.remoteCommand|block": "`icons.infraredSensor` %sensor|remote command",
|
||||
"sensors.InfraredSensor.waitUntil|block": "wait until `icons.infraredSensor` %sensor| %event",
|
||||
"sensors.RemoteInfraredBeaconButton.isPressed|block": "`icons.infraredSensor` %button|is pressed",
|
||||
"sensors.RemoteInfraredBeaconButton.onEvent|block": "on `icons.infraredSensor` %button|%event",
|
||||
"sensors.RemoteInfraredBeaconButton.wasPressed|block": "`icons.infraredSensor` %button|was pressed",
|
||||
|
@ -205,7 +205,7 @@ namespace sensors {
|
||||
* Waits for the event to occur
|
||||
*/
|
||||
//% help=input/ultrasonic/wait
|
||||
//% block="wait until `icons.infraredSensor` %sensor| %event"
|
||||
//% block="pause until `icons.infraredSensor` %sensor| %event"
|
||||
//% blockId=infraredwait
|
||||
//% parts="infraredsensor"
|
||||
//% sensor.fieldEditor="imagedropdown"
|
||||
@ -213,7 +213,7 @@ namespace sensors {
|
||||
//% blockNamespace=sensors
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
waitUntil(event: InfraredSensorEvent) {
|
||||
pauseUntil(event: InfraredSensorEvent) {
|
||||
control.waitForEvent(this._id, event);
|
||||
}
|
||||
|
||||
|
@ -26,5 +26,6 @@
|
||||
"music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
|
||||
"music.setVolume": "Set the output volume of the sound synthesizer.",
|
||||
"music.setVolume|param|volume": "the volume 0...256, eg: 128",
|
||||
"music.stopAllSounds": "Play a tone through the speaker for some amount of time.",
|
||||
"music.tempo": "Return the tempo in beats per minute (bpm).\nTempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play."
|
||||
}
|
@ -31,6 +31,7 @@
|
||||
"music.ringTone|block": "ring tone|at %note=device_note",
|
||||
"music.setTempo|block": "set tempo to %value|(bpm)",
|
||||
"music.setVolume|block": "set volume %volume",
|
||||
"music.stopAllSounds|block": "stop all sounds",
|
||||
"music.tempo|block": "tempo (bpm)",
|
||||
"music|block": "music",
|
||||
"sounds.animalsCatPurr|block": "Animals cat purr",
|
||||
|
@ -163,6 +163,21 @@ void playTone(int frequency, int ms) {
|
||||
sleep_ms(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a tone through the speaker for some amount of time.
|
||||
*/
|
||||
//% help=music/stop-all-sounds
|
||||
//% blockId=music_stop_all_sounds block="stop all sounds"
|
||||
//% parts="headphone"
|
||||
//% blockNamespace=music
|
||||
//% weight=76 blockGap=8
|
||||
void stopAllSounds() {
|
||||
if (currentSample) {
|
||||
samplePtr = currentSample->length;
|
||||
}
|
||||
_stopSound();
|
||||
}
|
||||
|
||||
/** Makes a sound bound to a buffer in WAV format. */
|
||||
//%
|
||||
Sound fromWAV(Buffer buf) {
|
||||
|
10
libs/music/shims.d.ts
vendored
@ -25,6 +25,16 @@ declare namespace music {
|
||||
//% weight=76 blockGap=8 shim=music::playTone
|
||||
function playTone(frequency: int32, ms: int32): void;
|
||||
|
||||
/**
|
||||
* Play a tone through the speaker for some amount of time.
|
||||
*/
|
||||
//% help=music/stop-all-sounds
|
||||
//% blockId=music_stop_all_sounds block="stop all sounds"
|
||||
//% parts="headphone"
|
||||
//% blockNamespace=music
|
||||
//% weight=76 blockGap=8 shim=music::stopAllSounds
|
||||
function stopAllSounds(): void;
|
||||
|
||||
/** Makes a sound bound to a buffer in WAV format. */
|
||||
//% shim=music::fromWAV
|
||||
function fromWAV(buf: Buffer): Sound;
|
||||
|
@ -3,6 +3,6 @@
|
||||
"sensors.TouchSensor.isPressed": "Check if touch sensor is touched.",
|
||||
"sensors.TouchSensor.onEvent": "Do something when a touch sensor is touched...",
|
||||
"sensors.TouchSensor.onEvent|param|body": "code to run when the event is raised",
|
||||
"sensors.TouchSensor.waitUntil": "Wait until the touch sensor is touched",
|
||||
"sensors.TouchSensor.pauseUntil": "Wait until the touch sensor is touched",
|
||||
"sensors.TouchSensor.wasPressed": "Check if touch sensor is touched since it was last checked."
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
"TouchSensorEvent.Released|block": "released",
|
||||
"sensors.TouchSensor.isPressed|block": "`icons.touchSensor` %sensor|is pressed",
|
||||
"sensors.TouchSensor.onEvent|block": "on `icons.touchSensor` %sensor|%event",
|
||||
"sensors.TouchSensor.waitUntil|block": "wait until `icons.touchSensor` %sensor|%event",
|
||||
"sensors.TouchSensor.pauseUntil|block": "pause until `icons.touchSensor` %sensor|%event",
|
||||
"sensors.TouchSensor.wasPressed|block": "`icons.touchSensor` %sensor|was pressed",
|
||||
"sensors.touchSensor1|block": "1",
|
||||
"sensors.touchSensor2|block": "2",
|
||||
|
@ -58,16 +58,16 @@ namespace sensors {
|
||||
* @param sensor the touch sensor that needs to be clicked or used
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
*/
|
||||
//% help=input/touch-sensor/wait-until
|
||||
//% blockId=touchWaitUntil block="wait until `icons.touchSensor` %sensor|%event"
|
||||
//% help=input/touch-sensor/pause-until
|
||||
//% blockId=touchWaitUntil block="pause until `icons.touchSensor` %sensor|%event"
|
||||
//% parts="touch"
|
||||
//% sensor.fieldEditor="imagedropdown"
|
||||
//% sensor.fieldOptions.columns=4
|
||||
//% blockNamespace=sensors
|
||||
//% weight=98 blockGap=8
|
||||
//% group="Touch Sensor"
|
||||
waitUntil(ev: TouchSensorEvent) {
|
||||
this.button.waitUntil(<ButtonEvent><number>ev);
|
||||
pauseUntil(ev: TouchSensorEvent) {
|
||||
this.button.pauseUntil(<ButtonEvent><number>ev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
11
libs/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"rootDir": ".",
|
||||
"newLine": "LF",
|
||||
"sourceMap": false,
|
||||
"types": []
|
||||
}
|
||||
}
|
@ -2,5 +2,5 @@
|
||||
"sensors.UltraSonicSensor.distance": "Gets the distance from the sonar in centimeters",
|
||||
"sensors.UltraSonicSensor.onEvent": "Registers code to run when the given color is close",
|
||||
"sensors.UltraSonicSensor.onEvent|param|handler": "the code to run when detected",
|
||||
"sensors.UltraSonicSensor.waitUntil": "Waits for the event to occur"
|
||||
"sensors.UltraSonicSensor.pauseUntil": "Waits for the event to occur"
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
"UltrasonicSensorEvent.ObjectNear|block": "object near",
|
||||
"sensors.UltraSonicSensor.distance|block": "`icons.ultrasonicSensor` %sensor|distance",
|
||||
"sensors.UltraSonicSensor.onEvent|block": "on `icons.ultrasonicSensor` %sensor|%event",
|
||||
"sensors.UltraSonicSensor.waitUntil|block": "wait until `icons.ultrasonicSensor` %sensor| %event",
|
||||
"sensors.UltraSonicSensor.pauseUntil|block": "pause until `icons.ultrasonicSensor` %sensor| %event",
|
||||
"sensors.ultrasonic1|block": "1",
|
||||
"sensors.ultrasonic2|block": "2",
|
||||
"sensors.ultrasonic3|block": "3",
|
||||
|
@ -58,7 +58,7 @@ namespace sensors {
|
||||
* Waits for the event to occur
|
||||
*/
|
||||
//% help=input/ultrasonic/wait
|
||||
//% block="wait until `icons.ultrasonicSensor` %sensor| %event"
|
||||
//% block="pause until `icons.ultrasonicSensor` %sensor| %event"
|
||||
//% blockId=ultrasonicWait
|
||||
//% parts="ultrasonicsensor"
|
||||
//% sensor.fieldEditor="imagedropdown"
|
||||
@ -66,7 +66,7 @@ namespace sensors {
|
||||
//% blockNamespace=sensors
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Ultrasonic Sensor"
|
||||
waitUntil(event: UltrasonicSensorEvent) {
|
||||
pauseUntil(event: UltrasonicSensorEvent) {
|
||||
control.waitForEvent(this._id, event);
|
||||
}
|
||||
|
||||
@ -92,13 +92,13 @@ namespace sensors {
|
||||
|
||||
//% fixedInstance whenUsed block="1" jres=icons.port1
|
||||
export const ultrasonic1: UltraSonicSensor = new UltraSonicSensor(1)
|
||||
|
||||
//% fixedInstance whenUsed block="4" jres=icons.port4
|
||||
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
||||
|
||||
//% fixedInstance whenUsed block="2" jres=icons.port2
|
||||
export const ultrasonic2: UltraSonicSensor = new UltraSonicSensor(2)
|
||||
|
||||
//% fixedInstance whenUsed block="3" jres=icons.port3
|
||||
export const ultrasonic3: UltraSonicSensor = new UltraSonicSensor(3)
|
||||
|
||||
//% fixedInstance whenUsed block="4" jres=icons.port4
|
||||
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
||||
}
|
||||
|
10
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.38",
|
||||
"version": "0.0.41",
|
||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
@ -39,11 +39,13 @@
|
||||
"semantic-ui-less": "^2.2.4",
|
||||
"@types/bluebird": "2.0.33",
|
||||
"@types/jquery": "3.2.16",
|
||||
"@types/node": "8.0.53"
|
||||
"@types/marked": "0.3.0",
|
||||
"@types/node": "8.0.53",
|
||||
"webfonts-generator": "^0.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.14.12",
|
||||
"pxt-core": "3.0.1"
|
||||
"pxt-common-packages": "0.14.13",
|
||||
"pxt-core": "3.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||
|
@ -20,7 +20,7 @@
|
||||
"simulator": {
|
||||
"autoRun": true,
|
||||
"streams": true,
|
||||
"aspectRatio": 0.67,
|
||||
"aspectRatio": 0.5,
|
||||
"parts": false,
|
||||
"enableTrace": true,
|
||||
"boardDefinition": {
|
||||
@ -136,6 +136,9 @@
|
||||
},
|
||||
"monacoColors": {
|
||||
"editor.background": "#ecf6ff"
|
||||
}
|
||||
}
|
||||
},
|
||||
"simAnimationEnter": "horizontal flip in",
|
||||
"simAnimationExit": "horizontal flip out"
|
||||
},
|
||||
"ignoreDocsErrors": true
|
||||
}
|
||||
|
140
sim/dalboard.ts
@ -22,17 +22,7 @@ namespace pxsim {
|
||||
D13
|
||||
}
|
||||
|
||||
export class DalBoard extends CoreBoard implements
|
||||
AccelerometerBoard,
|
||||
CommonBoard,
|
||||
// LightBoard,
|
||||
LightSensorBoard,
|
||||
MicrophoneBoard,
|
||||
MusicBoard,
|
||||
SlideSwitchBoard,
|
||||
TemperatureBoard,
|
||||
InfraredBoard,
|
||||
CapTouchBoard {
|
||||
export class EV3Board extends CoreBoard {
|
||||
// state & update logic for component services
|
||||
// neopixelState: CommonNeoPixelState;
|
||||
buttonState: EV3ButtonState;
|
||||
@ -44,80 +34,42 @@ namespace pxsim {
|
||||
edgeConnectorState: EdgeConnectorState;
|
||||
capacitiveSensorState: CapacitiveSensorState;
|
||||
accelerometerState: AccelerometerState;
|
||||
audioState: AudioState;
|
||||
touchButtonState: TouchButtonState;
|
||||
irState: InfraredState;
|
||||
lightState: EV3LightState;
|
||||
screenState: EV3ScreenState;
|
||||
|
||||
view: SVGSVGElement;
|
||||
|
||||
outputState: EV3OutputState;
|
||||
analogState: EV3AnalogState;
|
||||
uartState: EV3UArtState;
|
||||
motorState: EV3MotorState;
|
||||
screenState: EV3ScreenState;
|
||||
audioState: AudioState;
|
||||
|
||||
inputNodes: SensorNode[] = [];
|
||||
brickNode: BrickNode;
|
||||
outputNodes: MotorNode[] = [];
|
||||
|
||||
private motorMap: pxt.Map<number> = {
|
||||
0x01: 0,
|
||||
0x02: 1,
|
||||
0x04: 2,
|
||||
0x08: 3
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.bus.setNotify(DAL.DEVICE_ID_NOTIFY, DAL.DEVICE_ID_NOTIFY_ONE);
|
||||
|
||||
//components
|
||||
this.brickNode = new BrickNode();
|
||||
|
||||
this.builtinParts["buttons"] = this.buttonState = new EV3ButtonState();
|
||||
this.builtinParts["light"] = this.lightState = new EV3LightState();
|
||||
this.builtinParts["screen"] = this.screenState = new EV3ScreenState();
|
||||
this.builtinParts["audio"] = this.audioState = new AudioState();
|
||||
|
||||
/*this.builtinParts["neopixel"] = this.neopixelState = new CommonNeoPixelState();
|
||||
this.builtinParts["buttonpair"] = this.buttonState = new CommonButtonState();
|
||||
|
||||
this.builtinParts["switch"] = this.slideSwitchState = new SlideSwitchState();
|
||||
this.builtinParts["lightsensor"] = this.lightSensorState = new AnalogSensorState(DAL.DEVICE_ID_LIGHT_SENSOR, 0, 255);
|
||||
this.builtinParts["thermometer"] = this.thermometerState = new AnalogSensorState(DAL.DEVICE_ID_THERMOMETER, -5, 50);
|
||||
this.builtinParts["soundsensor"] = this.microphoneState = new AnalogSensorState(DAL.DEVICE_ID_TOUCH_SENSOR + 1, 0, 255);
|
||||
this.builtinParts["capacitivesensor"] = this.capacitiveSensorState = new CapacitiveSensorState({
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3,
|
||||
6: 4,
|
||||
9: 5,
|
||||
10: 6,
|
||||
12: 7
|
||||
});
|
||||
|
||||
this.builtinParts["accelerometer"] = this.accelerometerState = new AccelerometerState(runtime);
|
||||
this.builtinParts["edgeconnector"] = this.edgeConnectorState = new EdgeConnectorState({
|
||||
pins: [
|
||||
pxsim.CPlayPinName.A0,
|
||||
pxsim.CPlayPinName.A1,
|
||||
pxsim.CPlayPinName.A2,
|
||||
pxsim.CPlayPinName.A3,
|
||||
pxsim.CPlayPinName.A4,
|
||||
pxsim.CPlayPinName.A5,
|
||||
pxsim.CPlayPinName.A6,
|
||||
pxsim.CPlayPinName.A7,
|
||||
pxsim.CPlayPinName.A8,
|
||||
pxsim.CPlayPinName.A9,
|
||||
pxsim.CPlayPinName.D4,
|
||||
pxsim.CPlayPinName.D5,
|
||||
pxsim.CPlayPinName.D6,
|
||||
pxsim.CPlayPinName.D7,
|
||||
pxsim.CPlayPinName.D8,
|
||||
pxsim.CPlayPinName.D13
|
||||
]
|
||||
});
|
||||
this.builtinParts["microservo"] = this.edgeConnectorState;
|
||||
|
||||
this.builtinVisuals["microservo"] = () => new visuals.MicroServoView();
|
||||
this.builtinPartVisuals["microservo"] = (xy: visuals.Coord) => visuals.mkMicroServoPart(xy);
|
||||
this.touchButtonState = new TouchButtonState([
|
||||
pxsim.CPlayPinName.A1,
|
||||
pxsim.CPlayPinName.A2,
|
||||
pxsim.CPlayPinName.A3,
|
||||
pxsim.CPlayPinName.A4,
|
||||
pxsim.CPlayPinName.A5,
|
||||
pxsim.CPlayPinName.A6,
|
||||
pxsim.CPlayPinName.A7
|
||||
]);
|
||||
|
||||
this.builtinParts["ir"] = this.irState = new InfraredState();*/
|
||||
this.outputState = new EV3OutputState();
|
||||
this.analogState = new EV3AnalogState();
|
||||
this.uartState = new EV3UArtState();
|
||||
this.motorState = new EV3MotorState();
|
||||
this.screenState = new EV3ScreenState();
|
||||
this.audioState = new AudioState();
|
||||
}
|
||||
|
||||
receiveMessage(msg: SimulatorMessage) {
|
||||
@ -182,11 +134,45 @@ namespace pxsim {
|
||||
getDefaultPitchPin() {
|
||||
return this.edgeConnectorState.getPin(CPlayPinName.D6);
|
||||
}
|
||||
|
||||
getBrickNode() {
|
||||
return this.brickNode;
|
||||
}
|
||||
|
||||
getMotor(port: number, large?: boolean): MotorNode[] {
|
||||
if (port == 0xFF) return this.getMotors(); // Return all motors
|
||||
const motorPort = this.motorMap[port];
|
||||
if (this.outputNodes[motorPort] == undefined) {
|
||||
this.outputNodes[motorPort] = large ?
|
||||
new LargeMotorNode(motorPort) : new MediumMotorNode(motorPort);
|
||||
}
|
||||
return [this.outputNodes[motorPort]];
|
||||
}
|
||||
|
||||
getMotors() {
|
||||
return this.outputNodes;
|
||||
}
|
||||
|
||||
getSensor(port: number, type: number): SensorNode {
|
||||
if (this.inputNodes[port] == undefined) {
|
||||
switch (type) {
|
||||
case DAL.DEVICE_TYPE_GYRO: this.inputNodes[port] = new GyroSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_TOUCH: this.inputNodes[port] = new TouchSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_ULTRASONIC: this.inputNodes[port] = new UltrasonicSensorNode(port); break;
|
||||
}
|
||||
}
|
||||
return this.inputNodes[port];
|
||||
}
|
||||
|
||||
getInputNodes() {
|
||||
return this.inputNodes;
|
||||
}
|
||||
}
|
||||
|
||||
export function initRuntimeWithDalBoard() {
|
||||
U.assert(!runtime.board);
|
||||
let b = new DalBoard();
|
||||
let b = new EV3Board();
|
||||
runtime.board = b;
|
||||
runtime.postError = (e) => {
|
||||
// TODO
|
||||
@ -194,6 +180,10 @@ namespace pxsim {
|
||||
}
|
||||
}
|
||||
|
||||
export function ev3board(): EV3Board {
|
||||
return runtime.board as EV3Board;
|
||||
}
|
||||
|
||||
if (!pxsim.initCurrentRuntime) {
|
||||
pxsim.initCurrentRuntime = initRuntimeWithDalBoard;
|
||||
}
|
||||
|
@ -1,91 +0,0 @@
|
||||
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||
/// <reference path="../node_modules/pxt-core/built/pxtrunner.d.ts"/>
|
||||
|
||||
//HACK: allows instructions.html to access pxtblocks without requiring simulator.html to import blocks as well
|
||||
if (!(<any>window).pxt) (<any>window).pxt = {};
|
||||
import pxtrunner = pxt.runner;
|
||||
import pxtdocs = pxt.docs;
|
||||
|
||||
namespace pxsim.instructions {
|
||||
export function drawInstructions() {
|
||||
pxsim.visuals.mkBoardView = (opts: pxsim.visuals.BoardViewOptions): pxsim.visuals.BoardView => {
|
||||
return new visuals.EV3BoardSvg({
|
||||
runtime: runtime,
|
||||
theme: visuals.randomTheme(),
|
||||
disableTilt: false,
|
||||
wireframe: opts.wireframe,
|
||||
});
|
||||
}
|
||||
|
||||
let getQsVal = parseQueryString();
|
||||
|
||||
//project name
|
||||
let name = getQsVal("name") || "Untitled";
|
||||
|
||||
// board def
|
||||
const boardDef = JSON.parse(getQsVal("board")) as pxsim.BoardDefinition;
|
||||
|
||||
//parts list
|
||||
let parts = (getQsVal("parts") || "").split(" ");
|
||||
parts.sort();
|
||||
|
||||
// parts definitions
|
||||
let partDefinitions = JSON.parse(getQsVal("partdefs") || "{}") as pxsim.Map<PartDefinition>
|
||||
|
||||
//fn args
|
||||
let fnArgs = JSON.parse((getQsVal("fnArgs") || "{}"));
|
||||
|
||||
//project code
|
||||
let tsCode = getQsVal("code");
|
||||
let tsPackage = getQsVal("package") || "";
|
||||
let codeSpinnerDiv = document.getElementById("proj-code-spinner");
|
||||
let codeContainerDiv = document.getElementById("proj-code-container");
|
||||
if (tsCode) {
|
||||
//we use the docs renderer to decompile the code to blocks and render it
|
||||
//TODO: render the blocks code directly
|
||||
let md =
|
||||
`\`\`\`blocks
|
||||
${tsCode}
|
||||
\`\`\`
|
||||
\`\`\`package
|
||||
${tsPackage}
|
||||
\`\`\`
|
||||
`
|
||||
|
||||
pxtdocs.requireMarked = function () { return (<any>window).marked; }
|
||||
pxtrunner.renderMarkdownAsync(codeContainerDiv, md)
|
||||
.done(function () {
|
||||
let codeSvg = $("#proj-code-container svg");
|
||||
if (codeSvg.length > 0) {
|
||||
//code rendered successfully as blocks
|
||||
codeSvg.css("width", "inherit");
|
||||
codeSvg.css("height", "inherit");
|
||||
//takes the svg out of the wrapper markdown
|
||||
codeContainerDiv.innerHTML = "";
|
||||
codeContainerDiv.appendChild(codeSvg[0]);
|
||||
} else {
|
||||
//code failed to convert to blocks, display as typescript instead
|
||||
codeContainerDiv.innerText = tsCode;
|
||||
}
|
||||
$(codeContainerDiv).show();
|
||||
$(codeSpinnerDiv).hide();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (name)
|
||||
$("#proj-title").text(name);
|
||||
|
||||
//init runtime
|
||||
if (!pxsim.initCurrentRuntime)
|
||||
pxsim.initCurrentRuntime = initRuntimeWithDalBoard;
|
||||
|
||||
renderParts({
|
||||
name,
|
||||
boardDef,
|
||||
parts,
|
||||
partDefinitions,
|
||||
fnArgs
|
||||
})
|
||||
}
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en" data-framework="typescript">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Assembly Instructions</title>
|
||||
<style>
|
||||
|
||||
svg {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.blocklyText, .ace_editor {
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace !important;
|
||||
}
|
||||
|
||||
.blocklyText, .ace_editor {
|
||||
font-size: 1rem !important;
|
||||
}
|
||||
|
||||
.blocklyTreeLabel {
|
||||
font-size: 1.25rem !important;
|
||||
}
|
||||
|
||||
.blocklyCheckbox {
|
||||
fill: #ff3030 !important;
|
||||
text-shadow: 0px 0px 6px #f00;
|
||||
font-size: 17pt !important;
|
||||
}
|
||||
|
||||
.ui.card .blocklyPreview {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: calc(100% - 1em);
|
||||
max-height: calc(100% - 1em);
|
||||
}
|
||||
|
||||
code {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
code.lang-config, code.lang-package { display:none; }
|
||||
|
||||
code.lang-blocks::before,
|
||||
code.lang-sig::before,
|
||||
code.lang-block::before,
|
||||
code.lang-shuffle::before,
|
||||
code.lang-sim::before,
|
||||
code.lang-cards::before,
|
||||
code.lang-namespaces::before,
|
||||
code.lang-codecard::before {
|
||||
content: "...";
|
||||
position: absolute;
|
||||
top: calc(50% - 0.5em);
|
||||
left: calc(50% - 5em);
|
||||
}
|
||||
|
||||
code.lang-blocks,
|
||||
code.lang-sig,
|
||||
code.lang-block,
|
||||
code.lang-shuffle,
|
||||
code.lang-sim,
|
||||
code.lang-cards,
|
||||
code.lang-namespaces,
|
||||
code.lang-codecard {
|
||||
color: transparent;
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
@import "/cdn/semantic.css";
|
||||
@import "/cdn/icons.css";
|
||||
</style>
|
||||
<style>
|
||||
html {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: "Lucida Console", Monaco, monospace;
|
||||
}
|
||||
|
||||
div {
|
||||
/*undo semantic UI*/
|
||||
box-sizing: content-box;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
/*TODO: Share CSS with main webpage*/
|
||||
|
||||
.organization {
|
||||
position: absolute;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
height: 4rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: normal;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
font-family: 'Segoe UI', 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#front-panel .board-svg {
|
||||
position: absolute;
|
||||
left: 2rem;
|
||||
width: 300px;
|
||||
top: 16rem;
|
||||
}
|
||||
|
||||
#proj-title {
|
||||
width: 100%;
|
||||
font-size: 70px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
#proj-code {
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
position: absolute;
|
||||
right: 2rem;
|
||||
top: 16rem;
|
||||
}
|
||||
#proj-code-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 4px;
|
||||
overflow: hidden;
|
||||
display: none;
|
||||
}
|
||||
#proj-code-spinner {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.back-panel svg {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
left: inherit;
|
||||
bottom: -7px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id='loading' class="ui active inverted dimmer">
|
||||
<div class="ui large loader"></div>
|
||||
</div>
|
||||
<script>
|
||||
// This line gets patched up by the cloud
|
||||
var pxtConfig = null;
|
||||
</script>
|
||||
<script type="text/javascript" src="/cdn/lzma/lzma_worker-min.js"></script>
|
||||
<script type="text/javascript" src="/cdn/marked/marked.min.js"></script>
|
||||
<script type="text/javascript" src="/cdn/jquery.js"></script>
|
||||
<script type="text/javascript" src="/cdn/typescript.js"></script>
|
||||
<script type="text/javascript" src="/cdn/blockly/blockly_compressed.js"></script>
|
||||
<script type="text/javascript" src="/cdn/blockly/blocks_compressed.js"></script>
|
||||
<script type="text/javascript" src="/cdn/blockly/msg/js/en.js"></script>
|
||||
<script type="text/javascript" src="/cdn/pxtlib.js"></script>
|
||||
<script type="text/javascript" src="/cdn/pxtblocks.js"></script>
|
||||
<script type="text/javascript" src="/cdn/pxtsim.js"></script>
|
||||
<script type="text/javascript" src="/cdn/pxtrunner.js"></script>
|
||||
<script type="text/javascript" src="/cdn/semantic.js"></script>
|
||||
<script type="text/javascript" src="/embed.js"></script>
|
||||
<script type="text/javascript" src="/sim/common-sim.js"></script>
|
||||
<script type="text/javascript" src="/sim/sim.js"></script>
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
ksRunnerReady(function() {
|
||||
var orgLogo = pxt.appTarget.appTheme.organizationLogo;
|
||||
if (orgLogo)
|
||||
$('#front-panel').append(
|
||||
$('<img/>').attr('class', 'organization').attr('src', orgLogo)
|
||||
);
|
||||
var loading = document.getElementById('loading');
|
||||
pxsim.instructions.drawInstructions();
|
||||
$(loading).hide();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
<div id="front-panel" class="instr-panel">
|
||||
<h1 id="proj-title"></h1>
|
||||
|
||||
<!--TODO: extract real code snapshot from PXT -->
|
||||
<div id="proj-code">
|
||||
<i id="proj-code-spinner" class="spinner loading icon"></i>
|
||||
<div id="proj-code-container">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
68
sim/state/analog.ts
Normal file
@ -0,0 +1,68 @@
|
||||
namespace pxsim {
|
||||
|
||||
enum AnalogOff {
|
||||
InPin1 = 0, // int16[4]
|
||||
InPin6 = 8, // int16[4]
|
||||
OutPin5 = 16, // int16[4]
|
||||
BatteryTemp = 24, // int16
|
||||
MotorCurrent = 26, // int16
|
||||
BatteryCurrent = 28, // int16
|
||||
Cell123456 = 30, // int16
|
||||
Pin1 = 32, // int16[300][4]
|
||||
Pin6 = 2432, // int16[300][4]
|
||||
Actual = 4832, // uint16[4]
|
||||
LogIn = 4840, // uint16[4]
|
||||
LogOut = 4848, // uint16[4]
|
||||
NxtCol = 4856, // uint16[36][4] - NxtColor*4
|
||||
OutPin5Low = 5144, // int16[4]
|
||||
Updated = 5152, // int8[4]
|
||||
InDcm = 5156, // int8[4]
|
||||
InConn = 5160, // int8[4]
|
||||
OutDcm = 5164, // int8[4]
|
||||
OutConn = 5168, // int8[4]
|
||||
Size = 5172
|
||||
}
|
||||
|
||||
export class EV3AnalogState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(5172)
|
||||
MMapMethods.register("/dev/lms_analog", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
//console.log("analog before read");
|
||||
const inputNodes = ev3board().getInputNodes();
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const node = inputNodes[port];
|
||||
if (node) {
|
||||
data[AnalogOff.InConn + port] = node.isUart() ? DAL.CONN_INPUT_UART : DAL.CONN_INPUT_DUMB;
|
||||
if (node.isAnalog() && node.hasData()) {
|
||||
//data[AnalogOff.InPin6 + 2 * port] = node.getValue();
|
||||
util.map16Bit(data, AnalogOff.InPin6 + 2 * port, node.getValue())
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
for (let i = 0; i < buf.data.length; ++i)
|
||||
buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("analog read");
|
||||
console.log(buf.data);
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
console.log("analog write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
console.log("analog ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
27
sim/state/brick.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/// <reference path="./nodeTypes.ts"/>
|
||||
|
||||
namespace pxsim {
|
||||
|
||||
export class PortNode extends BaseNode {
|
||||
id = NodeType.Port;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class BrickNode extends BaseNode {
|
||||
id = NodeType.Brick;
|
||||
|
||||
buttonState: EV3ButtonState;
|
||||
lightState: EV3LightState;
|
||||
|
||||
constructor() {
|
||||
super(-1);
|
||||
|
||||
this.buttonState = new EV3ButtonState();
|
||||
this.lightState = new EV3LightState();
|
||||
}
|
||||
}
|
||||
}
|
46
sim/state/color.ts
Normal file
@ -0,0 +1,46 @@
|
||||
/// <reference path="./sensor.ts"/>
|
||||
|
||||
namespace pxsim {
|
||||
|
||||
export enum ColorSensorMode {
|
||||
Reflected = 0,
|
||||
Ambient = 1,
|
||||
Colors = 2,
|
||||
RefRaw = 3,
|
||||
RgbRaw = 4,
|
||||
ColorCal = 5
|
||||
}
|
||||
|
||||
export enum ThresholdState {
|
||||
Normal = 1,
|
||||
High = 2,
|
||||
Low = 3,
|
||||
}
|
||||
|
||||
export class ColorSensorNode extends UartSensorNode {
|
||||
id = NodeType.ColorSensor;
|
||||
|
||||
private color: number;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_COLOR;
|
||||
}
|
||||
|
||||
setColor(color: number) {
|
||||
this.color = color;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.color;
|
||||
}
|
||||
}
|
||||
}
|
@ -63,7 +63,6 @@ namespace pxsim.MMapMethods {
|
||||
|
||||
export function write(m: MMap, data: Buffer): number {
|
||||
return m.impl.write(data)
|
||||
|
||||
}
|
||||
|
||||
export function read(m: MMap, data: Buffer): number {
|
||||
|
47
sim/state/gyro.ts
Normal file
@ -0,0 +1,47 @@
|
||||
namespace pxsim {
|
||||
const enum GyroSensorMode {
|
||||
None = -1,
|
||||
Angle = 0,
|
||||
Rate = 1,
|
||||
}
|
||||
|
||||
export class GyroSensorNode extends UartSensorNode {
|
||||
id = NodeType.GyroSensor;
|
||||
|
||||
private angle: number = 0;
|
||||
private rate: number = 0;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_GYRO;
|
||||
}
|
||||
|
||||
setAngle(angle: number) {
|
||||
if (this.angle != angle) {
|
||||
this.angle = angle;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
setRate(rate: number) {
|
||||
if (this.rate != rate) {
|
||||
this.rate = rate;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.mode == GyroSensorMode.Angle ? this.angle :
|
||||
this.mode == GyroSensorMode.Rate ? this.rate : 0;
|
||||
}
|
||||
}
|
||||
}
|
18
sim/state/input.ts
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
namespace pxsim.motors {
|
||||
|
||||
export function __motorUsed(port: number, large: boolean) {
|
||||
console.log("MOTOR INIT " + port);
|
||||
const motors = ev3board().getMotor(port, large);
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.sensors {
|
||||
|
||||
export function __sensorUsed(port: number, type: number) {
|
||||
console.log("SENSOR INIT " + port + ", type: " + type);
|
||||
const sensor = ev3board().getSensor(port, type);
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ namespace pxsim {
|
||||
namespace pxsim.output {
|
||||
|
||||
export function setLights(pattern: number) {
|
||||
const lightState = (board() as DalBoard).lightState;
|
||||
const lightState = ev3board().getBrickNode().lightState;
|
||||
lightState.lightPattern = pattern;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
49
sim/state/motor.ts
Normal file
@ -0,0 +1,49 @@
|
||||
namespace pxsim {
|
||||
|
||||
enum MotorDataOff {
|
||||
TachoCounts = 0, // int32
|
||||
Speed = 4, // int8
|
||||
Padding = 5, // int8[3]
|
||||
TachoSensor = 8, // int32
|
||||
Size = 12
|
||||
}
|
||||
|
||||
export class EV3MotorState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(12 * DAL.NUM_OUTPUTS)
|
||||
MMapMethods.register("/dev/lms_motor", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
console.log("motor before read");
|
||||
for (let port = 0; port < DAL.NUM_OUTPUTS; ++port) {
|
||||
data[MotorDataOff.TachoCounts * port] = 0; // Tacho count
|
||||
data[MotorDataOff.Speed * port] = 50; // Speed
|
||||
data[MotorDataOff.TachoSensor * port] = 0; // Count
|
||||
}
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
for (let i = 0; i < buf.data.length; ++i)
|
||||
buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("motor read");
|
||||
console.log(buf.data);
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
if (buf.data.length == 0) return 2;
|
||||
const cmd = buf.data[0];
|
||||
console.log("motor write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
console.log("motor ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
73
sim/state/motors.ts
Normal file
@ -0,0 +1,73 @@
|
||||
namespace pxsim {
|
||||
|
||||
export class MotorNode extends BaseNode {
|
||||
isOutput = true;
|
||||
|
||||
public angle: number = 0;
|
||||
|
||||
private speed: number;
|
||||
private large: boolean;
|
||||
private rotation: number;
|
||||
private polarity: boolean;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
setSpeed(speed: number) {
|
||||
if (this.speed != speed) {
|
||||
this.speed = speed;
|
||||
this.changed = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
setLarge(large: boolean) {
|
||||
this.large = large;
|
||||
}
|
||||
|
||||
getSpeed() {
|
||||
return this.speed;
|
||||
}
|
||||
|
||||
stepSpeed(speed: number, angle: number, brake: boolean) {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
setPolarity(polarity: number) {
|
||||
// Either 1 or 255 (reverse)
|
||||
this.polarity = polarity === 255;
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
reset() {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
stop() {
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
start() {
|
||||
// TODO: implement
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
export class MediumMotorNode extends MotorNode {
|
||||
id = NodeType.MediumMotor;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
}
|
||||
|
||||
export class LargeMotorNode extends MotorNode {
|
||||
id = NodeType.LargeMotor;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
36
sim/state/nodeTypes.ts
Normal file
@ -0,0 +1,36 @@
|
||||
namespace pxsim {
|
||||
export enum NodeType {
|
||||
Port = 0,
|
||||
Brick = 1,
|
||||
TouchSensor = 2,
|
||||
MediumMotor = 3,
|
||||
LargeMotor = 4,
|
||||
GyroSensor = 5,
|
||||
ColorSensor = 6,
|
||||
UltrasonicSensor = 7
|
||||
}
|
||||
|
||||
export interface Node {
|
||||
id: number;
|
||||
didChange(): boolean;
|
||||
}
|
||||
|
||||
export class BaseNode implements Node {
|
||||
public id: number;
|
||||
public port: number;
|
||||
public isOutput = false;
|
||||
|
||||
private used = false;
|
||||
protected changed = true;
|
||||
|
||||
constructor(port: number) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
didChange() {
|
||||
const res = this.changed;
|
||||
this.changed = false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
104
sim/state/output.ts
Normal file
@ -0,0 +1,104 @@
|
||||
namespace pxsim {
|
||||
|
||||
export class EV3OutputState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(10)
|
||||
MMapMethods.register("/dev/lms_pwm", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
//console.log("pwm before read");
|
||||
for (let i = 0; i < 10; ++i)
|
||||
data[i] = 0
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
for (let i = 0; i < buf.data.length; ++i)
|
||||
buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("pwm read");
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
if (buf.data.length == 0) return 2;
|
||||
const cmd = buf.data[0];
|
||||
switch (cmd) {
|
||||
case DAL.opProgramStart: {
|
||||
// init
|
||||
console.log('init');
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputReset: {
|
||||
// reset
|
||||
const port = buf.data[1];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.reset());
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputStepSpeed: {
|
||||
// step speed
|
||||
const port = buf.data[1];
|
||||
const speed = buf.data[2];
|
||||
// note that b[3] is padding
|
||||
const step1 = buf.data[4];
|
||||
const step2 = buf.data[5]; // angle
|
||||
const step3 = buf.data[6];
|
||||
const brake = buf.data[7];
|
||||
//console.log(buf);
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.stepSpeed(speed, step2, brake === 1));
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputStop: {
|
||||
// stop
|
||||
const port = buf.data[1];
|
||||
const brake = buf.data[2];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.stop());
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputSpeed: {
|
||||
// setSpeed
|
||||
const port = buf.data[1];
|
||||
const speed = buf.data[2];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.setSpeed(speed));
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputStart: {
|
||||
// start
|
||||
const port = buf.data[1];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.start());
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputPolarity: {
|
||||
// reverse
|
||||
const port = buf.data[1];
|
||||
const polarity = buf.data[2];
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.setPolarity(polarity));
|
||||
return 2;
|
||||
}
|
||||
case DAL.opOutputSetType: {
|
||||
const port = buf.data[1];
|
||||
const large = buf.data[2] == 0x07;
|
||||
const motors = ev3board().getMotor(port);
|
||||
motors.forEach(motor => motor.setLarge(large));
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("pwm write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
console.log("pwm ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@ namespace pxsim {
|
||||
|
||||
|
||||
export class EV3ScreenState {
|
||||
shouldUpdate: boolean;
|
||||
points: Uint8Array;
|
||||
constructor() {
|
||||
this.points = new Uint8Array(visuals.SCREEN_WIDTH * visuals.SCREEN_HEIGHT)
|
||||
@ -24,12 +23,13 @@ namespace pxsim {
|
||||
|
||||
setPixel(x: number, y: number, v: number) {
|
||||
this.applyMode(OFF(x, y), v)
|
||||
this.shouldUpdate = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
clear() {
|
||||
for (let i = 0; i < this.points.length; ++i)
|
||||
this.points[i] = 0;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
blitLineCore(x: number, y: number, w: number, buf: RefBuffer, mode: Draw, offset = 0) {
|
||||
@ -58,7 +58,7 @@ namespace pxsim {
|
||||
}
|
||||
}
|
||||
|
||||
this.shouldUpdate = true;
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
|
||||
clearLine(x: number, y: number, w: number) {
|
||||
@ -81,12 +81,12 @@ namespace pxsim.screen {
|
||||
function YY(v: number) { return v >> 16 }
|
||||
|
||||
export function _setPixel(x: number, y: number, mode: Draw) {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
screenState.setPixel(x, y, mode);
|
||||
}
|
||||
|
||||
export function _blitLine(xw: number, y: number, buf: RefBuffer, mode: Draw) {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
screenState.blitLineCore(XX(xw), y, YY(xw), buf, mode)
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ namespace pxsim.screen {
|
||||
return ((x + 7) >> 3)
|
||||
}
|
||||
export function clear(): void {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
screenState.clear()
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@ namespace pxsim.ImageMethods {
|
||||
}
|
||||
|
||||
export function draw(buf: RefBuffer, x: number, y: number, mode: Draw): void {
|
||||
const screenState = (board() as DalBoard).screenState;
|
||||
const screenState = ev3board().screenState;
|
||||
|
||||
if (!screen.isValidImage(buf))
|
||||
return;
|
||||
|
73
sim/state/sensor.ts
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
namespace pxsim {
|
||||
|
||||
export class SensorNode extends BaseNode {
|
||||
|
||||
protected mode: number;
|
||||
protected valueChanged: boolean;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
public isUart() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public isAnalog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public getValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
setMode(mode: number) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_NONE;
|
||||
}
|
||||
|
||||
public hasData() {
|
||||
return true;
|
||||
}
|
||||
|
||||
valueChange() {
|
||||
const res = this.valueChanged;
|
||||
this.valueChanged = false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export class AnalogSensorNode extends SensorNode {
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
public isUart() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public isAnalog() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class UartSensorNode extends SensorNode {
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
hasChanged() {
|
||||
return this.changed;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,11 +3,16 @@ namespace pxsim.music {
|
||||
export function fromWAV(buf: RefBuffer) {
|
||||
return incr(buf)
|
||||
}
|
||||
|
||||
export function stopAllSounds() {
|
||||
SoundMethods.stop()
|
||||
}
|
||||
}
|
||||
|
||||
namespace pxsim.SoundMethods {
|
||||
let numSoundsPlaying = 0;
|
||||
const soundsLimit = 1;
|
||||
let audio: HTMLAudioElement;
|
||||
|
||||
export function buffer(buf: RefBuffer) {
|
||||
return incr(buf)
|
||||
@ -27,7 +32,7 @@ namespace pxsim.SoundMethods {
|
||||
}
|
||||
return new Promise<void>(resolve => {
|
||||
let url = "data:audio/wav;base64," + btoa(uint8ArrayToString(buf.data))
|
||||
let audio = new Audio(url)
|
||||
audio = new Audio(url)
|
||||
audio.onended = () => {
|
||||
resolve();
|
||||
numSoundsPlaying--;
|
||||
@ -36,5 +41,15 @@ namespace pxsim.SoundMethods {
|
||||
audio.play()
|
||||
})
|
||||
}
|
||||
|
||||
export function stop() {
|
||||
return new Promise<void>(resolve => {
|
||||
if (audio) {
|
||||
audio.pause();
|
||||
numSoundsPlaying--;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
42
sim/state/touch.ts
Normal file
@ -0,0 +1,42 @@
|
||||
namespace pxsim {
|
||||
|
||||
export const TOUCH_SENSOR_ANALOG_PRESSED = 2600;
|
||||
|
||||
export class TouchSensorNode extends AnalogSensorNode {
|
||||
id = NodeType.TouchSensor;
|
||||
|
||||
private pressed: boolean[];
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
this.pressed = [];
|
||||
}
|
||||
|
||||
public setPressed(pressed: boolean) {
|
||||
this.pressed.push(pressed);
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
}
|
||||
|
||||
public isPressed() {
|
||||
return this.pressed;
|
||||
}
|
||||
|
||||
public getValue() {
|
||||
if (this.pressed.length) {
|
||||
if (this.pressed.pop())
|
||||
return TOUCH_SENSOR_ANALOG_PRESSED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_TOUCH;
|
||||
}
|
||||
|
||||
public hasData() {
|
||||
return this.pressed.length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
156
sim/state/uart.ts
Normal file
@ -0,0 +1,156 @@
|
||||
namespace pxsim {
|
||||
|
||||
enum UartOff {
|
||||
TypeData = 0, // Types[8][4]
|
||||
Repeat = 1792, // uint16[300][4]
|
||||
Raw = 4192, // int8[32][300][4]
|
||||
Actual = 42592, // uint16[4]
|
||||
LogIn = 42600, // uint16[4]
|
||||
Status = 42608, // int8[4]
|
||||
Output = 42612, // int8[32][4]
|
||||
OutputLength = 42740, // int8[4]
|
||||
Size = 42744
|
||||
}
|
||||
|
||||
enum UartStatus {
|
||||
UART_PORT_CHANGED = 1,
|
||||
UART_DATA_READY = 8
|
||||
}
|
||||
|
||||
enum IO {
|
||||
UART_SET_CONN = 0xc00c7500,
|
||||
UART_READ_MODE_INFO = 0xc03c7501,
|
||||
UART_NACK_MODE_INFO = 0xc03c7502,
|
||||
UART_CLEAR_CHANGED = 0xc03c7503,
|
||||
IIC_SET_CONN = 0xc00c6902,
|
||||
IIC_READ_TYPE_INFO = 0xc03c6903,
|
||||
IIC_SETUP = 0xc04c6905,
|
||||
IIC_SET = 0xc02c6906,
|
||||
TST_PIN_ON = 0xc00b7401,
|
||||
TST_PIN_OFF = 0xc00b7402,
|
||||
TST_PIN_READ = 0xc00b7403,
|
||||
TST_PIN_WRITE = 0xc00b7404,
|
||||
TST_UART_ON = 0xc0487405,
|
||||
TST_UART_OFF = 0xc0487406,
|
||||
TST_UART_EN = 0xc0487407,
|
||||
TST_UART_DIS = 0xc0487408,
|
||||
TST_UART_READ = 0xc0487409,
|
||||
TST_UART_WRITE = 0xc048740a,
|
||||
}
|
||||
|
||||
|
||||
enum DevConOff {
|
||||
Connection = 0, // int8[4]
|
||||
Type = 4, // int8[4]
|
||||
Mode = 8, // int8[4]
|
||||
Size = 12
|
||||
}
|
||||
|
||||
enum UartCtlOff {
|
||||
TypeData = 0, // Types
|
||||
Port = 56, // int8
|
||||
Mode = 57, // int8
|
||||
Size = 58
|
||||
}
|
||||
|
||||
enum TypesOff {
|
||||
Name = 0, // int8[12]
|
||||
Type = 12, // int8
|
||||
Connection = 13, // int8
|
||||
Mode = 14, // int8
|
||||
DataSets = 15, // int8
|
||||
Format = 16, // int8
|
||||
Figures = 17, // int8
|
||||
Decimals = 18, // int8
|
||||
Views = 19, // int8
|
||||
RawMin = 20, // float32
|
||||
RawMax = 24, // float32
|
||||
PctMin = 28, // float32
|
||||
PctMax = 32, // float32
|
||||
SiMin = 36, // float32
|
||||
SiMax = 40, // float32
|
||||
InvalidTime = 44, // uint16
|
||||
IdValue = 46, // uint16
|
||||
Pins = 48, // int8
|
||||
Symbol = 49, // int8[5]
|
||||
Align = 54, // uint16
|
||||
Size = 56
|
||||
}
|
||||
|
||||
export class EV3UArtState {
|
||||
|
||||
constructor() {
|
||||
let data = new Uint8Array(UartOff.Size);
|
||||
MMapMethods.register("/dev/lms_uart", {
|
||||
data,
|
||||
beforeMemRead: () => {
|
||||
//console.log("uart before read");
|
||||
const inputNodes = ev3board().getInputNodes();
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const node = inputNodes[port];
|
||||
if (node) {
|
||||
// Actual
|
||||
const index = 0; //UartOff.Actual + port * 2;
|
||||
data[UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index] = node.getValue();
|
||||
// Status
|
||||
data[UartOff.Status + port] = node.valueChange() ? UartStatus.UART_PORT_CHANGED : UartStatus.UART_DATA_READY;
|
||||
}
|
||||
}
|
||||
},
|
||||
read: buf => {
|
||||
let v = "vSIM"
|
||||
// for (let i = 0; i < buf.data.length; ++i)
|
||||
// buf.data[i] = v.charCodeAt(i) || 0
|
||||
console.log("uart read");
|
||||
console.log(buf.data);
|
||||
return buf.data.length
|
||||
},
|
||||
write: buf => {
|
||||
console.log("uart write");
|
||||
console.log(buf);
|
||||
return 2
|
||||
},
|
||||
ioctl: (id, buf) => {
|
||||
switch (id) {
|
||||
case IO.UART_SET_CONN: {
|
||||
// Set mode
|
||||
console.log("IO.UART_SET_CONN");
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const connection = buf.data[DevConOff.Connection + port]; // CONN_NONE, CONN_INPUT_UART
|
||||
const type = buf.data[DevConOff.Type + port];
|
||||
const mode = buf.data[DevConOff.Mode + port];
|
||||
console.log(`${port}, mode: ${mode}`)
|
||||
const node = ev3board().getInputNodes()[port];
|
||||
if (node) node.setMode(mode);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
case IO.UART_CLEAR_CHANGED: {
|
||||
console.log("IO.UART_CLEAR_CHANGED")
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
const connection = buf.data[DevConOff.Connection + port]; // CONN_NONE, CONN_INPUT_UART
|
||||
const type = buf.data[DevConOff.Type + port];
|
||||
const mode = buf.data[DevConOff.Mode + port];
|
||||
const node = ev3board().getInputNodes()[port];
|
||||
if (node) node.setMode(mode);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
case IO.UART_READ_MODE_INFO: {
|
||||
console.log("IO.UART_READ_MODE_INFO")
|
||||
const port = buf.data[UartCtlOff.Port];
|
||||
const mode = buf.data[UartCtlOff.Mode];
|
||||
const node = ev3board().getInputNodes()[port];
|
||||
if (node) buf.data[UartCtlOff.TypeData + TypesOff.Type] = node.getDeviceType(); // DEVICE_TYPE_NONE, DEVICE_TYPE_TOUCH,
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
console.log("uart ioctl");
|
||||
console.log(id);
|
||||
console.log(buf);
|
||||
return 2;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
31
sim/state/ultrasonic.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/// <reference path="./sensor.ts"/>
|
||||
|
||||
namespace pxsim {
|
||||
export class UltrasonicSensorNode extends UartSensorNode {
|
||||
id = NodeType.UltrasonicSensor;
|
||||
|
||||
private distance: number = 50;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_ULTRASONIC;
|
||||
}
|
||||
|
||||
setDistance(distance: number) {
|
||||
if (this.distance != distance) {
|
||||
this.distance = distance;
|
||||
this.changed = true;
|
||||
this.valueChanged = true;
|
||||
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.distance;
|
||||
}
|
||||
}
|
||||
}
|
7
sim/state/util.ts
Normal file
@ -0,0 +1,7 @@
|
||||
namespace pxsim.util {
|
||||
|
||||
export function map16Bit(buffer: Uint8Array, index: number, value: number) {
|
||||
buffer[index] = (value >> 8) & 0xff;
|
||||
buffer[index+1] = value & 0xff;
|
||||
}
|
||||
}
|
32
sim/visuals/assets/Color Sensor.svg
Normal file
@ -0,0 +1,32 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 33.22 34">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-448.15" y1="475.99" x2="-448.15" y2="475.83" gradientTransform="matrix(32.16, 0, 0, -33.37, 14429.08, 15914.64)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>Color Sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg41">
|
||||
<g id="color_box" data-name="color box">
|
||||
<g id="color_grey" data-name="color grey">
|
||||
<path id="color_sideboxes" data-name="color sideboxes" d="M2.14,9.19H34a.7.7,0,0,1,.7.7V28a.7.7,0,0,1-.7.7H2.14a.7.7,0,0,1-.7-.7V9.89A.7.7,0,0,1,2.14,9.19Z" transform="translate(-1.44 -1.6)" style="fill: #a8aaa8"/>
|
||||
<g id="color_bigbox-2" data-name="color bigbox-2">
|
||||
<image width="33" height="34" transform="translate(0.06)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAjCAYAAADxG9hnAAAACXBIWXMAAAsSAAALEgHS3X78AAAAzUlEQVRYR+3YMU4DMRBG4W8Q5eYMUEMuw/3ScQDugkTPcoSsa4ZibYjcUMVQ+Ekjj+Tif7YrT2Sm/8BtayIisOCurtemYEXJzIzMFBEL7vGIJ7vMtVnxgje8q09zxAmvOONzQJ1r3gnH9jQLHuw3cmMMB3tewXIZGrVG8p056vS/MkV6pkjPFOmZIj1TpGeK9EyRninSM0V6pkjPFOmZIj2XIn81n0h+RAo+sNWNUbXV3NI+4Sueaz9iJNFouWu0iVFEHIwb0jQK1szcvgDqy2NNnOFs5AAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path d="M5,3.33h26c1,0,1.78.57,1.78,1.27V32.77c0,.7-.8,1.27-1.78,1.27H5c-1,0-1.78-.57-1.78-1.27V4.6C3.25,3.9,4.05,3.33,5,3.33Z" transform="translate(-1.44 -1.6)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="color_side_black_4" data-name="color side black 4" x="31.83" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_3" data-name="color side black 3" x="0.84" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_2" data-name="color side black 2" x="31.83" y="18.34" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black1" data-name="color side black1" x="0.84" y="18.34" width="0.7" height="5.58"/>
|
||||
</g>
|
||||
<path id="color_red" data-name="color red" d="M11.63,23.43a6.32,6.32,0,0,1,.15-1.37,8.79,8.79,0,1,1,12.54,0,6.42,6.42,0,1,1-12.55,2.7,6.61,6.61,0,0,1-.15-1.33Z" transform="translate(-1.44 -1.6)" style="fill: #d42715"/>
|
||||
<path id="color_black" data-name="color black" d="M13.11,23.43a4.89,4.89,0,0,1,.34-1.81,7.4,7.4,0,1,1,10.4-1.2,7.32,7.32,0,0,1-1.18,1.18,5,5,0,1,1-9.56,1.83Z" transform="translate(-1.44 -1.6)"/>
|
||||
<g id="color_sensors" data-name="color sensors">
|
||||
<circle id="color_sensor_white_big" data-name="color sensor white big" cx="16.61" cy="14.43" r="3.35" style="fill: #f1f1f1"/>
|
||||
<circle id="color_sensor_white_small" data-name="color sensor white small" cx="16.61" cy="21.69" r="1.81" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
34
sim/visuals/assets/ColorSensorsvg.ts
Normal file
@ -0,0 +1,34 @@
|
||||
namespace pxsim {
|
||||
export const COLOR_SENSOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 33.22 34">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-448.15" y1="475.99" x2="-448.15" y2="475.83" gradientTransform="matrix(32.16, 0, 0, -33.37, 14429.08, 15914.64)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>Color Sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg41">
|
||||
<g id="color_box" data-name="color box">
|
||||
<g id="color_grey" data-name="color grey">
|
||||
<path id="color_sideboxes" data-name="color sideboxes" d="M2.14,9.19H34a.7.7,0,0,1,.7.7V28a.7.7,0,0,1-.7.7H2.14a.7.7,0,0,1-.7-.7V9.89A.7.7,0,0,1,2.14,9.19Z" transform="translate(-1.44 -1.6)" style="fill: #a8aaa8"/>
|
||||
<g id="color_bigbox-2" data-name="color bigbox-2">
|
||||
<image width="33" height="34" transform="translate(0.06)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAjCAYAAADxG9hnAAAACXBIWXMAAAsSAAALEgHS3X78AAAAzUlEQVRYR+3YMU4DMRBG4W8Q5eYMUEMuw/3ScQDugkTPcoSsa4ZibYjcUMVQ+Ekjj+Tif7YrT2Sm/8BtayIisOCurtemYEXJzIzMFBEL7vGIJ7vMtVnxgje8q09zxAmvOONzQJ1r3gnH9jQLHuw3cmMMB3tewXIZGrVG8p056vS/MkV6pkjPFOmZIj1TpGeK9EyRninSM0V6pkjPFOmZIj2XIn81n0h+RAo+sNWNUbXV3NI+4Sueaz9iJNFouWu0iVFEHIwb0jQK1szcvgDqy2NNnOFs5AAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path d="M5,3.33h26c1,0,1.78.57,1.78,1.27V32.77c0,.7-.8,1.27-1.78,1.27H5c-1,0-1.78-.57-1.78-1.27V4.6C3.25,3.9,4.05,3.33,5,3.33Z" transform="translate(-1.44 -1.6)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="color_side_black_4" data-name="color side black 4" x="31.83" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_3" data-name="color side black 3" x="0.84" y="10.38" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black_2" data-name="color side black 2" x="31.83" y="18.34" width="0.7" height="5.58"/>
|
||||
<rect id="color_side_black1" data-name="color side black1" x="0.84" y="18.34" width="0.7" height="5.58"/>
|
||||
</g>
|
||||
<path id="color_red" data-name="color red" d="M11.63,23.43a6.32,6.32,0,0,1,.15-1.37,8.79,8.79,0,1,1,12.54,0,6.42,6.42,0,1,1-12.55,2.7,6.61,6.61,0,0,1-.15-1.33Z" transform="translate(-1.44 -1.6)" style="fill: #d42715"/>
|
||||
<path id="color_black" data-name="color black" d="M13.11,23.43a4.89,4.89,0,0,1,.34-1.81,7.4,7.4,0,1,1,10.4-1.2,7.32,7.32,0,0,1-1.18,1.18,5,5,0,1,1-9.56,1.83Z" transform="translate(-1.44 -1.6)"/>
|
||||
<g id="color_sensors" data-name="color sensors">
|
||||
<circle id="color_sensor_white_big" data-name="color sensor white big" cx="16.61" cy="14.43" r="3.35" style="fill: #f1f1f1"/>
|
||||
<circle id="color_sensor_white_small" data-name="color sensor white small" cx="16.61" cy="21.69" r="1.81" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
103
sim/visuals/assets/EV3.svg
Normal file
@ -0,0 +1,103 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 110.73 170.04">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-374.89" y1="432.9" x2="-374.89" y2="432.82" gradientTransform="matrix(110.73, 0, 0, -106.94, 41567.45, 46425.3)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#f1f1f1"/>
|
||||
<stop offset="1" stop-color="#7a7a7a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-376" y1="450.74" x2="-376" y2="450.72" gradientTransform="matrix(100.11, 0, 0, -79.18, 37697.19, 35762.28)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-376.21" y1="614.94" x2="-376.21" y2="614.75" gradientTransform="matrix(98.29, 0, 0, -23.36, 37033.43, 14529.9)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-black" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-green" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#8CE300"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-red" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#D02E26"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-orange" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#F8D039"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-5" x1="-743.87" y1="1256.85" x2="-743.87" y2="1257.21" gradientTransform="matrix(3.03, 0, 0, -6.22, 2312.41, 7891.56)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#757575"/>
|
||||
<stop offset="1" stop-color="#393939"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip-path" transform="translate(0 0)">
|
||||
<rect x="86.48" y="149.58" width="12.38" height="12.38" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>EV3</title>
|
||||
<g id="EV3">
|
||||
<g id="brick">
|
||||
<path id="ev3_body_2" data-name="ev3 body 2" d="M2,31.7H108.76a2,2,0,0,1,2,2h0v103a2,2,0,0,1-2,2H2a2,2,0,0,1-2-2H0v-103a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient)"/>
|
||||
<path id="ev3_body_1" data-name="ev3 body 1" d="M8.19,127.57h94.35a2,2,0,0,1,2,2h0v38.53a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0V129.54a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_screen_grey" data-name="ev3 screen grey" d="M7.28,0h96.17a2,2,0,0,1,2,2h0V77.21a2,2,0,0,1-2,2H7.28a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path id="ev3_screenborder" data-name="ev3 screenborder" d="M18.2,10.47H92.68a3.79,3.79,0,0,1,3.79,3.79V56.12a3.8,3.8,0,0,1-3.79,3.8H18.2a3.8,3.8,0,0,1-3.79-3.8V14.26A3.79,3.79,0,0,1,18.2,10.47Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<path id="ev3_screen" data-name="ev3 screen" d="M24,12.44H87.22A2.73,2.73,0,0,1,90,15.17h0V55.52a2.73,2.73,0,0,1-2.73,2.73H24a2.73,2.73,0,0,1-2.73-2.73V15.17A2.73,2.73,0,0,1,24,12.44Z" transform="translate(0 0)" style="fill: #97b5a6"/>
|
||||
<path id="ev3_grey_buttom" data-name="ev3 grey buttom" d="M6.22,146.68h98.29v21.39a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0Z" transform="translate(0 0)" style="fill: url(#linear-gradient-3)"/>
|
||||
</g>
|
||||
<g id="buttons">
|
||||
<path id="btn_grey" data-name="btn grey" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: #6a6a6a"/>
|
||||
<path id="btn_color" data-name="btn color" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: url(#linear-gradient-black)"/>
|
||||
<path id="btn_left" data-name="btn left" d="M30.87,103.3H41.26v12.28H30.87a6.14,6.14,0,0,1-6.14-6.14h0a6.14,6.14,0,0,1,6.14-6.14Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_right" data-name="btn right" d="M80,115.58H69.62V103.3H80a6.14,6.14,0,0,1,6.15,6.14h0A6.14,6.14,0,0,1,80,115.58Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_enter" data-name="btn enter" d="M49.45,103.3h12a.46.46,0,0,1,.46.45v11.38a.46.46,0,0,1-.46.45h-12a.46.46,0,0,1-.46-.45V103.75a.46.46,0,0,1,.46-.45Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<path id="btn_up" data-name="btn up" d="M49.15,87.37l12.74-.15,9.55,9.86L67.5,101v7.13H63.86v-4.1a3,3,0,0,0-3-3c-3,0-11.08,0-11.08,0a2.47,2.47,0,0,0-2.58,2.35v4.77H43.53V101l-3.94-4Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_down" data-name="btn down" d="M61.83,131.54l-12.66.1-9.58-9.85,4-3.91v-7.17h3.6v4.11a3.06,3.06,0,0,0,3,3.06c3,.05,11,0,11,0a2.6,2.6,0,0,0,2.65-2.55v-4.62h3.67v7.17l3.91,3.91Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<rect id="btn_part_4" data-name="btn part 4" x="54" y="59.76" width="3.03" height="13.8" style="fill: #393939"/>
|
||||
<rect id="btn_part_3" data-name="btn part 3" x="54" y="72.96" width="3.03" height="6.07" style="fill: #9a9a9a"/>
|
||||
<rect id="btn_part_2" data-name="btn part 2" x="54" y="72.96" width="3.03" height="6.22" style="fill: url(#linear-gradient-5)"/>
|
||||
<rect id="btn_part_1" data-name="btn part 1" x="54" y="79.18" width="3.03" height="5.92" style="fill: gray"/>
|
||||
<path id="btn_back" data-name="btn back" d="M13.2,79.18H36.86v5.71c-2.62,2.64-6,6-6,6H15.17a2,2,0,0,1-2-2Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="LEGO_logo" data-name="LEGO logo">
|
||||
<rect id="logo_white_bg" data-name="logo white bg" x="86.56" y="149.66" width="12.21" height="12.21" style="fill: #fff"/>
|
||||
<g id="lego">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_5" data-name="logo part 5">
|
||||
<path id="Path_18" data-name="Path 18" d="M86.56,161.87H98.77V149.66H86.56ZM98,154.73a4.76,4.76,0,0,1-.24,1.18c-.43,1.27-.91,2.07-2.07,2.07a1.12,1.12,0,0,1-1.16-.7l0-.15-.09.11a1.86,1.86,0,0,1-1.46.72,1.29,1.29,0,0,1-1-.43l-.07-.09-.06.06a1.6,1.6,0,0,1-1.16.42,1.32,1.32,0,0,1-1-.37l-.09,0-.07.07a1.55,1.55,0,0,1-1.11.37.87.87,0,0,1-.95-.79.37.37,0,0,1,0-.11,8.15,8.15,0,0,1,1.09-3.1,1,1,0,0,1,.92-.52.78.78,0,0,1,.57.17c.11.11.11.2.13.42l0,.28.16-.24a1.6,1.6,0,0,1,1.52-.65,1,1,0,0,1,.9.37l0,.09.06-.07a1.8,1.8,0,0,1,1.2-.39,1.53,1.53,0,0,1,1.12.37.69.69,0,0,1,.13.2l.07.11.08-.11a1.59,1.59,0,0,1,1.31-.57,1.27,1.27,0,0,1,1,.35,1.37,1.37,0,0,1,.26,1" transform="translate(0 0)" style="fill: #ffed00"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_4" data-name="logo part 4">
|
||||
<path id="Path_19" data-name="Path 19" d="M86.56,161.87H98.77V149.66H86.56Zm11.75-6.66a6.73,6.73,0,0,1-.52,1.59,2.28,2.28,0,0,1-2.1,1.55,1.67,1.67,0,0,1-1.36-.54,2.18,2.18,0,0,1-1.48.54,1.73,1.73,0,0,1-1.09-.35,2.12,2.12,0,0,1-1.22.35,1.8,1.8,0,0,1-1-.3,2.19,2.19,0,0,1-1.18.3A1.28,1.28,0,0,1,87,157.14v0a8.26,8.26,0,0,1,1.18-3.34A1.37,1.37,0,0,1,89.4,153c.59,0,.79.17.9.37a2.24,2.24,0,0,1,1.46-.4,1.51,1.51,0,0,1,1,.33A2.4,2.4,0,0,1,94,153a1.74,1.74,0,0,1,1.36.45,2,2,0,0,1,1.33-.43,1.53,1.53,0,0,1,1.37.61,1.79,1.79,0,0,1,.29,1.55" transform="translate(0 0)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_3" data-name="logo part 3">
|
||||
<path id="Path_20" data-name="Path 20" d="M86.48,162H98.86V149.58H86.48Zm12.2-.18h-12v-12h12Z" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_2" data-name="logo part 2">
|
||||
<path id="Path_21" data-name="Path 21" d="M98.25,153.29v-.09h.06s.07,0,.07.05,0,0-.07,0Zm.2.17,0-.06c0-.05,0-.07-.06-.07h0a.09.09,0,0,0,.08-.09.07.07,0,0,0-.07-.08h-.17v.3h.07v-.13h0s0,0,0,0,0,.05,0,.07l0,0Zm-.16-.39a.24.24,0,0,1,0,.48.24.24,0,0,1-.24-.24.26.26,0,0,1,.24-.24m0-.07a.31.31,0,0,0,0,.62.31.31,0,0,0,.31-.31h0a.32.32,0,0,0-.31-.31" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_1" data-name="logo part 1">
|
||||
<path id="Path_22" data-name="Path 22" d="M96.7,153.33a1.73,1.73,0,0,0-1.38.61.66.66,0,0,0-.15-.22,1.47,1.47,0,0,0-1.16-.41,1.87,1.87,0,0,0-1.25.41,1.1,1.1,0,0,0-1-.41,1.7,1.7,0,0,0-1.6.7.52.52,0,0,0-.15-.46.87.87,0,0,0-.63-.2,1.1,1.1,0,0,0-1,.57,8.73,8.73,0,0,0-1.13,3.17,1,1,0,0,0,1,1h.08a1.53,1.53,0,0,0,1.18-.39,1.35,1.35,0,0,0,1,.39,1.61,1.61,0,0,0,1.23-.46,1.36,1.36,0,0,0,1.09.46,1.92,1.92,0,0,0,1.53-.77,1.2,1.2,0,0,0,1.24.75c1.2,0,1.73-.83,2.16-2.12a4.54,4.54,0,0,0,.27-1.2,1.21,1.21,0,0,0-1-1.37,1.29,1.29,0,0,0-.34,0m-8,3.28c.62-.11.79.11.77.33-.07.61-.63.76-1.12.74a.62.62,0,0,1-.69-.55v0a8.47,8.47,0,0,1,1.07-3,.72.72,0,0,1,.68-.39c.31,0,.37.15.37.33a14.2,14.2,0,0,1-1.07,2.55m2-.57c0,.11-.11.35-.17.59a3.1,3.1,0,0,1,.61-.09c.31,0,.48.14.48.38,0,.59-.66.76-1.11.76a.85.85,0,0,1-.94-.75v-.08a6,6,0,0,1,.67-2.27,1.36,1.36,0,0,1,1.53-.9c.31,0,.68.13.68.44s-.35.56-.68.59h-.5a3.58,3.58,0,0,0-.24.48c.64-.09.9,0,.79.41s-.59.52-1.12.44m3.13-1.55a.46.46,0,0,0-.37.21,6.33,6.33,0,0,0-.64,1.73c0,.28.09.35.22.35s.46-.24.55-.61c0,0-.42,0-.31-.37s.33-.44.68-.46c.7,0,.63.48.57.76a1.81,1.81,0,0,1-1.7,1.6.9.9,0,0,1-1-.79v-.18a5,5,0,0,1,.4-1.55c.37-.87.76-1.48,1.77-1.48.59,0,1.07.22,1,.76a.67.67,0,0,1-.64.68c-.11,0-.52,0-.39-.42,0-.13,0-.24-.15-.24m3.75.75a7.06,7.06,0,0,1-.59,1.61,1.41,1.41,0,0,1-1.37.86.82.82,0,0,1-.94-.86,5.11,5.11,0,0,1,.39-1.63c.31-.83.63-1.51,1.66-1.49s.94,1.05.85,1.51m-.85-.52a9.84,9.84,0,0,1-.63,1.85.33.33,0,0,1-.31.22c-.13,0-.17-.09-.2-.2a7.75,7.75,0,0,1,.7-1.94c.09-.13.18-.16.26-.13s.18.11.18.2" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="EV3_logo" data-name="EV3 logo">
|
||||
<path id="ev3_3" data-name="ev3 3" d="M36,155a.18.18,0,0,1,.2.16h0V156a.16.16,0,0,1-.17.14H34a.36.36,0,0,0-.38.33v1.14a.34.34,0,0,0,.38.3h2c.19,0,.17.14.17.14v.82c0,.08-.06.14-.17.14H32.57a.2.2,0,0,1-.2-.19h0v-.05a.38.38,0,0,0-.38-.38H30.87a.38.38,0,0,0-.38.38v1.64a.37.37,0,0,0,.38.33h6.75a.36.36,0,0,0,.39-.3v-6.89a.36.36,0,0,0-.39-.3H30.9a.34.34,0,0,0-.38.3v1.67a.38.38,0,0,0,.35.38H32a.36.36,0,0,0,.35-.36v-.05a.17.17,0,0,1,.16-.19H36Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_v" data-name="ev3 v" d="M29.29,153.2H27.7c-.24,0-.33.17-.44.38L25.32,158a.27.27,0,0,1-.19.11.23.23,0,0,1-.19-.14L23,153.58c-.11-.21-.22-.38-.46-.38H20.92c-.35,0-.41.19-.3.41l3.2,6.73c.17.32.28.38.58.38h1.42a.55.55,0,0,0,.57-.38l3.22-6.73c.11-.22,0-.41-.32-.41" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_e" data-name="ev3 e" d="M19.39,156.1a.34.34,0,0,1,.38.3v1.17a.33.33,0,0,1-.38.3H14.34c-.11,0-.2.06-.2.14h0v.82h0c0,.08.09.14.2.14h5.05a.33.33,0,0,1,.38.3v1.15a.33.33,0,0,1-.35.3H12.67a.35.35,0,0,1-.38-.3v-6.89a.34.34,0,0,1,.38-.3h6.75a.31.31,0,0,1,.35.28v1.17a.31.31,0,0,1-.33.3H14.36c-.11,0-.22,0-.22.13V156c0,.08.09.14.19.14Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 12 KiB |
108
sim/visuals/assets/EV3svg.ts
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const EV3_SVG = `<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 110.73 170.04">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-374.89" y1="432.9" x2="-374.89" y2="432.82" gradientTransform="matrix(110.73, 0, 0, -106.94, 41567.45, 46425.3)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#f1f1f1"/>
|
||||
<stop offset="1" stop-color="#7a7a7a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-376" y1="450.74" x2="-376" y2="450.72" gradientTransform="matrix(100.11, 0, 0, -79.18, 37697.19, 35762.28)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-376.21" y1="614.94" x2="-376.21" y2="614.75" gradientTransform="matrix(98.29, 0, 0, -23.36, 37033.43, 14529.9)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-black" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-green" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#8CE300"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-red" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#D02E26"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-orange" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#F8D039"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-5" x1="-743.87" y1="1256.85" x2="-743.87" y2="1257.21" gradientTransform="matrix(3.03, 0, 0, -6.22, 2312.41, 7891.56)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#757575"/>
|
||||
<stop offset="1" stop-color="#393939"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip-path" transform="translate(0 0)">
|
||||
<rect x="86.48" y="149.58" width="12.38" height="12.38" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>EV3</title>
|
||||
<g id="EV3">
|
||||
<g id="brick">
|
||||
<path id="ev3_body_2" data-name="ev3 body 2" d="M2,31.7H108.76a2,2,0,0,1,2,2h0v103a2,2,0,0,1-2,2H2a2,2,0,0,1-2-2H0v-103a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient)"/>
|
||||
<path id="ev3_body_1" data-name="ev3 body 1" d="M8.19,127.57h94.35a2,2,0,0,1,2,2h0v38.53a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0V129.54a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_screen_grey" data-name="ev3 screen grey" d="M7.28,0h96.17a2,2,0,0,1,2,2h0V77.21a2,2,0,0,1-2,2H7.28a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(0 0)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path id="ev3_screenborder" data-name="ev3 screenborder" d="M18.2,10.47H92.68a3.79,3.79,0,0,1,3.79,3.79V56.12a3.8,3.8,0,0,1-3.79,3.8H18.2a3.8,3.8,0,0,1-3.79-3.8V14.26A3.79,3.79,0,0,1,18.2,10.47Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<g id="ev3_screen">
|
||||
<path id="ev3_screen_path" data-name="ev3 screen" d="M24,12.44H87.22A2.73,2.73,0,0,1,90,15.17h0V55.52a2.73,2.73,0,0,1-2.73,2.73H24a2.73,2.73,0,0,1-2.73-2.73V15.17A2.73,2.73,0,0,1,24,12.44Z" transform="translate(0 0)" style="fill: #97b5a6"/>
|
||||
</g>
|
||||
<path id="ev3_grey_buttom" data-name="ev3 grey buttom" d="M6.22,146.68h98.29v21.39a2,2,0,0,1-2,2H8.19a2,2,0,0,1-2-2h0Z" transform="translate(0 0)" style="fill: url(#linear-gradient-3)"/>
|
||||
</g>
|
||||
<g id="buttons">
|
||||
<path id="btn_grey" data-name="btn grey" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: #6a6a6a"/>
|
||||
<path id="btn_color" data-name="btn color" d="M48.69,133.94c-5.58-5.39-14.26-14.26-14.26-14.26v-1.82H31a8.27,8.27,0,1,1,0-16.53h3.41V99.5L48.54,85.09H62.65C69,91.61,76.75,99.2,76.75,99.2v2.13H80a8.27,8.27,0,1,1,0,16.53H76.75v1.82c-7.51,7.73-14,14.26-14,14.26Z" transform="translate(0 0)" style="fill: url(#linear-gradient-black)"/>
|
||||
<path id="btn_left" data-name="btn left" d="M30.87,103.3H41.26v12.28H30.87a6.14,6.14,0,0,1-6.14-6.14h0a6.14,6.14,0,0,1,6.14-6.14Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_right" data-name="btn right" d="M80,115.58H69.62V103.3H80a6.14,6.14,0,0,1,6.15,6.14h0A6.14,6.14,0,0,1,80,115.58Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_enter" data-name="btn enter" d="M49.45,103.3h12a.46.46,0,0,1,.46.45v11.38a.46.46,0,0,1-.46.45h-12a.46.46,0,0,1-.46-.45V103.75a.46.46,0,0,1,.46-.45Z" transform="translate(0 0)" style="fill: #393939"/>
|
||||
<path id="btn_up" data-name="btn up" d="M49.15,87.37l12.74-.15,9.55,9.86L67.5,101v7.13H63.86v-4.1a3,3,0,0,0-3-3c-3,0-11.08,0-11.08,0a2.47,2.47,0,0,0-2.58,2.35v4.77H43.53V101l-3.94-4Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<path id="btn_down" data-name="btn down" d="M61.83,131.54l-12.66.1-9.58-9.85,4-3.91v-7.17h3.6v4.11a3.06,3.06,0,0,0,3,3.06c3,.05,11,0,11,0a2.6,2.6,0,0,0,2.65-2.55v-4.62h3.67v7.17l3.91,3.91Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
<rect id="btn_part_4" data-name="btn part 4" x="54" y="59.76" width="3.03" height="13.8" style="fill: #393939"/>
|
||||
<rect id="btn_part_3" data-name="btn part 3" x="54" y="72.96" width="3.03" height="6.07" style="fill: #9a9a9a"/>
|
||||
<rect id="btn_part_2" data-name="btn part 2" x="54" y="72.96" width="3.03" height="6.22" style="fill: url(#linear-gradient-5)"/>
|
||||
<rect id="btn_part_1" data-name="btn part 1" x="54" y="79.18" width="3.03" height="5.92" style="fill: gray"/>
|
||||
<path id="btn_back" data-name="btn back" d="M13.2,79.18H36.86v5.71c-2.62,2.64-6,6-6,6H15.17a2,2,0,0,1-2-2Z" transform="translate(0 0)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="LEGO_logo" data-name="LEGO logo">
|
||||
<rect id="logo_white_bg" data-name="logo white bg" x="86.56" y="149.66" width="12.21" height="12.21" style="fill: #fff"/>
|
||||
<g id="lego">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_5" data-name="logo part 5">
|
||||
<path id="Path_18" data-name="Path 18" d="M86.56,161.87H98.77V149.66H86.56ZM98,154.73a4.76,4.76,0,0,1-.24,1.18c-.43,1.27-.91,2.07-2.07,2.07a1.12,1.12,0,0,1-1.16-.7l0-.15-.09.11a1.86,1.86,0,0,1-1.46.72,1.29,1.29,0,0,1-1-.43l-.07-.09-.06.06a1.6,1.6,0,0,1-1.16.42,1.32,1.32,0,0,1-1-.37l-.09,0-.07.07a1.55,1.55,0,0,1-1.11.37.87.87,0,0,1-.95-.79.37.37,0,0,1,0-.11,8.15,8.15,0,0,1,1.09-3.1,1,1,0,0,1,.92-.52.78.78,0,0,1,.57.17c.11.11.11.2.13.42l0,.28.16-.24a1.6,1.6,0,0,1,1.52-.65,1,1,0,0,1,.9.37l0,.09.06-.07a1.8,1.8,0,0,1,1.2-.39,1.53,1.53,0,0,1,1.12.37.69.69,0,0,1,.13.2l.07.11.08-.11a1.59,1.59,0,0,1,1.31-.57,1.27,1.27,0,0,1,1,.35,1.37,1.37,0,0,1,.26,1" transform="translate(0 0)" style="fill: #ffed00"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_4" data-name="logo part 4">
|
||||
<path id="Path_19" data-name="Path 19" d="M86.56,161.87H98.77V149.66H86.56Zm11.75-6.66a6.73,6.73,0,0,1-.52,1.59,2.28,2.28,0,0,1-2.1,1.55,1.67,1.67,0,0,1-1.36-.54,2.18,2.18,0,0,1-1.48.54,1.73,1.73,0,0,1-1.09-.35,2.12,2.12,0,0,1-1.22.35,1.8,1.8,0,0,1-1-.3,2.19,2.19,0,0,1-1.18.3A1.28,1.28,0,0,1,87,157.14v0a8.26,8.26,0,0,1,1.18-3.34A1.37,1.37,0,0,1,89.4,153c.59,0,.79.17.9.37a2.24,2.24,0,0,1,1.46-.4,1.51,1.51,0,0,1,1,.33A2.4,2.4,0,0,1,94,153a1.74,1.74,0,0,1,1.36.45,2,2,0,0,1,1.33-.43,1.53,1.53,0,0,1,1.37.61,1.79,1.79,0,0,1,.29,1.55" transform="translate(0 0)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_3" data-name="logo part 3">
|
||||
<path id="Path_20" data-name="Path 20" d="M86.48,162H98.86V149.58H86.48Zm12.2-.18h-12v-12h12Z" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_2" data-name="logo part 2">
|
||||
<path id="Path_21" data-name="Path 21" d="M98.25,153.29v-.09h.06s.07,0,.07.05,0,0-.07,0Zm.2.17,0-.06c0-.05,0-.07-.06-.07h0a.09.09,0,0,0,.08-.09.07.07,0,0,0-.07-.08h-.17v.3h.07v-.13h0s0,0,0,0,0,.05,0,.07l0,0Zm-.16-.39a.24.24,0,0,1,0,.48.24.24,0,0,1-.24-.24.26.26,0,0,1,.24-.24m0-.07a.31.31,0,0,0,0,.62.31.31,0,0,0,.31-.31h0a.32.32,0,0,0-.31-.31" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="logo_part_1" data-name="logo part 1">
|
||||
<path id="Path_22" data-name="Path 22" d="M96.7,153.33a1.73,1.73,0,0,0-1.38.61.66.66,0,0,0-.15-.22,1.47,1.47,0,0,0-1.16-.41,1.87,1.87,0,0,0-1.25.41,1.1,1.1,0,0,0-1-.41,1.7,1.7,0,0,0-1.6.7.52.52,0,0,0-.15-.46.87.87,0,0,0-.63-.2,1.1,1.1,0,0,0-1,.57,8.73,8.73,0,0,0-1.13,3.17,1,1,0,0,0,1,1h.08a1.53,1.53,0,0,0,1.18-.39,1.35,1.35,0,0,0,1,.39,1.61,1.61,0,0,0,1.23-.46,1.36,1.36,0,0,0,1.09.46,1.92,1.92,0,0,0,1.53-.77,1.2,1.2,0,0,0,1.24.75c1.2,0,1.73-.83,2.16-2.12a4.54,4.54,0,0,0,.27-1.2,1.21,1.21,0,0,0-1-1.37,1.29,1.29,0,0,0-.34,0m-8,3.28c.62-.11.79.11.77.33-.07.61-.63.76-1.12.74a.62.62,0,0,1-.69-.55v0a8.47,8.47,0,0,1,1.07-3,.72.72,0,0,1,.68-.39c.31,0,.37.15.37.33a14.2,14.2,0,0,1-1.07,2.55m2-.57c0,.11-.11.35-.17.59a3.1,3.1,0,0,1,.61-.09c.31,0,.48.14.48.38,0,.59-.66.76-1.11.76a.85.85,0,0,1-.94-.75v-.08a6,6,0,0,1,.67-2.27,1.36,1.36,0,0,1,1.53-.9c.31,0,.68.13.68.44s-.35.56-.68.59h-.5a3.58,3.58,0,0,0-.24.48c.64-.09.9,0,.79.41s-.59.52-1.12.44m3.13-1.55a.46.46,0,0,0-.37.21,6.33,6.33,0,0,0-.64,1.73c0,.28.09.35.22.35s.46-.24.55-.61c0,0-.42,0-.31-.37s.33-.44.68-.46c.7,0,.63.48.57.76a1.81,1.81,0,0,1-1.7,1.6.9.9,0,0,1-1-.79v-.18a5,5,0,0,1,.4-1.55c.37-.87.76-1.48,1.77-1.48.59,0,1.07.22,1,.76a.67.67,0,0,1-.64.68c-.11,0-.52,0-.39-.42,0-.13,0-.24-.15-.24m3.75.75a7.06,7.06,0,0,1-.59,1.61,1.41,1.41,0,0,1-1.37.86.82.82,0,0,1-.94-.86,5.11,5.11,0,0,1,.39-1.63c.31-.83.63-1.51,1.66-1.49s.94,1.05.85,1.51m-.85-.52a9.84,9.84,0,0,1-.63,1.85.33.33,0,0,1-.31.22c-.13,0-.17-.09-.2-.2a7.75,7.75,0,0,1,.7-1.94c.09-.13.18-.16.26-.13s.18.11.18.2" transform="translate(0 0)" style="fill: #171714"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="EV3_logo" data-name="EV3 logo">
|
||||
<path id="ev3_3" data-name="ev3 3" d="M36,155a.18.18,0,0,1,.2.16h0V156a.16.16,0,0,1-.17.14H34a.36.36,0,0,0-.38.33v1.14a.34.34,0,0,0,.38.3h2c.19,0,.17.14.17.14v.82c0,.08-.06.14-.17.14H32.57a.2.2,0,0,1-.2-.19h0v-.05a.38.38,0,0,0-.38-.38H30.87a.38.38,0,0,0-.38.38v1.64a.37.37,0,0,0,.38.33h6.75a.36.36,0,0,0,.39-.3v-6.89a.36.36,0,0,0-.39-.3H30.9a.34.34,0,0,0-.38.3v1.67a.38.38,0,0,0,.35.38H32a.36.36,0,0,0,.35-.36v-.05a.17.17,0,0,1,.16-.19H36Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_v" data-name="ev3 v" d="M29.29,153.2H27.7c-.24,0-.33.17-.44.38L25.32,158a.27.27,0,0,1-.19.11.23.23,0,0,1-.19-.14L23,153.58c-.11-.21-.22-.38-.46-.38H20.92c-.35,0-.41.19-.3.41l3.2,6.73c.17.32.28.38.58.38h1.42a.55.55,0,0,0,.57-.38l3.22-6.73c.11-.22,0-.41-.32-.41" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
<path id="ev3_e" data-name="ev3 e" d="M19.39,156.1a.34.34,0,0,1,.38.3v1.17a.33.33,0,0,1-.38.3H14.34c-.11,0-.2.06-.2.14h0v.82h0c0,.08.09.14.2.14h5.05a.33.33,0,0,1,.38.3v1.15a.33.33,0,0,1-.35.3H12.67a.35.35,0,0,1-.38-.3v-6.89a.34.34,0,0,1,.38-.3h6.75a.31.31,0,0,1,.35.28v1.17a.31.31,0,0,1-.33.3H14.36c-.11,0-.22,0-.22.13V156c0,.08.09.14.19.14Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
74
sim/visuals/assets/Large Motor.svg
Normal file
@ -0,0 +1,74 @@
|
||||
<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61">
|
||||
<defs>
|
||||
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872">
|
||||
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e">
|
||||
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927">
|
||||
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>Large Motor</title>
|
||||
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)">
|
||||
<g>
|
||||
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/>
|
||||
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/>
|
||||
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
|
||||
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
|
||||
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
|
||||
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
|
||||
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
|
||||
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
|
||||
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
|
||||
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
|
||||
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
|
||||
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
|
||||
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
|
||||
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
|
||||
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
|
||||
</g>
|
||||
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/>
|
||||
<g>
|
||||
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03">
|
||||
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)">
|
||||
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153">
|
||||
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
|
||||
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
|
||||
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
|
||||
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
|
||||
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
|
||||
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
|
||||
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
|
||||
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
|
||||
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
|
||||
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
|
||||
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
|
||||
</g>
|
||||
<g>
|
||||
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/>
|
||||
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/>
|
||||
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/>
|
||||
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/>
|
||||
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/>
|
||||
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
76
sim/visuals/assets/LargeMotorsvg.ts
Normal file
@ -0,0 +1,76 @@
|
||||
namespace pxsim {
|
||||
export const LARGE_MOTOR_SVG = `<svg id="e13b39e7-895d-4931-9be9-7aecaf709784" data-name="46d2506d-be16-4175-90b0-aabf357ea333" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 79.56 153.61">
|
||||
<defs>
|
||||
<clipPath id="7dd75c25-af24-4f64-9ea1-f270fbd17872">
|
||||
<path d="M12.82.54a17.07,17.07,0,0,1,20.77,12.3,1.53,1.53,0,0,1,1.6-.24l.21.19,10.41,10.1c.31.3.47.3.47,1.14V35.81h6.79a4,4,0,0,1,4,4V65.63a4,4,0,0,1-4,4H46.15v11.8l13.68-.1h.61s7.76,9.81,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78H69.17v7.57A4,4,0,0,1,67,151.75V153h0a.63.63,0,0,1-.61.61H40.08a.6.6,0,0,1-.64-.56V152a4,4,0,0,1-2.89-3.85v-7.57H30.07a5.78,5.78,0,0,1-5.78-5.78v-8.18h-6.8a4,4,0,0,1-4-4V96.84a4,4,0,0,1,4-4h6.8V92l.75-.78v-10L14.13,70.71c-.25-.27-.39-.25-.39-.67V34.27l.37-.39A17.06,17.06,0,0,1,12.82.54Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="9d9a0722-eca6-4c98-bf03-49097e654f0e">
|
||||
<path d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78V92l9.26-9.58a2.29,2.29,0,0,1,2.38-1c4.4,0,23.86-.15,23.86-.15h.65s7.76,9.8,18.12,23.87v29.64h0a5.78,5.78,0,0,1-5.78,5.78Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="0f29df77-bfe3-4749-8432-7a5b3681f927">
|
||||
<path d="M35.85,135.26a5.78,5.78,0,0,1-5.78-5.78h0V92.6h0a5.78,5.78,0,0,1,5.77-5.79H57.17S64.08,96,72.73,107.22v22.25h0A5.78,5.78,0,0,1,67,135.26H35.85Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>Large Motor</title>
|
||||
<g style="clip-path: url(#7dd75c25-af24-4f64-9ea1-f270fbd17872)">
|
||||
<g>
|
||||
<path id="1614620b-40ec-4523-b90a-428aad6bd045" data-name="eadcf40d-5b1f-4f82-8d01-d628e9e4bcbb" d="M40.49,64.16V41.26A5.48,5.48,0,0,1,46,35.8h5.62A5.48,5.48,0,0,1,57,41.26v22.9h0a5.45,5.45,0,0,1-5.46,5.46H46A5.45,5.45,0,0,1,40.49,64.16Z" style="fill: #a8a9a8"/>
|
||||
<circle id="1a43435f-56ec-4b4e-a3ae-b40d13b2f218" data-name="93612c19-30fe-4c1d-bb05-67002522431d" cx="51.72" cy="64.32" r="3.79" style="fill: #fff"/>
|
||||
<circle id="43fd443a-13b5-48ef-af02-32d5de3e95b1" data-name="aee14a95-6af8-4dce-8543-2eda3545de29" cx="51.72" cy="41.11" r="3.79" style="fill: #fff"/>
|
||||
<path id="7bfb4e09-fb97-433a-8104-a0426c319fe6" data-name="1d2e9494-7cc7-48f0-9562-12d1d83b7bb0" d="M39.44,153v-5.29a.61.61,0,0,1,.61-.61H66.34a.61.61,0,0,1,.61.61h0V153h0a.63.63,0,0,1-.61.61H40.08a.61.61,0,0,1-.64-.58Z" style="fill: #a8a9a8"/>
|
||||
<path id="ded8d34f-3eb8-4d18-bbd7-80e03d734fef" data-name="ccd9d8b0-00ff-4f0b-bfdc-94153d199419" d="M36.58,151.58V136.89a.61.61,0,0,1,.61-.61H68.51a.61.61,0,0,1,.61.61h0v14.69a.61.61,0,0,1-.61.61H37.19a.61.61,0,0,1-.61-.61Z" style="fill: #a8a9a8"/>
|
||||
<path id="a30c6f9d-adb5-4251-ad04-1bd8bfaab7af" data-name="e8b462c5-81f0-4111-9486-bb5fc1221c77" d="M55.44,59.6V57.8c0-.87-.81-.46-.81-.46l-1.19.59c-.38.18-.33-.34-.33-.34V55c0-.72.82-.77.82-.77h1.25s.26-.2.26-1.38-.29-1.32-.29-1.32H53.9a.68.68,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1-.05-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H48.56s-.3.18-.3,1.32.3,1.38.3,1.38h1.38a.73.73,0,0,1,.73.77v2.62c0,.52-.36.34-.36.34l-1-.59c-.68-.38-1.23,0-1.23.46v1.8s0,1,1.23.1a5.08,5.08,0,0,1,3-.7,4.18,4.18,0,0,1,2.35.7C55.37,60.14,55.44,59.6,55.44,59.6Z" style="fill: #fff"/>
|
||||
<path id="c7805530-90df-4e25-868f-c9475cacc294" data-name="51a46c0a-a8a3-4420-b297-1d82512a0b32" d="M47.79,46.14c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.84,5.72,5.72,0,0,0,2.76-.84.85.85,0,0,1,.31-.09.71.71,0,0,1,.76.65V47.9s-.24,1-1.07.6a5,5,0,0,0-2.76-.77A6.46,6.46,0,0,0,49,48.5a.68.68,0,0,1-.24.08.83.83,0,0,1-1-.61s0,0,0-.07S47.76,46.94,47.79,46.14Z" style="fill: #fff"/>
|
||||
<path id="f8fcbff1-7e8c-4c85-8f0e-222f81e36654" data-name="be4fbc2c-74e0-495a-bfad-cf557a83a287" d="M13.75,70V34.27L33.21,13.56c0-.84,1.4-1.36,2-1l.21.19,10.42,10.1c.31.3.46.3.46,1.14l-.19,59-18.57.67-13.4-13C13.89,70.44,13.75,70.46,13.75,70Z" style="fill: #a8a9a8"/>
|
||||
<path id="1dc809f3-4ab0-4e83-b8a0-ab178c9c843d" data-name="4d02192d-b81d-48fe-8732-1ddf5bded46b" d="M35.44,82.8l10.67-.57v-8l-4.43-4.7H30.05a1.6,1.6,0,0,0-1.16.4L25.34,73.6c-.28.27-.3,1.12-.3,1.12V92Z" style="fill: #a8a9a8"/>
|
||||
<g id="e0794b99-de5a-4337-b43b-7cdb158e4272" data-name="233cb9b7-9706-41a9-a0a4-7b51b61b2ff5">
|
||||
<path id="c86708aa-fcc1-4e15-8d85-6e5415398b0c" data-name="6ed465b7-465a-4389-8ebc-d8f92a4226dd" d="M13.49,121.2V98.29A5.46,5.46,0,0,1,19,92.84h5.62A5.45,5.45,0,0,1,30,98.3v22.9h0a5.48,5.48,0,0,1-5.46,5.46H19A5.48,5.48,0,0,1,13.49,121.2Z" style="fill: #a8a9a8"/>
|
||||
<circle id="0355a228-ed20-4633-ba10-c36cf551e228" data-name="955ad5d6-af09-42ad-8d56-9ff62c40912d" cx="18.35" cy="121.35" r="3.79" style="fill: #fff"/>
|
||||
<circle id="73922eab-afce-48dd-9bae-80da92a8b392" data-name="75a0ff09-d40c-46e3-aaf0-c5878f2efdac" cx="18.35" cy="98.14" r="3.79" style="fill: #fff"/>
|
||||
<path id="e9f7b6a6-dcdd-4d55-a7bb-ad3951bb1e39" data-name="eeb5a6b6-ef4a-4f05-95cd-8b1c3eb419c4" d="M22.07,116.64v-1.8c0-.86-.81-.46-.81-.46L20,115c-.38.18-.33-.34-.33-.34V112c0-.72.82-.76.82-.76h1.25s.32-.26.29-1.39-.29-1.32-.29-1.32H20.53a.67.67,0,0,1-.66-.65v-1.3a3.57,3.57,0,0,0-1.4-.31c-1,0-1.17.31-1.17.31v1.3c0,.67-.73.65-.73.65H15.19s-.3.18-.3,1.32.3,1.39.3,1.39h1.38a.71.71,0,0,1,.73.69v2.69c0,.52-.36.34-.36.34l-1-.58c-.68-.39-1.23,0-1.23.46v1.8s0,1,1.23.1a5.09,5.09,0,0,1,3-.71,4.16,4.16,0,0,1,2.35.71C22,117.17,22.07,116.64,22.07,116.64Z" style="fill: #fff"/>
|
||||
<path id="82138da6-9b2a-4b9a-952e-568841e5ed52" data-name="80481c02-bb01-43aa-bd64-15ab30fbbb5e" d="M14.44,103.18c0-.8,1.2-.56,1.2-.56a7,7,0,0,0,2.85.83,5.78,5.78,0,0,0,2.77-.83.7.7,0,0,1,1,.25.67.67,0,0,1,.1.31v1.76s-.24,1-1.07.59a5,5,0,0,0-2.77-.77,6.59,6.59,0,0,0-2.85.77.68.68,0,0,1-.24.08.83.83,0,0,1-1-.63v0S14.44,104,14.44,103.18Z" style="fill: #fff"/>
|
||||
</g>
|
||||
<path id="aa62b88a-4cd5-4c76-acaf-e85a7fd45341" data-name="6b63d025-68d6-47eb-ba62-60017f4a1dd4" d="M30.07,140.62a5.78,5.78,0,0,1-5.78-5.78h0V92l9.26-9.57a2.29,2.29,0,0,1,2.38-1c4.4,0,23.87-.14,23.87-.14h.64s7.76,9.8,18.13,23.86v29.64h0a5.79,5.79,0,0,1-5.79,5.79Z" style="fill: #a8a9a8"/>
|
||||
<g>
|
||||
<g id="1172473e-5b0c-4dd6-85c5-28f5593b9312" data-name="a0498222-7e69-48db-90b7-05f2ce124a03">
|
||||
<g style="clip-path: url(#9d9a0722-eca6-4c98-bf03-49097e654f0e)">
|
||||
<g id="da9d77a3-c9b0-4118-a8e3-c65ec5cbe7d4" data-name="8270fb93-0862-4480-a5b8-675cc77ac153">
|
||||
<path id="77253f44-139e-4b90-82df-465a787cab9c" data-name="bb0a4ec3-45a5-4c91-b064-db5494e447e6" d="M78.56,142.76l1-7.69V103.85L66.49,87.72v14.86L42.7,133.66,35.55,141Z" style="fill: #f2f2f2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path id="9d05c10c-72eb-4f9f-8517-e403ec636357" data-name="74e07bdd-431b-40c1-b0f3-71128f2a0c08" d="M35.85,135.56a5.78,5.78,0,0,1-5.78-5.78h0V92.9h0a5.78,5.78,0,0,1,5.77-5.79H57.17s6.91,9.15,15.56,20.41v22.25h0A5.78,5.78,0,0,1,67,135.56H35.85Z" style="fill: #a8a9a8"/>
|
||||
<g id="6df8eb1f-3187-427f-8d99-bc7a37e6cc25" data-name="9bbfb3ec-86c2-4d27-8275-76f2f9737a7f">
|
||||
<g id="e4d7143c-1fb6-45a4-a205-1c920b8a823c" data-name="7e017c33-f09b-4d39-803f-1bedf1ebf566">
|
||||
<g id="3a4e493d-cd17-48c4-97b6-da7ee3c4898e" data-name="69e3df75-72a6-4499-baab-f65ec194e193">
|
||||
<g style="clip-path: url(#0f29df77-bfe3-4749-8432-7a5b3681f927)">
|
||||
<g id="7cada08f-1e90-4ef2-8ae4-3f2adfd3e953" data-name="b7007e32-15c9-40b3-a885-a7231fd104d1">
|
||||
<path id="02e64b51-bd56-4079-9736-8a269cb37029" data-name="c599a4f4-ae5d-411c-902d-dbcde04a2d6e" d="M60.44,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112Zm-3.61,0a1.09,1.09,0,1,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6a1.08,1.08,0,0,1-1.11,1.05h0a1.07,1.07,0,0,1-1-1.11V112Zm-3.62,0a1.1,1.1,0,0,1,1.12-1.06,1.08,1.08,0,0,1,1,1.12V139.6a1.09,1.09,0,0,1-2.17-.06V112ZM46,112a1.09,1.09,0,0,1,2.18-.14,1.34,1.34,0,0,1,0,.2V139.6A1.08,1.08,0,0,1,47,140.65h0a1.07,1.07,0,0,1-1-1.11V112Z" style="fill: #6a6a6a"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<circle id="a5a29926-0401-43af-b098-0c7439485e7c" data-name="bcdc8e69-90f7-4365-8f7a-7c1567704161" cx="29.69" cy="135.22" r="2.24" style="fill: #9a9a9a"/>
|
||||
<circle id="313e9fdc-7bbb-4d49-9d19-2415450fb691" data-name="b7785d8e-a2e4-41a7-9c34-4d9f6aebd906" cx="58.36" cy="84.71" r="2.24" style="fill: #9a9a9a"/>
|
||||
<g id="1eb2ae58-2419-47d4-86bf-4f26a7f0cf61" data-name="KNOB">
|
||||
<g id="26377a78-5df7-4bea-8daa-669ea612118c" data-name="5301e639-3e28-489d-96ec-91bda6d459b7">
|
||||
<circle id="13e05316-9dcc-4be0-9e0e-4b1df48fad92" data-name="f1bc8b30-bdb2-4084-8c02-e322d1c0b9bf" cx="17.06" cy="17.06" r="17.06" style="fill: #b72b1c"/>
|
||||
</g>
|
||||
<g>
|
||||
<circle id="58277aee-b73f-4f42-94ef-3b959dc26807" data-name="ce4b2c57-9b3b-4aed-902e-31d9f366dc61" cx="20.12" cy="28.12" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="980a54d2-804e-408d-8655-debf2e5856d0" data-name="6a44a65a-f04b-4564-81a2-4eefa438c5f1" cx="28.27" cy="14" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="9b2e3cd0-e4bd-42ce-b558-4f4bc46eaf23" data-name="d5fea8d1-47c1-448e-adb6-8519e2516216" cx="14.15" cy="5.85" r="3.79" style="fill: #3c3c3c"/>
|
||||
<circle id="06781f30-70ec-4914-81c3-4083325e7c18" data-name="1faf9727-3903-4be3-a3d3-4ab2d5d92b1f" cx="6" cy="19.97" r="3.79" style="fill: #3c3c3c"/>
|
||||
<path id="f1de636f-1fd2-4419-ae5c-d6a853c5834d" data-name="9e52c672-4ec8-4d92-9380-e44b4f69f848" d="M13.56,16.89a2.91,2.91,0,0,0,.7,2.26,12,12,0,0,1,1.2-.39c.69-.18.95.59.95.59l.33,1.21s.33.24,1.41-.08,1.2-.62,1.2-.62-.17-.6-.32-1.22a.66.66,0,0,1,.45-.8l1.26-.34a3.63,3.63,0,0,0-.07-1.43c-.19-.93-.6-1.05-.6-1.05l-1.25.34c-.65.17-.82-.54-.82-.54l-.36-1.33s-.25-.24-1.35,0-1.26.64-1.26.64.14.61.35,1.34a.7.7,0,0,1-.48.88l-.07,0Z" style="fill: #242424"/>
|
||||
<path id="e8012624-d689-4ee7-a77a-99e9713ea199" data-name="3179af54-0c25-42bc-9804-f3575e0b1b0b" d="M17.44,24.25a.47.47,0,0,1-.56-.32l-.55-2.06h0a.45.45,0,0,1,.32-.55h0l1.63-.23,1.44-.6a.47.47,0,0,1,.56.32l.55,2.05h0a.45.45,0,0,1-.32.55h0L18.94,24Z" style="fill: #3c3c3c"/>
|
||||
<path id="31a64bab-6b92-41d0-afe9-392c1fae8ddb" data-name="841a583e-aa25-4a7e-8907-fbe64ce57066" d="M9.88,17.31a.46.46,0,0,1,.33-.56l2-.55h0a.47.47,0,0,1,.56.33L13,18.16l.6,1.45a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.57-1.53L9.84,17.3Z" style="fill: #3c3c3c"/>
|
||||
<path id="2b1c6b9e-6fda-40be-8bb8-318c30b7dca4" data-name="42515acc-688f-41c7-884c-80b8a90e09c0" d="M16.82,9.8a.47.47,0,0,1,.56.32l.55,2.05h0a.46.46,0,0,1-.33.55L16,13l-1.45.61a.45.45,0,0,1-.55-.32h0l-.53-2.1h0a.45.45,0,0,1,.31-.56h0l1.53-.57,1.55-.25Z" style="fill: #3c3c3c"/>
|
||||
<path id="be04cab5-eaac-4d03-a1ee-dbe70dd5bf90" data-name="8690082b-7091-4631-a199-b79823698dd6" d="M24.33,16.74a.43.43,0,0,1-.3.54h0l-2,.55h0a.46.46,0,0,1-.55-.33l-.22-1.64-.6-1.44a.45.45,0,0,1,.31-.56h0l2-.55h0a.46.46,0,0,1,.56.33l.57,1.53.25,1.55Z" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
28
sim/visuals/assets/MediumMotor.svg
Normal file
@ -0,0 +1,28 @@
|
||||
<svg id="svg7610" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 44.14 44.15">
|
||||
<defs>
|
||||
<linearGradient id="motor-linear-gradient" x1="-313.1" y1="551.59" x2="-313.1" y2="551.43" gradientTransform="matrix(44.14, 0, 0, -44.15, 13843.7, 24396.04)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8a9a8"/>
|
||||
<stop offset="1" stop-color="#545554"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>MediumMotor</title>
|
||||
<g id="Medium_Motor" data-name="Medium Motor">
|
||||
<g id="Group_4" data-name="Group 4">
|
||||
<path id="Path_1" data-name="Path 1" d="M4.07,1.5h39a2.36,2.36,0,0,1,2.57,2V43.82c0,1-1.1,1.82-2.57,1.82h-39c-1.47,0-2.57-.81-2.57-1.82V3.47A2.36,2.36,0,0,1,4.07,1.5Z" transform="translate(-1.5 -1.49)" style="fill: url(#motor-linear-gradient)"/>
|
||||
</g>
|
||||
<g id="Group_7" data-name="Group 7">
|
||||
<g id="g7596">
|
||||
<path id="Union_1-2" data-name="Union 1-2" d="M1.5,22.74a6.21,6.21,0,0,1,6.22-6.22h8.8V7.72A6.22,6.22,0,0,1,22.74,1.5H24.4a6.21,6.21,0,0,1,6.22,6.22v8.8h8.8a6.21,6.21,0,0,1,6.22,6.22V24.4a6.22,6.22,0,0,1-6.22,6.22h-8.8v8.8a6.22,6.22,0,0,1-6.22,6.22H22.74a6.23,6.23,0,0,1-6.22-6.22h0v-8.8H7.72A6.22,6.22,0,0,1,1.5,24.4h0Z" transform="translate(-1.5 -1.49)" style="fill: #a8a9a8"/>
|
||||
</g>
|
||||
<circle id="Ellipse_1" data-name="Ellipse 1" cx="37.77" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2" data-name="Ellipse 2" cx="6.37" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_1-2" data-name="Ellipse 1-2" cx="22.15" cy="6.38" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2-2" data-name="Ellipse 2-2" cx="22.15" cy="37.78" r="4.85" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
<g id="Ellipse_4" data-name="Ellipse 4">
|
||||
<circle id="ellipse7603" cx="22.3" cy="22.16" r="6.75" style="fill: #b72b1c"/>
|
||||
<circle id="ellipse7605" cx="22.3" cy="22.16" r="6.63" style="fill: none;stroke: #8b1104;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="Hole" d="M23.9,26.72s.56-.86,1.18-.51,1.27.73,1.27.73a2.37,2.37,0,0,0,1.24-1.23c.63-1.1.49-1.57.49-1.57l-1.41-.81a.64.64,0,0,1-.32-.86l.06-.1.84-1.44a3.9,3.9,0,0,0-1.39-1.13,6,6,0,0,0-1.6-.59l-.83,1.44a.73.73,0,0,1-1,.24,11.15,11.15,0,0,0-1.32-.6s-.54.13-1.2,1.2-.51,1.6-.51,1.6l1.46.84a.64.64,0,0,1,.4.82.55.55,0,0,1-.08.15,11.25,11.25,0,0,1-.82,1.43A4.83,4.83,0,0,0,23.19,28C23.56,27.35,23.9,26.72,23.9,26.72Z" transform="translate(-1.5 -1.49)"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
30
sim/visuals/assets/MediumMotorsvg.ts
Normal file
@ -0,0 +1,30 @@
|
||||
namespace pxsim.visuals {
|
||||
export const MEDIUM_MOTOR_SVG = `<svg id="svg7610" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 44.14 44.15">
|
||||
<defs>
|
||||
<linearGradient id="motor-linear-gradient" x1="-313.1" y1="551.59" x2="-313.1" y2="551.43" gradientTransform="matrix(44.14, 0, 0, -44.15, 13843.7, 24396.04)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8a9a8"/>
|
||||
<stop offset="1" stop-color="#545554"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>Medium Motor</title>
|
||||
<g id="Medium_Motor" data-name="Medium Motor">
|
||||
<g id="Group_4" data-name="Group 4">
|
||||
<path id="Path_1" data-name="Path 1" d="M4.07,1.5h39a2.36,2.36,0,0,1,2.57,2V43.82c0,1-1.1,1.82-2.57,1.82h-39c-1.47,0-2.57-.81-2.57-1.82V3.47A2.36,2.36,0,0,1,4.07,1.5Z" transform="translate(-1.5 -1.49)" style="fill: url(#motor-linear-gradient)"/>
|
||||
</g>
|
||||
<g id="Group_7" data-name="Group 7">
|
||||
<g id="g7596">
|
||||
<path id="Union_1-2" data-name="Union 1-2" d="M1.5,22.74a6.21,6.21,0,0,1,6.22-6.22h8.8V7.72A6.22,6.22,0,0,1,22.74,1.5H24.4a6.21,6.21,0,0,1,6.22,6.22v8.8h8.8a6.21,6.21,0,0,1,6.22,6.22V24.4a6.22,6.22,0,0,1-6.22,6.22h-8.8v8.8a6.22,6.22,0,0,1-6.22,6.22H22.74a6.23,6.23,0,0,1-6.22-6.22h0v-8.8H7.72A6.22,6.22,0,0,1,1.5,24.4h0Z" transform="translate(-1.5 -1.49)" style="fill: #a8a9a8"/>
|
||||
</g>
|
||||
<circle id="Ellipse_1" data-name="Ellipse 1" cx="37.77" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2" data-name="Ellipse 2" cx="6.37" cy="22.16" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_1-2" data-name="Ellipse 1-2" cx="22.15" cy="6.38" r="4.85" style="fill: #3c3c3c"/>
|
||||
<circle id="Ellipse_2-2" data-name="Ellipse 2-2" cx="22.15" cy="37.78" r="4.85" style="fill: #3c3c3c"/>
|
||||
</g>
|
||||
<g id="Ellipse_4" data-name="Ellipse 4">
|
||||
<circle id="ellipse7603" cx="22.3" cy="22.16" r="6.75" style="fill: #b72b1c"/>
|
||||
<circle id="ellipse7605" cx="22.3" cy="22.16" r="6.63" style="fill: none;stroke: #8b1104;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="Hole" d="M22.09,21s-.05,1-.77,1H19.86a2.37,2.37,0,0,0-.45,1.69c0,1.27.36,1.6.36,1.6h1.62a.64.64,0,0,1,.7.59.2.2,0,0,1,0,.11v1.67a4,4,0,0,0,1.77.29,6.88,6.88,0,0,0,1.68-.29V26a.73.73,0,0,1,.73-.7,9.89,9.89,0,0,0,1.44-.14s.4-.37.44-1.63-.36-1.64-.36-1.64H26.1a.65.65,0,0,1-.75-.51.5.5,0,0,1,0-.17,11.36,11.36,0,0,1,0-1.65,4.9,4.9,0,0,0-3.25,0C22.08,20.23,22.09,21,22.09,21Z" transform="translate(-1.5 -1.49)"/>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
13
sim/visuals/assets/Portsvg.ts
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const PORT_SVG = `<svg id="svg6348" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49.96 58.93">
|
||||
<title>port</title>
|
||||
<g id="icn_port" data-name="icn port">
|
||||
<path id="port_2" data-name="port 2" d="M4.48,0h50V58.93h-50Z" transform="translate(-4.48)" style="fill: #eaeaea"/>
|
||||
<path id="port_1" data-name="port 1" d="M9.74,46.49V18.66H26.85V11.75h4.72V2.59H44.49v8.82h5.06V46.49h-8v7.43H38.9V46.41h-2v7.5H34.71v-7.5H32.55v7.5h-2.1v-7.5H28.6v7.5H26.5v-7.5H24.68v7.5H22.22v-7.5H20.54v7.5H18V46.46Z" transform="translate(-4.48)" style="fill: #a8aaa8"/>
|
||||
<g id="text10060" style="isolation: isolate">
|
||||
<text id="port_text" transform="translate(22.21 40.2)" style="isolation: isolate;font-size: 16px;fill: white;font-family: ArialMT, Arial">B</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
61
sim/visuals/assets/Touch sensor.svg
Normal file
@ -0,0 +1,61 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 37">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-23.5 -19.95)">
|
||||
<path d="M27.94,55.37c-1.06,0-2-.6-2-1.36v-4.4H25a1,1,0,0,1-1-1V29.37a1,1,0,0,1,1-1h1v-5c0-.77.91-1.37,2-1.37H38.71v1.37h6.37V22H56.16c1.07,0,2,.6,2,1.37v5h1a1,1,0,0,1,1,1V48.61a1,1,0,0,1-1,1h-1V54c0,.76-.9,1.37-2,1.37Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-419.47" y1="499.03" x2="-419.47" y2="498.9" gradientTransform="matrix(32.16, 0, 0, -33.37, 13531, 16705.16)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#a20800"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-4" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-5" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-2"/>
|
||||
|
||||
<linearGradient id="linear-gradient-6" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#000"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-7" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-8" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-9" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-6"/>
|
||||
</defs>
|
||||
<title>Touch sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="_457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6" data-name="457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6">
|
||||
<g id="Touch_sensor" data-name="Touch sensor">
|
||||
<g id="touch_box" data-name="touch box">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="touch_box_grey" data-name="touch box grey">
|
||||
<g id="touch_box_total" data-name="touch box total">
|
||||
<path id="touch_box_1" data-name="touch box 1" d="M24.76,28.37H59.34a.76.76,0,0,1,.76.76V48.85a.76.76,0,0,1-.76.76H24.76a.76.76,0,0,1-.76-.76V29.13A.76.76,0,0,1,24.76,28.37Z" transform="translate(-23.5 -19.95)" style="fill: #a8aaa8"/>
|
||||
<g>
|
||||
<image width="37" height="37" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAACXBIWXMAAAsSAAALEgHS3X78AAAA/UlEQVRYR+2YvY3DMAxG3xekVGZw+gyQOW6Sm+VmuAEyTfr4VrB6ppBkGEb+6ATJFXyAIAigyEdbFWVm/EfW04MkXQu8hV3o7tlcajklJWALpOvXLpKBvu6NBHQsy3Uys7yGsbst8A3sAE+3PXCoe6MDvur+KAYcgR9Jx+mvTBSpPT6xXV3PfrH2HBLM3hhFqK1H2VDE5nhyNMY7c7GlLJG4yepewKcIMS8h5iXEvISYlxDzEmJeQsxLiHkJMS8h5iXEvISYlxDzMhf79HhxrD8Vy8AfMNSAd6+h1s9Qpz1mZpJ64JdCx/tp9Xszs3HUCSBpg3/g9ioyRWoAOAOiRFr4OQdRFAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="touch_box_2-2" data-name="touch box 2-2" d="M27.94,22H38.71v1.37h6.37V22H56.15c1.07,0,2,.6,2,1.37V54c0,.76-.9,1.36-2,1.36H27.94c-1.07,0-2-.6-2-1.36V23.37C26,22.6,26.87,22,27.94,22Z" transform="translate(-23.5 -19.95)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="touch_boxside_1" data-name="touch boxside 1" x="35.08" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_2" data-name="touch boxside 2" x="1.41" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_3" data-name="touch boxside 3" x="35.08" y="20.1" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_4" data-name="touch boxside 4" x="1.41" y="20.1" width="0.76" height="6.07"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="touch_btn" data-name="touch btn">
|
||||
<rect id="touch_gradient4" data-name="touch gradient4" x="5.05" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-2)"/>
|
||||
<rect id="touch_gradient3" data-name="touch gradient3" x="15.44" y="6.22" width="6.22" height="9.56" style="fill: url(#linear-gradient-3)"/>
|
||||
<rect id="touch_gradient2" data-name="touch gradient2" x="22.49" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-4)"/>
|
||||
<rect id="touch_gradient1" data-name="touch gradient1" x="15.44" y="23.67" width="6.22" height="9.56" style="fill: url(#linear-gradient-5)"/>
|
||||
<g id="touch_red" data-name="touch red">
|
||||
<circle cx="18.55" cy="19.8" r="6.07" style="fill: #d42715"/>
|
||||
<circle cx="18.55" cy="19.8" r="5.94" style="fill: none;stroke: #a20800;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="touch_hole" data-name="touch hole" d="M40.52,37.33s-.05.91-.69.92H38.52a2.13,2.13,0,0,0-.41,1.52c0,1.14.32,1.44.32,1.44h1.46a.58.58,0,0,1,.63.53v1.6a3.46,3.46,0,0,0,1.59.26,5.9,5.9,0,0,0,1.5-.26v-1.5a.67.67,0,0,1,.66-.63,9.38,9.38,0,0,0,1.3-.12s.36-.34.39-1.47-.31-1.48-.31-1.48H44.12a.57.57,0,0,1-.67-.45.86.86,0,0,1,0-.16,9,9,0,0,1,0-1.47,4.31,4.31,0,0,0-2.92,0C40.5,36.68,40.52,37.33,40.52,37.33Z" transform="translate(-23.5 -19.95)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.9 KiB |
64
sim/visuals/assets/TouchSensorsvg.ts
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const TOUCH_SENSOR_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 37">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-23.5 -19.95)">
|
||||
<path d="M27.94,55.37c-1.06,0-2-.6-2-1.36v-4.4H25a1,1,0,0,1-1-1V29.37a1,1,0,0,1,1-1h1v-5c0-.77.91-1.37,2-1.37H38.71v1.37h6.37V22H56.16c1.07,0,2,.6,2,1.37v5h1a1,1,0,0,1,1,1V48.61a1,1,0,0,1-1,1h-1V54c0,.76-.9,1.37-2,1.37Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-419.47" y1="499.03" x2="-419.47" y2="498.9" gradientTransform="matrix(32.16, 0, 0, -33.37, 13531, 16705.16)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#a8aaa8"/>
|
||||
<stop offset="1" stop-color="#535453"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#a20800"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-3" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-4" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-2"/>
|
||||
<linearGradient id="linear-gradient-5" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-2"/>
|
||||
|
||||
<linearGradient id="linear-gradient-6" x1="-523.02" y1="1202.1" x2="-523.91" y2="1202.1" gradientTransform="matrix(9.56, 0, 0, -6.22, 5012.11, 7495.73)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#d42715"/>
|
||||
<stop offset="1" stop-color="#000"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-7" x1="-937.08" y1="111.13" x2="-937.97" y2="111.13" gradientTransform="matrix(0, 9.56, 6.22, 0, -672.58, 8970)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-8" x1="-227.08" y1="-525.1" x2="-227.97" y2="-525.1" gradientTransform="matrix(-9.56, 0, 0, 6.22, -2147, 3285.47)" xlink:href="#linear-gradient-6"/>
|
||||
<linearGradient id="linear-gradient-9" x1="186.98" y1="565.87" x2="186.08" y2="565.87" gradientTransform="matrix(0, -9.56, -6.22, 0, 3537.68, 1810.89)" xlink:href="#linear-gradient-6"/>
|
||||
</defs>
|
||||
<title>Touch sensor</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="_457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6" data-name="457f40bb-bec4-4a4a-9249-bb4ee7f4f5d6">
|
||||
<g id="Touch_sensor" data-name="Touch sensor">
|
||||
<g id="touch_box" data-name="touch box">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="touch_box_grey" data-name="touch box grey">
|
||||
<g id="touch_box_total" data-name="touch box total">
|
||||
<path id="touch_box_1" data-name="touch box 1" d="M24.76,28.37H59.34a.76.76,0,0,1,.76.76V48.85a.76.76,0,0,1-.76.76H24.76a.76.76,0,0,1-.76-.76V29.13A.76.76,0,0,1,24.76,28.37Z" transform="translate(-23.5 -19.95)" style="fill: #a8aaa8"/>
|
||||
<g>
|
||||
<image width="37" height="37" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAACXBIWXMAAAsSAAALEgHS3X78AAAA/UlEQVRYR+2YvY3DMAxG3xekVGZw+gyQOW6Sm+VmuAEyTfr4VrB6ppBkGEb+6ATJFXyAIAigyEdbFWVm/EfW04MkXQu8hV3o7tlcajklJWALpOvXLpKBvu6NBHQsy3Uys7yGsbst8A3sAE+3PXCoe6MDvur+KAYcgR9Jx+mvTBSpPT6xXV3PfrH2HBLM3hhFqK1H2VDE5nhyNMY7c7GlLJG4yepewKcIMS8h5iXEvISYlxDzEmJeQsxLiHkJMS8h5iXEvISYlxDzMhf79HhxrD8Vy8AfMNSAd6+h1s9Qpz1mZpJ64JdCx/tp9Xszs3HUCSBpg3/g9ioyRWoAOAOiRFr4OQdRFAAAAABJRU5ErkJggg==" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="touch_box_2-2" data-name="touch box 2-2" d="M27.94,22H38.71v1.37h6.37V22H56.15c1.07,0,2,.6,2,1.37V54c0,.76-.9,1.36-2,1.36H27.94c-1.07,0-2-.6-2-1.36V23.37C26,22.6,26.87,22,27.94,22Z" transform="translate(-23.5 -19.95)" style="fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<rect id="touch_boxside_1" data-name="touch boxside 1" x="35.08" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_2" data-name="touch boxside 2" x="1.41" y="11.45" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_3" data-name="touch boxside 3" x="35.08" y="20.1" width="0.76" height="6.07"/>
|
||||
<rect id="touch_boxside_4" data-name="touch boxside 4" x="1.41" y="20.1" width="0.76" height="6.07"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="touch_btn" data-name="touch btn">
|
||||
<rect id="touch_gradient4" data-name="touch gradient4" x="5.05" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-2)"/>
|
||||
<rect id="touch_gradient3" data-name="touch gradient3" x="15.44" y="6.22" width="6.22" height="9.56" style="fill: url(#linear-gradient-3)"/>
|
||||
<rect id="touch_gradient2" data-name="touch gradient2" x="22.49" y="16.76" width="9.56" height="6.22" style="fill: url(#linear-gradient-4)"/>
|
||||
<rect id="touch_gradient1" data-name="touch gradient1" x="15.44" y="23.67" width="6.22" height="9.56" style="fill: url(#linear-gradient-5)"/>
|
||||
<g id="touch_red" data-name="touch red">
|
||||
<circle cx="18.55" cy="19.8" r="6.07" style="fill: #d42715"/>
|
||||
<circle cx="18.55" cy="19.8" r="5.94" style="fill: none;stroke: #a20800;stroke-width: 0.25px"/>
|
||||
</g>
|
||||
<path id="touch_hole" data-name="touch hole" d="M40.52,37.33s-.05.91-.69.92H38.52a2.13,2.13,0,0,0-.41,1.52c0,1.14.32,1.44.32,1.44h1.46a.58.58,0,0,1,.63.53v1.6a3.46,3.46,0,0,0,1.59.26,5.9,5.9,0,0,0,1.5-.26v-1.5a.67.67,0,0,1,.66-.63,9.38,9.38,0,0,0,1.3-.12s.36-.34.39-1.47-.31-1.48-.31-1.48H44.12a.57.57,0,0,1-.67-.45.86.86,0,0,1,0-.16,9,9,0,0,1,0-1.47,4.31,4.31,0,0,0-2.92,0C40.5,36.68,40.52,37.33,40.52,37.33Z" transform="translate(-23.5 -19.95)"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
51
sim/visuals/assets/gyro.svg
Normal file
@ -0,0 +1,51 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 62.5">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-11.5 1.52)">
|
||||
<path d="M21.71,61a8.91,8.91,0,0,1-2-.46H15.49a2,2,0,0,1-2-2h0V54h-.76a.76.76,0,0,1-.76-.76V7a.76.76,0,0,1,.76-.76h.76V2a2,2,0,0,1,2-2H28.14V.61h3.42V0H44.31a2,2,0,0,1,2,2h0V6.22h.91A.76.76,0,0,1,48,7h0V53.24a.76.76,0,0,1-.76.76h-.91v4.55a2,2,0,0,1-2,2H40.17c-.18.3-1.91.46-2.23.46Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-438.91" y1="1403.05" x2="-438.91" y2="1402.05" gradientTransform="matrix(32.76, 0, 0, -5.01, 14410.48, 7079.21)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#3e3e3e"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-468.07" y1="2985.3" x2="-468.07" y2="2984.3" gradientTransform="matrix(20.61, 0, 0, -2.03, 9674.72, 6104.84)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>gyro</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg5788">
|
||||
<g id="gyro">
|
||||
<g id="gyro_total" data-name="gyro total">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="gyro_mask_total" data-name="gyro mask total">
|
||||
<g id="gyro_box" data-name="gyro box">
|
||||
<path id="gyro_sides" data-name="gyro sides" d="M12.76,6.22H47.19A.76.76,0,0,1,48,7V53.24a.76.76,0,0,1-.76.76H12.76a.76.76,0,0,1-.76-.76V7A.76.76,0,0,1,12.76,6.22Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
<rect id="gyro_grey_behind" data-name="gyro grey behind" x="15.52" y="2.13" width="5.76" height="15.77" style="fill: #9a9a9a"/>
|
||||
<g>
|
||||
<image width="37" height="51" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA0CAYAAADmI0o+AAAACXBIWXMAAAsSAAALEgHS3X78AAABDklEQVRYR+2ZwU3DQBBF36DcSBHcU0DKohZqoKZwJmkh5jwcNg62iRHfHkEO/0mWbXn99TyytKudyEzukU1/ERFb4AnYzo6epwPeM7OrytkARETQwp6BHRDz734jgQPwEhFv1OQcrhWjfeEO2KMHwleFSnKGYtCC+kNhOn51zsNPo/4Ti6lYTMViKhZTsZhKpdjS+fEm00l8Kf2Kgst5yVpsRIXYcC33ATxe7ldVrkIMxhWDlVJQJwYFMkMqf/5SLKZiMRWLqVhMxWIqFlOxmIrFVCymYjEVi6lYTMViKvcmdm2eTjdVcvjwjzkDJ1rPciTW0fqFULxz80uOwCtwzMyMvvW8sjNbQUeTOgN8AqpBM7JNqq/cAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="gyro_grey_large-2" data-name="gyro grey large-2" d="M15.49,0H28.15V16l3.42-.26V0H44.31a2,2,0,0,1,2,2h0V45.81a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="gyro_white" data-name="gyro white">
|
||||
<g id="gyro_white-2" data-name="gyro white-2">
|
||||
<path id="gyro_white_2" data-name="gyro white 2" d="M14.73,29.58H45.07a1.21,1.21,0,0,1,1.21,1.21h0V58.55a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V30.79A1.21,1.21,0,0,1,14.73,29.58Z" transform="translate(-11.5 1.52)" style="fill: #f1f1f1"/>
|
||||
<path id="gyro_white_1" data-name="gyro white 1" d="M13.52,55.52H46.28v3a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0Z" transform="translate(-11.5 1.52)" style="opacity: 0.600000023841858;isolation: isolate;fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<g id="gyro_white_small" data-name="gyro white small">
|
||||
<path d="M37.94,60.85H21.71a7.84,7.84,0,0,1-1.26-.24,3.14,3.14,0,0,1-1-.38l1.25-1a1.8,1.8,0,0,1,1.05-.36H37.94a1,1,0,0,1,.6.33l.16.15L40,60.49a2.47,2.47,0,0,1-.93.25A11.33,11.33,0,0,1,37.94,60.85Z" transform="translate(-11.5 1.52)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path d="M37.94,60.73a9,9,0,0,0,1.85-.27L38.62,59.4l-.17-.14c-.18-.17-.34-.31-.51-.31H21.71a1.68,1.68,0,0,0-1,.34l-1.11.93a8.7,8.7,0,0,0,2.08.51H37.94m0,.25H21.71c-.34,0-2.46-.44-2.46-.78l1.33-1.1a1.88,1.88,0,0,1,1.13-.4H37.94c.33,0,.57.29.84.51l1.4,1.26C40.18,60.81,38.27,61,37.94,61Z" transform="translate(-11.5 1.52)" style="fill: #9a9a9a"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="gyro_red_elements" data-name="gyro red elements">
|
||||
<circle id="gyro_reddot" data-name="gyro reddot" cx="18.4" cy="18.97" r="3.03" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow_2" data-name="gyro arrow 2" d="M21.92,23.36s-3.9-5.13-.76-10.77a9.59,9.59,0,0,0,.91.45c.65.37.74-.3.61-.75l-1.21-3.8-3.8,1.07a1.2,1.2,0,0,0-.45.15c-.2.12-.37.4,0,.61l1.06.6s-4.53,6.65,1.06,14.26C20.94,24,21.92,23.36,21.92,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow1" data-name="gyro arrow1" d="M37.84,23.36s3.9-5.13.76-10.77a9.59,9.59,0,0,1-.91.45c-.64.37-.74-.3-.6-.75l1.21-3.8,3.79,1.07a1.31,1.31,0,0,1,.46.15c.2.12.36.4,0,.61l-1.07.6S46,17.57,40.42,25.18C38.83,24,37.84,23.36,37.84,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
54
sim/visuals/assets/gyrosvg.ts
Normal file
@ -0,0 +1,54 @@
|
||||
namespace pxsim {
|
||||
|
||||
export const GYRO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 37 62.5">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(-11.5 1.52)">
|
||||
<path d="M21.71,61a8.91,8.91,0,0,1-2-.46H15.49a2,2,0,0,1-2-2h0V54h-.76a.76.76,0,0,1-.76-.76V7a.76.76,0,0,1,.76-.76h.76V2a2,2,0,0,1,2-2H28.14V.61h3.42V0H44.31a2,2,0,0,1,2,2h0V6.22h.91A.76.76,0,0,1,48,7h0V53.24a.76.76,0,0,1-.76.76h-.91v4.55a2,2,0,0,1-2,2H40.17c-.18.3-1.91.46-2.23.46Z" style="fill: none"/>
|
||||
</clipPath>
|
||||
<linearGradient id="linear-gradient" x1="-438.91" y1="1403.05" x2="-438.91" y2="1402.05" gradientTransform="matrix(32.76, 0, 0, -5.01, 14410.48, 7079.21)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#3e3e3e"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-2" x1="-468.07" y1="2985.3" x2="-468.07" y2="2984.3" gradientTransform="matrix(20.61, 0, 0, -2.03, 9674.72, 6104.84)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#fff"/>
|
||||
<stop offset="1" stop-color="gray"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<title>gyro</title>
|
||||
<g style="isolation: isolate">
|
||||
<g id="svg5788">
|
||||
<g id="gyro">
|
||||
<g id="gyro_total" data-name="gyro total">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="gyro_mask_total" data-name="gyro mask total">
|
||||
<g id="gyro_box" data-name="gyro box">
|
||||
<path id="gyro_sides" data-name="gyro sides" d="M12.76,6.22H47.19A.76.76,0,0,1,48,7V53.24a.76.76,0,0,1-.76.76H12.76a.76.76,0,0,1-.76-.76V7A.76.76,0,0,1,12.76,6.22Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
<rect id="gyro_grey_behind" data-name="gyro grey behind" x="15.52" y="2.13" width="5.76" height="15.77" style="fill: #9a9a9a"/>
|
||||
<g>
|
||||
<image width="37" height="51" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAA0CAYAAADmI0o+AAAACXBIWXMAAAsSAAALEgHS3X78AAABDklEQVRYR+2ZwU3DQBBF36DcSBHcU0DKohZqoKZwJmkh5jwcNg62iRHfHkEO/0mWbXn99TyytKudyEzukU1/ERFb4AnYzo6epwPeM7OrytkARETQwp6BHRDz734jgQPwEhFv1OQcrhWjfeEO2KMHwleFSnKGYtCC+kNhOn51zsNPo/4Ti6lYTMViKhZTsZhKpdjS+fEm00l8Kf2Kgst5yVpsRIXYcC33ATxe7ldVrkIMxhWDlVJQJwYFMkMqf/5SLKZiMRWLqVhMxWIqFlOxmIrFVCymYjEVi6lYTMViKvcmdm2eTjdVcvjwjzkDJ1rPciTW0fqFULxz80uOwCtwzMyMvvW8sjNbQUeTOgN8AqpBM7JNqq/cAAAAAElFTkSuQmCC" style="opacity: 0.30000000000000004;mix-blend-mode: multiply"/>
|
||||
<path id="gyro_grey_large-2" data-name="gyro grey large-2" d="M15.49,0H28.15V16l3.42-.26V0H44.31a2,2,0,0,1,2,2h0V45.81a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V2a2,2,0,0,1,2-2Z" transform="translate(-11.5 1.52)" style="fill: #a8aaa8"/>
|
||||
</g>
|
||||
<g id="gyro_white" data-name="gyro white">
|
||||
<g id="gyro_white-2" data-name="gyro white-2">
|
||||
<path id="gyro_white_2" data-name="gyro white 2" d="M14.73,29.58H45.07a1.21,1.21,0,0,1,1.21,1.21h0V58.55a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0V30.79A1.21,1.21,0,0,1,14.73,29.58Z" transform="translate(-11.5 1.52)" style="fill: #f1f1f1"/>
|
||||
<path id="gyro_white_1" data-name="gyro white 1" d="M13.52,55.52H46.28v3a2,2,0,0,1-2,2H15.49a2,2,0,0,1-2-2h0Z" transform="translate(-11.5 1.52)" style="opacity: 0.600000023841858;isolation: isolate;fill: url(#linear-gradient)"/>
|
||||
</g>
|
||||
<g id="gyro_white_small" data-name="gyro white small">
|
||||
<path d="M37.94,60.85H21.71a7.84,7.84,0,0,1-1.26-.24,3.14,3.14,0,0,1-1-.38l1.25-1a1.8,1.8,0,0,1,1.05-.36H37.94a1,1,0,0,1,.6.33l.16.15L40,60.49a2.47,2.47,0,0,1-.93.25A11.33,11.33,0,0,1,37.94,60.85Z" transform="translate(-11.5 1.52)" style="fill: url(#linear-gradient-2)"/>
|
||||
<path d="M37.94,60.73a9,9,0,0,0,1.85-.27L38.62,59.4l-.17-.14c-.18-.17-.34-.31-.51-.31H21.71a1.68,1.68,0,0,0-1,.34l-1.11.93a8.7,8.7,0,0,0,2.08.51H37.94m0,.25H21.71c-.34,0-2.46-.44-2.46-.78l1.33-1.1a1.88,1.88,0,0,1,1.13-.4H37.94c.33,0,.57.29.84.51l1.4,1.26C40.18,60.81,38.27,61,37.94,61Z" transform="translate(-11.5 1.52)" style="fill: #9a9a9a"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="gyro_red_elements" data-name="gyro red elements">
|
||||
<circle id="gyro_reddot" data-name="gyro reddot" cx="18.4" cy="18.97" r="3.03" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow_2" data-name="gyro arrow 2" d="M21.92,23.36s-3.9-5.13-.76-10.77a9.59,9.59,0,0,0,.91.45c.65.37.74-.3.61-.75l-1.21-3.8-3.8,1.07a1.2,1.2,0,0,0-.45.15c-.2.12-.37.4,0,.61l1.06.6s-4.53,6.65,1.06,14.26C20.94,24,21.92,23.36,21.92,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
<path id="gyro_arrow1" data-name="gyro arrow1" d="M37.84,23.36s3.9-5.13.76-10.77a9.59,9.59,0,0,1-.91.45c-.64.37-.74-.3-.6-.75l1.21-3.8,3.79,1.07a1.31,1.31,0,0,1,.46.15c.2.12.36.4,0,.61l-1.07.6S46,17.57,40.42,25.18C38.83,24,37.84,23.36,37.84,23.36Z" transform="translate(-11.5 1.52)" style="fill: #d42715"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
10
sim/visuals/assets/port.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg id="svg6348" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49.96 58.93">
|
||||
<title>port</title>
|
||||
<g id="icn_port" data-name="icn port">
|
||||
<path id="port_2" data-name="port 2" d="M4.48,0h50V58.93h-50Z" transform="translate(-4.48)" style="fill: #eaeaea"/>
|
||||
<path id="port_1" data-name="port 1" d="M9.74,46.49V18.66H26.85V11.75h4.72V2.59H44.49v8.82h5.06V46.49h-8v7.43H38.9V46.41h-2v7.5H34.71v-7.5H32.55v7.5h-2.1v-7.5H28.6v7.5H26.5v-7.5H24.68v7.5H22.22v-7.5H20.54v7.5H18V46.46Z" transform="translate(-4.48)" style="fill: #a8aaa8"/>
|
||||
<g id="text10060" style="isolation: isolate">
|
||||
<text id="port_text" transform="translate(22.21 40.2)" style="isolation: isolate;font-size: 16px;fill: white;font-family: ArialMT, Arial">B</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 765 B |
77
sim/visuals/assets/ultra sonic.svg
Normal file
@ -0,0 +1,77 @@
|
||||
<svg id="svg5190" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 83.53 35.14">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(0.04 -22.43)">
|
||||
<circle cx="17.53" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip-path-2" transform="translate(0.04 -22.43)">
|
||||
<circle cx="65.92" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>ultra sonic</title>
|
||||
<g id="ultra_sonic" data-name="ultra sonic">
|
||||
<rect id="US_main_black2" data-name="US main black2" x="22.57" y="1.49" width="43.38" height="31.25" style="fill: #242424"/>
|
||||
<rect id="US_main_black1" data-name="US main black1" x="30.16" y="8.47" width="25.33" height="17.59"/>
|
||||
<g id="US_eye1" data-name="US eye1">
|
||||
<g id="US_eye1_black" data-name="US eye1 black">
|
||||
<circle cx="17.57" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="17.57" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye1_red" data-name="US eye1 red" cx="17.57" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye1_gold_circle" data-name="US eye1 gold circle" cx="17.57" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye1_wh_in_gold" data-name="US eye1 wh in gold" cx="17.57" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye1_net" data-name="US eye1 net">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||
<g id="US_eye1_net_total" data-name="US eye1 net total">
|
||||
<rect id="US_eye1_net14" data-name="US eye1 net14" x="10.84" y="33.53" width="0.61" height="22.79" transform="translate(-20.93 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net13" data-name="US eye1 net13" x="11.8" y="47.44" width="22.51" height="0.61" transform="translate(-20.75 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net12" data-name="US eye1 net12" x="13.33" y="32.09" width="0.61" height="22.79" transform="translate(-19.88 -9.79) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net11" data-name="US eye1 net11" x="10.36" y="44.95" width="22.51" height="0.61" transform="translate(-19.7 -5.56) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net10" data-name="US eye1 net10" x="15.83" y="30.65" width="0.61" height="22.79" transform="translate(-18.82 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net9" data-name="US eye1 net9" x="8.92" y="42.45" width="22.51" height="0.61" transform="translate(-18.64 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net8" data-name="US eye1 net8" x="18.33" y="29.21" width="0.61" height="22.79" transform="translate(-17.77 -7.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net7" data-name="US eye1 net7" x="7.47" y="39.96" width="22.51" height="0.61" transform="translate(-17.59 -7.67) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net6" data-name="US eye1 net6" x="20.82" y="27.77" width="0.61" height="22.79" transform="translate(-16.72 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net5" data-name="US eye1 net5" x="6.03" y="37.46" width="22.51" height="0.61" transform="translate(-16.53 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net4" data-name="US eye1 net4" x="23.32" y="26.32" width="0.61" height="22.79" transform="translate(-15.66 -5.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net3" data-name="US eye1 net3" x="4.59" y="34.96" width="22.51" height="0.61" transform="translate(-15.48 -9.78) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net2" data-name="US eye1 net2" x="25.81" y="24.88" width="0.61" height="22.79" transform="translate(-14.61 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net1" data-name="US eye1 net1" x="3.15" y="32.47" width="22.51" height="0.61" transform="translate(-14.42 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="US_eye2" data-name="US eye2">
|
||||
<g id="US_eye2_black" data-name="US eye2 black">
|
||||
<circle cx="65.96" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="65.96" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye2_red" data-name="US eye2 red" cx="65.96" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye2_gold_circle" data-name="US eye2 gold circle" cx="65.96" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye2_wh_in_gold" data-name="US eye2 wh in gold" cx="65.96" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye2_net" data-name="US eye2 net">
|
||||
<g style="clip-path: url(#clip-path-2)">
|
||||
<g id="US_eye2_net_mask" data-name="US eye2 net mask">
|
||||
<g id="US_eye2_net_total" data-name="US eye2 net total">
|
||||
<rect id="US_eye2_net14" data-name="US eye2 net14" x="59.23" y="33.53" width="0.61" height="22.79" transform="translate(-14.45 13.35) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net13" data-name="US eye2 net13" x="60.18" y="47.44" width="22.51" height="0.61" transform="translate(-14.27 19.69) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net12" data-name="US eye2 net12" x="61.72" y="32.09" width="0.61" height="22.79" transform="translate(-13.4 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net11" data-name="US eye2 net11" x="58.74" y="44.95" width="22.51" height="0.61" transform="translate(-13.21 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net10" data-name="US eye2 net10" x="64.22" y="30.65" width="0.61" height="22.79" transform="translate(-12.34 15.46) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net9" data-name="US eye2 net9" x="57.3" y="42.45" width="22.51" height="0.61" transform="translate(-12.16 17.58) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net8" data-name="US eye2 net8" x="66.71" y="29.21" width="0.61" height="22.79" transform="translate(-11.29 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net7" data-name="US eye2 net7" x="55.86" y="39.96" width="22.51" height="0.61" transform="translate(-11.1 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net6" data-name="US eye2 net6" x="69.21" y="27.77" width="0.61" height="22.79" transform="translate(-10.23 17.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net5" data-name="US eye2 net5" x="54.42" y="37.46" width="22.51" height="0.61" transform="translate(-10.05 15.47) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net4" data-name="US eye2 net4" x="71.71" y="26.32" width="0.61" height="22.79" transform="translate(-9.18 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net3" data-name="US eye2 net3" x="52.98" y="34.96" width="22.51" height="0.61" transform="translate(-8.99 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net2" data-name="US eye2 net2" x="74.2" y="24.88" width="0.61" height="22.79" transform="translate(-8.12 19.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net1" data-name="US eye2 net1" x="51.54" y="32.47" width="22.51" height="0.61" transform="translate(-7.94 13.36) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 7.6 KiB |
79
sim/visuals/assets/ultrasonicsvg.ts
Normal file
@ -0,0 +1,79 @@
|
||||
namespace pxsim {
|
||||
export const ULTRASONIC_SVG = `<svg id="svg5190" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 83.53 35.14">
|
||||
<defs>
|
||||
<clipPath id="clip-path" transform="translate(0.04 -22.43)">
|
||||
<circle cx="17.53" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip-path-2" transform="translate(0.04 -22.43)">
|
||||
<circle cx="65.92" cy="40" r="6.98" style="fill: none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<title>ultra sonic</title>
|
||||
<g id="ultra_sonic" data-name="ultra sonic">
|
||||
<rect id="US_main_black2" data-name="US main black2" x="22.57" y="1.49" width="43.38" height="31.25" style="fill: #242424"/>
|
||||
<rect id="US_main_black1" data-name="US main black1" x="30.16" y="8.47" width="25.33" height="17.59"/>
|
||||
<g id="US_eye1" data-name="US eye1">
|
||||
<g id="US_eye1_black" data-name="US eye1 black">
|
||||
<circle cx="17.57" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="17.57" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye1_red" data-name="US eye1 red" cx="17.57" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye1_gold_circle" data-name="US eye1 gold circle" cx="17.57" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye1_wh_in_gold" data-name="US eye1 wh in gold" cx="17.57" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye1_net" data-name="US eye1 net">
|
||||
<g style="clip-path: url(#clip-path)">
|
||||
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||
<g id="US_eye1_net_total" data-name="US eye1 net total">
|
||||
<rect id="US_eye1_net14" data-name="US eye1 net14" x="10.84" y="33.53" width="0.61" height="22.79" transform="translate(-20.93 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net13" data-name="US eye1 net13" x="11.8" y="47.44" width="22.51" height="0.61" transform="translate(-20.75 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net12" data-name="US eye1 net12" x="13.33" y="32.09" width="0.61" height="22.79" transform="translate(-19.88 -9.79) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net11" data-name="US eye1 net11" x="10.36" y="44.95" width="22.51" height="0.61" transform="translate(-19.7 -5.56) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net10" data-name="US eye1 net10" x="15.83" y="30.65" width="0.61" height="22.79" transform="translate(-18.82 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net9" data-name="US eye1 net9" x="8.92" y="42.45" width="22.51" height="0.61" transform="translate(-18.64 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net8" data-name="US eye1 net8" x="18.33" y="29.21" width="0.61" height="22.79" transform="translate(-17.77 -7.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net7" data-name="US eye1 net7" x="7.47" y="39.96" width="22.51" height="0.61" transform="translate(-17.59 -7.67) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net6" data-name="US eye1 net6" x="20.82" y="27.77" width="0.61" height="22.79" transform="translate(-16.72 -6.62) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net5" data-name="US eye1 net5" x="6.03" y="37.46" width="22.51" height="0.61" transform="translate(-16.53 -8.73) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net4" data-name="US eye1 net4" x="23.32" y="26.32" width="0.61" height="22.79" transform="translate(-15.66 -5.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net3" data-name="US eye1 net3" x="4.59" y="34.96" width="22.51" height="0.61" transform="translate(-15.48 -9.78) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net2" data-name="US eye1 net2" x="25.81" y="24.88" width="0.61" height="22.79" transform="translate(-14.61 -4.51) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye1_net1" data-name="US eye1 net1" x="3.15" y="32.47" width="22.51" height="0.61" transform="translate(-14.42 -10.84) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="US_eye2" data-name="US eye2">
|
||||
<g id="US_eye2_black" data-name="US eye2 black">
|
||||
<circle cx="65.96" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
|
||||
<circle cx="65.96" cy="17.57" r="17.32" style="fill: none"/>
|
||||
</g>
|
||||
<circle id="US_eye2_red" data-name="US eye2 red" cx="65.96" cy="17.57" r="10.77" style="fill: #ab1919"/>
|
||||
<circle id="US_eye2_gold_circle" data-name="US eye2 gold circle" cx="65.96" cy="17.57" r="8.04" style="fill: #aa7707"/>
|
||||
<circle id="US_eye2_wh_in_gold" data-name="US eye2 wh in gold" cx="65.96" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
|
||||
<g id="US_eye2_net" data-name="US eye2 net">
|
||||
<g style="clip-path: url(#clip-path-2)">
|
||||
<g id="US_eye2_net_mask" data-name="US eye2 net mask">
|
||||
<g id="US_eye2_net_total" data-name="US eye2 net total">
|
||||
<rect id="US_eye2_net14" data-name="US eye2 net14" x="59.23" y="33.53" width="0.61" height="22.79" transform="translate(-14.45 13.35) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net13" data-name="US eye2 net13" x="60.18" y="47.44" width="22.51" height="0.61" transform="translate(-14.27 19.69) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net12" data-name="US eye2 net12" x="61.72" y="32.09" width="0.61" height="22.79" transform="translate(-13.4 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net11" data-name="US eye2 net11" x="58.74" y="44.95" width="22.51" height="0.61" transform="translate(-13.21 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net10" data-name="US eye2 net10" x="64.22" y="30.65" width="0.61" height="22.79" transform="translate(-12.34 15.46) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net9" data-name="US eye2 net9" x="57.3" y="42.45" width="22.51" height="0.61" transform="translate(-12.16 17.58) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net8" data-name="US eye2 net8" x="66.71" y="29.21" width="0.61" height="22.79" transform="translate(-11.29 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net7" data-name="US eye2 net7" x="55.86" y="39.96" width="22.51" height="0.61" transform="translate(-11.1 16.52) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net6" data-name="US eye2 net6" x="69.21" y="27.77" width="0.61" height="22.79" transform="translate(-10.23 17.57) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net5" data-name="US eye2 net5" x="54.42" y="37.46" width="22.51" height="0.61" transform="translate(-10.05 15.47) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net4" data-name="US eye2 net4" x="71.71" y="26.32" width="0.61" height="22.79" transform="translate(-9.18 18.63) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net3" data-name="US eye2 net3" x="52.98" y="34.96" width="22.51" height="0.61" transform="translate(-8.99 14.41) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net2" data-name="US eye2 net2" x="74.2" y="24.88" width="0.61" height="22.79" transform="translate(-8.12 19.68) rotate(-30)" style="fill: #aa7707"/>
|
||||
<rect id="US_eye2_net1" data-name="US eye2 net1" x="51.54" y="32.47" width="22.51" height="0.61" transform="translate(-7.94 13.36) rotate(-30)" style="fill: #aa7707"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
}
|
Before Width: | Height: | Size: 75 KiB |
@ -1,6 +1,6 @@
|
||||
namespace pxsim.visuals {
|
||||
mkBoardView = (opts: BoardViewOptions): BoardView => {
|
||||
return new visuals.EV3BoardSvg({
|
||||
return new visuals.EV3View({
|
||||
runtime: runtime,
|
||||
theme: visuals.randomTheme(),
|
||||
disableTilt: false,
|
||||
|
51
sim/visuals/controlView.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/// <reference path="./nodes/staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export const CONTROL_WIDTH = 87.5;
|
||||
export const CONTROL_HEIGHT = 175;
|
||||
|
||||
export abstract class ControlView<T extends BaseNode> extends SimView<T> implements LayoutElement {
|
||||
private background: SVGSVGElement;
|
||||
|
||||
abstract getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement): SVGElement;
|
||||
|
||||
constructor(protected parent: SVGSVGElement, protected globalDefs: SVGDefsElement, protected state: T, protected port: number) {
|
||||
super(state);
|
||||
}
|
||||
|
||||
getInnerWidth(): number {
|
||||
return CONTROL_WIDTH;
|
||||
}
|
||||
|
||||
getInnerHeight(): number {
|
||||
return CONTROL_HEIGHT;
|
||||
}
|
||||
|
||||
getPaddingRatio() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getWiringRatio() {
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
buildDom(width: number): SVGElement {
|
||||
this.background = svg.elt("svg", { height: "100%", width: "100%"}) as SVGSVGElement;
|
||||
this.background.appendChild(this.getInnerView(this.parent, this.globalDefs));
|
||||
return this.background;
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
|
||||
}
|
||||
|
||||
getWeight() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
29
sim/visuals/controls/closeIcon.ts
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class CloseIconControl extends ControlView<PortNode> {
|
||||
private closeGroup: SVGGElement;
|
||||
|
||||
getInnerView() {
|
||||
this.closeGroup = svg.elt("g") as SVGGElement;
|
||||
this.closeGroup.style.cursor = 'pointer';
|
||||
const circleCloseWrapper = pxsim.svg.child(this.closeGroup, "g");
|
||||
pxsim.svg.child(circleCloseWrapper, "circle", { 'cx': "16", 'cy': "16", 'r': "16", 'style': "fill: #fff" });
|
||||
pxsim.svg.child(circleCloseWrapper, "circle", { 'cx': "16", 'cy': "16", 'r': "15", 'style': "fill: none;stroke: #a8aaa8;stroke-width: 2px" });
|
||||
pxsim.svg.child(this.closeGroup, "rect", { 'x': "10", 'y': "16", 'width': "18", 'height': "2", 'transform': "translate(-9.46 17.41) rotate(-45)", 'style': "fill: #a8aaa8" });
|
||||
pxsim.svg.child(this.closeGroup, "rect", { 'x': "18", 'y': "8", 'width': "2", 'height': "18", 'transform': "translate(-9.46 17.41) rotate(-45)", 'style': "fill: #a8aaa8" });
|
||||
|
||||
return this.closeGroup;
|
||||
}
|
||||
|
||||
public getInnerHeight() {
|
||||
return 32;
|
||||
}
|
||||
|
||||
public getInnerWidth() {
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
41
sim/visuals/controls/colorGrid.ts
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ColorGridControl extends ControlView<ColorSensorNode> {
|
||||
private group: SVGGElement;
|
||||
|
||||
getInnerView() {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.group.setAttribute("transform", `translate(17, ${35 + this.getHeight() / 4}) scale(5)`)
|
||||
|
||||
const colorIds = ['red', 'yellow', 'blue', 'green', 'black', 'grey'];
|
||||
const colors = ['#f12a21', '#ffd01b', '#006db3', '#00934b', '#000', '#6c2d00'];
|
||||
const colorValue = [5, 4, 2, 3, 1, 7];
|
||||
|
||||
let cy = -4;
|
||||
for (let c = 0; c < colorIds.length; c++) {
|
||||
const cx = c % 2 == 0 ? 2.2 : 8.2;
|
||||
if (c % 2 == 0) cy += 5;
|
||||
const circle = pxsim.svg.child(this.group, "circle", { 'class': 'sim-color-grid-circle', 'cx': cx, 'cy': cy, 'r': '2', 'style': `fill: ${colors[c]}` });
|
||||
circle.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(colorValue[c]);
|
||||
})
|
||||
}
|
||||
|
||||
const whiteCircleWrapper = pxsim.svg.child(this.group, "g", { 'id': 'white-cirlce-wrapper' });
|
||||
pxsim.svg.child(whiteCircleWrapper, "circle", { 'class': 'sim-color-grid-circle', 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: #fff` });
|
||||
pxsim.svg.child(whiteCircleWrapper, "circle", { 'cx': 2.2, 'cy': '16', 'r': '2', 'style': `fill: none;stroke: #94989b;stroke-width: 0.5px` });
|
||||
whiteCircleWrapper.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(6);
|
||||
})
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private setColor(color: number) {
|
||||
const state = this.state;
|
||||
state.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
34
sim/visuals/controls/colorWheel.ts
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ColorWheelControl extends ControlView<ColorSensorNode> {
|
||||
private group: SVGGElement;
|
||||
|
||||
private static COLOR_DARK = 1;
|
||||
private static COLOR_LIGHT = 99;
|
||||
|
||||
getInnerView() {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.group.setAttribute("transform", `translate(12, ${this.getHeight() / 2 - 15}) scale(2.5)`)
|
||||
|
||||
const circle = pxsim.svg.child(this.group, "g");
|
||||
const lightHalf = pxsim.svg.child(circle, "path", { 'class': 'sim-color-wheel-half', 'd': 'M19,28.76a11.71,11.71,0,1,1,4.58-.92A11.74,11.74,0,0,1,19,28.76Z', 'transform': 'translate(-6.5 -4.5)', 'style': `fill: #fff;stroke: #000;stroke-miterlimit: 10` });
|
||||
pxsim.svg.child(circle, "path", { 'd': 'M19,28.52a11.42,11.42,0,0,0,4.48-.9,11.75,11.75,0,0,0,3.67-2.47,11.55,11.55,0,0,0,2.46-3.67,11.48,11.48,0,0,0,0-9,11.41,11.41,0,0,0-6.13-6.13,11.48,11.48,0,0,0-9,0,11.41,11.41,0,0,0-6.13,6.13,11.48,11.48,0,0,0,0,9,11.55,11.55,0,0,0,2.46,3.67,11.75,11.75,0,0,0,3.67,2.47,11.42,11.42,0,0,0,4.48.9M19,29A12,12,0,1,1,31,17,12,12,0,0,1,19,29Z', 'transform': 'translate(-6.5 -4.5)', 'style': `fill: #fff;stroke: #000;stroke-miterlimit: 10` });
|
||||
lightHalf.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(ColorWheelControl.COLOR_LIGHT);
|
||||
})
|
||||
const darkHalf = pxsim.svg.child(this.group, "path", { 'class': 'sim-color-wheel-half', 'd': 'M19,5c.16,8.54,0,14.73,0,24A12,12,0,0,1,19,5Z', 'transform': 'translate(-6.5 -4.5)' });
|
||||
darkHalf.addEventListener(pointerEvents.down, ev => {
|
||||
this.setColor(ColorWheelControl.COLOR_DARK);
|
||||
})
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private setColor(color: number) {
|
||||
const state = this.state;
|
||||
state.setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
120
sim/visuals/controls/distanceSlider.ts
Normal file
@ -0,0 +1,120 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class DistanceSliderControl extends ControlView<UltrasonicSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private gradient: SVGLinearGradientElement;
|
||||
private slider: SVGGElement;
|
||||
|
||||
private static SLIDER_HANDLE_HEIGHT = 31;
|
||||
|
||||
private isVisible = false;
|
||||
|
||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||
let gid = "gradient-slider-" + this.getId();
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.gradient = createGradient(gid, this.getGradientDefinition());
|
||||
this.gradient.setAttribute('x1', '-438.37');
|
||||
this.gradient.setAttribute('y1', '419.43');
|
||||
this.gradient.setAttribute('x2', '-438.37');
|
||||
this.gradient.setAttribute('y2', '418.43');
|
||||
this.gradient.setAttribute('gradientTransform', 'matrix(50, 0, 0, -110, 21949.45, 46137.67)');
|
||||
this.gradient.setAttribute('gradientUnits', 'userSpaceOnUse');
|
||||
globalDefs.appendChild(this.gradient);
|
||||
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
|
||||
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||
sliderGroup.setAttribute("transform", `translate(0, ${10 + this.getTopPadding()})`)
|
||||
|
||||
const rect = pxsim.svg.child(sliderGroup, "rect", { 'x': this.getLeftPadding(), 'y': 2, 'width': this.getWidth() - this.getLeftPadding() * 2, 'height': this.getContentHeight(), 'style': `fill: url(#${gid})` });
|
||||
|
||||
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
||||
const sliderInner = pxsim.svg.child(this.slider, "g");
|
||||
pxsim.svg.child(sliderInner, "rect", { 'width': this.getWidth(), 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' });
|
||||
pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getWidth() - 1, 'height': DistanceSliderControl.SLIDER_HANDLE_HEIGHT - 1, 'rx': '1.5', 'ry': '1.5', 'style': 'fill: none;stroke: #b32e29' });
|
||||
|
||||
const dragSurface = svg.child(this.group, "rect", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.getInnerWidth(),
|
||||
height: this.getInnerHeight(),
|
||||
opacity: 0,
|
||||
cursor: '-webkit-grab'
|
||||
})
|
||||
|
||||
let pt = parent.createSVGPoint();
|
||||
let captured = false;
|
||||
|
||||
touchEvents(dragSurface, ev => {
|
||||
if (captured && (ev as MouseEvent).clientY != undefined) {
|
||||
ev.preventDefault();
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, ev => {
|
||||
captured = true;
|
||||
if ((ev as MouseEvent).clientY != undefined) {
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, () => {
|
||||
captured = false;
|
||||
}, () => {
|
||||
captured = false;
|
||||
})
|
||||
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private getLeftPadding() {
|
||||
return this.getInnerWidth() * 0.12;
|
||||
}
|
||||
|
||||
private getTopPadding() {
|
||||
return this.getInnerHeight() / 4;
|
||||
}
|
||||
|
||||
private getContentHeight() {
|
||||
return this.getInnerHeight() * 0.6;
|
||||
}
|
||||
|
||||
onBoardStateChanged() {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
const node = this.state;
|
||||
const percentage = node.getValue();
|
||||
const y = this.getContentHeight() * percentage / 100;
|
||||
this.slider.setAttribute("transform", `translate(0, ${y - DistanceSliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
super.onComponentVisible();
|
||||
this.isVisible = true;
|
||||
this.onBoardStateChanged();
|
||||
}
|
||||
|
||||
onComponentHidden() {
|
||||
this.isVisible = false;
|
||||
}
|
||||
|
||||
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
let cur = svg.cursorPoint(pt, parent, ev);
|
||||
const height = this.getContentHeight(); //DistanceSliderControl.SLIDER_HEIGHT;
|
||||
let t = Math.max(0, Math.min(1, (this.getTopPadding() + height + this.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
|
||||
|
||||
const state = this.state;
|
||||
state.setDistance((1 - t) * (100));
|
||||
}
|
||||
|
||||
private getGradientDefinition(): LinearGradientDefinition {
|
||||
return {
|
||||
stops: [
|
||||
{ offset: 0, color: '#626262' },
|
||||
{ offset: 1, color: "#ddd" }
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
94
sim/visuals/controls/rotationSlider.ts
Normal file
@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class RotationSliderControl extends ControlView<GyroSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private slider: SVGGElement;
|
||||
|
||||
private isVisible = false;
|
||||
|
||||
private static SLIDER_WIDTH = 70;
|
||||
private static SLIDER_HEIGHT = 78;
|
||||
|
||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
|
||||
const sliderGroup = pxsim.svg.child(this.group, "g");
|
||||
sliderGroup.setAttribute("transform", `translate(5, ${10 + this.getTopPadding()})`)
|
||||
|
||||
const rotationLine = pxsim.svg.child(sliderGroup, "g");
|
||||
pxsim.svg.child(rotationLine, "path", { 'transform': 'translate(5.11 -31.1)', 'd': 'M68.71,99.5l6.1-8S61.3,79.91,42.69,78.35,12,83.14,6.49,85.63a48.69,48.69,0,0,0-9.6,5.89L3.16,99.3S19.27,87.7,37.51,87.94,68.71,99.5,68.71,99.5Z', 'style': 'fill: #626262' });
|
||||
|
||||
this.slider = pxsim.svg.child(sliderGroup, "g") as SVGGElement;
|
||||
const handleInner = pxsim.svg.child(sliderGroup, "g");
|
||||
pxsim.svg.child(this.slider, "circle", { 'cx': 9, 'cy': 50, 'r': 13, 'style': 'fill: #f12a21' });
|
||||
pxsim.svg.child(this.slider, "circle", { 'cx': 9, 'cy': 50, 'r': 12.5, 'style': 'fill: none;stroke: #b32e29' });
|
||||
|
||||
const dragSurface = svg.child(this.group, "rect", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.getInnerWidth(),
|
||||
height: this.getInnerHeight(),
|
||||
opacity: 0,
|
||||
cursor: '-webkit-grab'
|
||||
})
|
||||
|
||||
let pt = parent.createSVGPoint();
|
||||
let captured = false;
|
||||
|
||||
touchEvents(dragSurface, ev => {
|
||||
if (captured && (ev as MouseEvent).clientX != undefined) {
|
||||
ev.preventDefault();
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, ev => {
|
||||
captured = true;
|
||||
if ((ev as MouseEvent).clientX != undefined) {
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, () => {
|
||||
captured = false;
|
||||
}, () => {
|
||||
captured = false;
|
||||
})
|
||||
|
||||
return this.group;
|
||||
}
|
||||
|
||||
private getTopPadding() {
|
||||
return this.getInnerHeight() / 4;
|
||||
}
|
||||
|
||||
onBoardStateChanged() {
|
||||
if (!this.isVisible) {
|
||||
return;
|
||||
}
|
||||
const node = this.state;
|
||||
const percentage = node.getValue();
|
||||
const x = RotationSliderControl.SLIDER_WIDTH * percentage / 100;
|
||||
const y = Math.abs((percentage - 50) / 50) * 10;
|
||||
this.slider.setAttribute("transform", `translate(${x}, ${y})`);
|
||||
}
|
||||
|
||||
onComponentVisible() {
|
||||
super.onComponentVisible();
|
||||
this.isVisible = true;
|
||||
this.onBoardStateChanged();
|
||||
}
|
||||
|
||||
onComponentHidden() {
|
||||
this.isVisible = false;
|
||||
}
|
||||
|
||||
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
let cur = svg.cursorPoint(pt, parent, ev);
|
||||
const width = CONTROL_WIDTH; //DistanceSliderControl.SLIDER_HEIGHT;
|
||||
let t = Math.max(0, Math.min(1, (width + this.left / this.scaleFactor - cur.x / this.scaleFactor) / width))
|
||||
|
||||
const state = this.state;
|
||||
state.setAngle((1 - t) * (100));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
298
sim/visuals/layoutView.ts
Normal file
@ -0,0 +1,298 @@
|
||||
/// <reference path="./view.ts" />
|
||||
/// <reference path="./nodes/staticView.ts" />
|
||||
/// <reference path="./nodes/portView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const DEFAULT_WIDTH = 350;
|
||||
export const DEFAULT_HEIGHT = 700;
|
||||
|
||||
export const BRICK_HEIGHT_RATIO = 1 / 3;
|
||||
export const MODULE_AND_WIRING_HEIGHT_RATIO = 1 / 3; // For inputs and outputs
|
||||
|
||||
export const MODULE_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO * 3 / 4;
|
||||
export const WIRING_HEIGHT_RATIO = MODULE_AND_WIRING_HEIGHT_RATIO / 4;
|
||||
|
||||
export const MODULE_INNER_PADDING_RATIO = 1 / 35;
|
||||
|
||||
export interface LayoutElement extends View {
|
||||
getId(): number;
|
||||
getPort(): number;
|
||||
getPaddingRatio(): number;
|
||||
getWiringRatio(): number;
|
||||
setSelected(selected: boolean): void;
|
||||
}
|
||||
|
||||
export class LayoutView extends ViewContainer {
|
||||
private inputs: LayoutElement[] = [];
|
||||
private outputs: LayoutElement[] = [];
|
||||
|
||||
private inputWires: WireView[] = [];
|
||||
private outputWires: WireView[] = [];
|
||||
|
||||
private selected: number;
|
||||
private selectedIsInput: boolean;
|
||||
private brick: BrickView;
|
||||
private offsets: number[];
|
||||
private contentGroup: SVGGElement;
|
||||
private scrollGroup: SVGGElement;
|
||||
private renderedViews: Map<boolean> = {};
|
||||
|
||||
private childScaleFactor: number;
|
||||
|
||||
private totalLength: number;
|
||||
private height: number;
|
||||
private hasDimensions = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.outputs = [
|
||||
new PortView(0, 'A'),
|
||||
new PortView(1, 'B'),
|
||||
new PortView(2, 'C'),
|
||||
new PortView(3, 'D')
|
||||
];
|
||||
|
||||
this.brick = new BrickView(0);
|
||||
|
||||
this.inputs = [
|
||||
new PortView(0, '1'),
|
||||
new PortView(1, '2'),
|
||||
new PortView(2, '3'),
|
||||
new PortView(3, '4')
|
||||
];
|
||||
|
||||
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
|
||||
this.outputWires[port] = new WireView(port);
|
||||
}
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
this.inputWires[port] = new WireView(port);
|
||||
}
|
||||
}
|
||||
|
||||
public layout(width: number, height: number) {
|
||||
this.hasDimensions = true;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.scrollGroup.setAttribute("width", width.toString());
|
||||
this.scrollGroup.setAttribute("height", height.toString());
|
||||
this.position();
|
||||
}
|
||||
|
||||
public setBrick(brick: BrickView) {
|
||||
this.brick = brick;
|
||||
this.position();
|
||||
}
|
||||
|
||||
public getBrick() {
|
||||
return this.brick;
|
||||
}
|
||||
|
||||
public setInput(port: number, child: LayoutElement) {
|
||||
if (this.inputs[port]) {
|
||||
// Remove current input
|
||||
this.inputs[port].dispose();
|
||||
}
|
||||
this.inputs[port] = child;
|
||||
this.position();
|
||||
}
|
||||
|
||||
public setOutput(port: number, child: LayoutElement) {
|
||||
if (this.outputs[port]) {
|
||||
// Remove current input
|
||||
this.outputs[port].dispose();
|
||||
}
|
||||
this.outputs[port] = child;
|
||||
this.position();
|
||||
}
|
||||
|
||||
public onClick(index: number, input: boolean, ev: any) {
|
||||
this.setSelected(index, input);
|
||||
}
|
||||
|
||||
public clearSelected() {
|
||||
this.selected = undefined;
|
||||
this.selectedIsInput = undefined;
|
||||
}
|
||||
|
||||
public setSelected(index: number, input?: boolean) {
|
||||
if (index !== this.selected || input !== this.selectedIsInput) {
|
||||
this.selected = index;
|
||||
this.selectedIsInput = input;
|
||||
const node = this.getSelected();
|
||||
if (node) node.setSelected(true);
|
||||
|
||||
//this.redoPositioning();
|
||||
runtime.queueDisplayUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public getSelected() {
|
||||
if (this.selected !== undefined) {
|
||||
return this.selectedIsInput ? this.inputs[this.selected] : this.outputs[this.selected];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected buildDom(width: number) {
|
||||
this.contentGroup = svg.elt("g") as SVGGElement;
|
||||
this.scrollGroup = svg.child(this.contentGroup, "g") as SVGGElement;
|
||||
return this.contentGroup;
|
||||
}
|
||||
|
||||
public getInnerWidth() {
|
||||
if (!this.hasDimensions) {
|
||||
return 0;
|
||||
}
|
||||
return this.width;
|
||||
}
|
||||
|
||||
public getInnerHeight() {
|
||||
if (!this.hasDimensions) {
|
||||
return 0;
|
||||
}
|
||||
return this.height;
|
||||
}
|
||||
|
||||
public updateTheme(theme: IBoardTheme) {
|
||||
this.inputs.forEach(n => {
|
||||
n.updateTheme(theme);
|
||||
})
|
||||
this.brick.updateTheme(theme);
|
||||
this.outputs.forEach(n => {
|
||||
n.updateTheme(theme);
|
||||
})
|
||||
}
|
||||
|
||||
private position() {
|
||||
if (!this.hasDimensions) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.offsets = [];
|
||||
|
||||
const selectedNode = this.getSelected();
|
||||
|
||||
const contentWidth = this.width || DEFAULT_WIDTH;
|
||||
const contentHeight = this.height || DEFAULT_HEIGHT;
|
||||
|
||||
const moduleHeight = this.getModuleHeight();
|
||||
|
||||
const brickHeight = this.getBrickHeight();
|
||||
this.brick.inject(this.scrollGroup);
|
||||
const brickWidth = this.brick.getInnerWidth() / this.brick.getInnerHeight() * brickHeight;
|
||||
const brickPadding = (contentWidth - brickWidth) / 2;
|
||||
|
||||
const modulePadding = contentWidth / 35;
|
||||
const moduleSpacing = contentWidth / 4;
|
||||
const moduleWidth = moduleSpacing - (modulePadding * 2);
|
||||
let currentX = modulePadding;
|
||||
let currentY = 0;
|
||||
this.outputs.forEach((n, i) => {
|
||||
const outputPadding = moduleWidth * n.getPaddingRatio();
|
||||
const outputWidth = moduleWidth - outputPadding * 2;
|
||||
n.inject(this.scrollGroup, outputWidth);
|
||||
n.resize(outputWidth);
|
||||
const nHeight = n.getHeight() / n.getWidth() * outputWidth;
|
||||
n.translate(currentX + outputPadding, currentY + moduleHeight - nHeight);
|
||||
n.setSelected(n == selectedNode);
|
||||
if (n.hasClick()) n.registerClick((ev: any) => {
|
||||
this.onClick(i, false, ev);
|
||||
})
|
||||
currentX += moduleSpacing;
|
||||
})
|
||||
|
||||
currentX = 0;
|
||||
currentY = moduleHeight;
|
||||
|
||||
const wireBrickSpacing = brickWidth / 5;
|
||||
const wiringYPadding = 10;
|
||||
let wireStartX = 0;
|
||||
let wireEndX = brickPadding + wireBrickSpacing;
|
||||
let wireEndY = currentY + this.getWiringHeight() + wiringYPadding;
|
||||
let wireStartY = currentY - wiringYPadding;
|
||||
|
||||
// Draw output lines
|
||||
for (let port = 0; port < DAL.NUM_OUTPUTS; port++) {
|
||||
if (!this.outputWires[port].isRendered()) this.outputWires[port].inject(this.scrollGroup);
|
||||
this.outputWires[port].updateDimensions(wireStartX + moduleSpacing * this.outputs[port].getWiringRatio(), wireStartY, wireEndX, wireEndY);
|
||||
this.outputWires[port].setSelected(this.outputs[port].getId() == NodeType.Port);
|
||||
wireStartX += moduleSpacing;
|
||||
wireEndX += wireBrickSpacing;
|
||||
}
|
||||
|
||||
currentX = brickPadding;
|
||||
currentY += this.getWiringHeight();
|
||||
|
||||
// Render the brick in the middle
|
||||
this.brick.resize(brickWidth);
|
||||
this.brick.translate(currentX, currentY);
|
||||
|
||||
currentX = modulePadding;
|
||||
currentY += brickHeight + this.getWiringHeight();
|
||||
|
||||
this.inputs.forEach((n, i) => {
|
||||
const inputPadding = moduleWidth * n.getPaddingRatio();
|
||||
const inputWidth = moduleWidth - inputPadding * 2;
|
||||
n.inject(this.scrollGroup, inputWidth);
|
||||
n.resize(inputWidth);
|
||||
n.translate(currentX + inputPadding, currentY);
|
||||
n.setSelected(n == selectedNode);
|
||||
if (n.hasClick()) n.registerClick((ev: any) => {
|
||||
this.onClick(i, true, ev);
|
||||
})
|
||||
currentX += moduleSpacing;
|
||||
})
|
||||
|
||||
wireStartX = moduleSpacing / 2;
|
||||
wireEndX = brickPadding + wireBrickSpacing;
|
||||
wireEndY = currentY - this.getWiringHeight() - wiringYPadding;
|
||||
wireStartY = currentY + wiringYPadding;
|
||||
|
||||
// Draw input lines
|
||||
for (let port = 0; port < DAL.NUM_INPUTS; port++) {
|
||||
if (!this.inputWires[port].isRendered()) this.inputWires[port].inject(this.scrollGroup);
|
||||
this.inputWires[port].updateDimensions(wireStartX, wireStartY, wireEndX, wireEndY);
|
||||
this.inputWires[port].setSelected(this.inputs[port].getId() == NodeType.Port);
|
||||
wireStartX += moduleSpacing;
|
||||
wireEndX += wireBrickSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
public getSelectedCoords() {
|
||||
const selected = this.getSelected();
|
||||
if (!selected) return undefined;
|
||||
const port = this.getSelected().getPort();
|
||||
return {
|
||||
x: this.getSelected().getPort() * this.width / 4 + this.width * MODULE_INNER_PADDING_RATIO,
|
||||
y: this.selectedIsInput ? this.getModuleHeight() + 2 * this.getWiringHeight() + this.getBrickHeight() : this.getModuleHeight() / 4
|
||||
}
|
||||
}
|
||||
|
||||
public getCloseIconCoords(closeIconWidth: number, closeIconHeight: number) {
|
||||
return {
|
||||
x: this.getSelected().getPort() * this.width / 4 + this.getModuleBounds().width / 2 - closeIconWidth / 2,
|
||||
y: this.selectedIsInput ? this.getModuleHeight() + 2 * this.getWiringHeight() + this.getBrickHeight() + this.getModuleHeight() - closeIconHeight : 0
|
||||
}
|
||||
}
|
||||
|
||||
public getModuleHeight() {
|
||||
return (this.height || DEFAULT_HEIGHT) * MODULE_HEIGHT_RATIO;
|
||||
}
|
||||
|
||||
public getBrickHeight() {
|
||||
return (this.height || DEFAULT_HEIGHT) * BRICK_HEIGHT_RATIO;
|
||||
}
|
||||
|
||||
public getWiringHeight() {
|
||||
return (this.height || DEFAULT_HEIGHT) * WIRING_HEIGHT_RATIO;
|
||||
}
|
||||
|
||||
public getModuleBounds() {
|
||||
return {
|
||||
width: this.width / 4,
|
||||
height: this.getModuleHeight()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
196
sim/visuals/nodes/brickView.ts
Normal file
@ -0,0 +1,196 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class BrickView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private static EV3_SCREEN_ID = "ev3_screen";
|
||||
private static EV3_LIGHT_ID = "btn_color";
|
||||
|
||||
private buttons: SVGElement[];
|
||||
private light: SVGElement;
|
||||
|
||||
private currentCanvasX = 178;
|
||||
private currentCanvasY = 128;
|
||||
|
||||
constructor(port: number) {
|
||||
super(EV3_SVG, "board", NodeType.Brick, port);
|
||||
}
|
||||
|
||||
protected buildDomCore() {
|
||||
// Setup buttons
|
||||
const btnids = ["btn_up", "btn_enter", "btn_down", "btn_right", "btn_left", "btn_back"];
|
||||
this.buttons = btnids.map(n => this.content.getElementById(this.normalizeId(n)) as SVGElement);
|
||||
this.buttons.forEach(b => svg.addClass(b, "sim-button"));
|
||||
|
||||
this.light = this.content.getElementById(this.normalizeId(BrickView.EV3_LIGHT_ID)) as SVGElement;
|
||||
}
|
||||
|
||||
private setStyleFill(svgId: string, fillUrl: string) {
|
||||
const el = (this.content.getElementById(svgId) as SVGRectElement);
|
||||
if (el) el.style.fill = `url("#${fillUrl}")`;
|
||||
}
|
||||
|
||||
public hasClick() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public shouldUpdateState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public updateState() {
|
||||
this.updateLight();
|
||||
}
|
||||
|
||||
public updateThemeCore() {
|
||||
let theme = this.theme;
|
||||
svg.fill(this.buttons[0], theme.buttonUps[0]);
|
||||
svg.fill(this.buttons[1], theme.buttonUps[1]);
|
||||
svg.fill(this.buttons[2], theme.buttonUps[2]);
|
||||
}
|
||||
|
||||
private lastLightPattern: number = -1;
|
||||
private lastLightAnimationId: any;
|
||||
private updateLight() {
|
||||
let state = ev3board().getBrickNode().lightState;
|
||||
|
||||
const lightPattern = state.lightPattern;
|
||||
if (lightPattern == this.lastLightPattern) return;
|
||||
this.lastLightPattern = lightPattern;
|
||||
if (this.lastLightAnimationId) cancelAnimationFrame(this.lastLightAnimationId);
|
||||
switch (lightPattern) {
|
||||
case 0: // LED_BLACK
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`));
|
||||
//svg.fill(this.light, "#FFF");
|
||||
break;
|
||||
case 1: // LED_GREEN
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-green`));
|
||||
//svg.fill(this.light, "#00ff00");
|
||||
break;
|
||||
case 2: // LED_RED
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-red`));
|
||||
//svg.fill(this.light, "#ff0000");
|
||||
break;
|
||||
case 3: // LED_ORANGE
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-orange`));
|
||||
//svg.fill(this.light, "#FFA500");
|
||||
break;
|
||||
case 4: // LED_GREEN_FLASH
|
||||
this.flashLightAnimation('green');
|
||||
break;
|
||||
case 5: // LED_RED_FLASH
|
||||
this.flashLightAnimation('red');
|
||||
break;
|
||||
case 6: // LED_ORANGE_FLASH
|
||||
this.flashLightAnimation('orange');
|
||||
break;
|
||||
case 7: // LED_GREEN_PULSE
|
||||
this.pulseLightAnimation('green');
|
||||
break;
|
||||
case 8: // LED_RED_PULSE
|
||||
this.pulseLightAnimation('red');
|
||||
break;
|
||||
case 9: // LED_ORANGE_PULSE
|
||||
this.pulseLightAnimation('orange');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private flashLightAnimation(id: string) {
|
||||
let fps = 3;
|
||||
let now;
|
||||
let then = Date.now();
|
||||
let interval = 1000 / fps;
|
||||
let delta;
|
||||
let that = this;
|
||||
function draw() {
|
||||
that.lastLightAnimationId = requestAnimationFrame(draw);
|
||||
now = Date.now();
|
||||
delta = now - then;
|
||||
if (delta > interval) {
|
||||
then = now - (delta % interval);
|
||||
that.flashLightAnimationStep(id);
|
||||
}
|
||||
}
|
||||
draw();
|
||||
}
|
||||
|
||||
private flash: boolean;
|
||||
private flashLightAnimationStep(id: string) {
|
||||
if (this.flash) {
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`));
|
||||
} else {
|
||||
this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`));
|
||||
}
|
||||
this.flash = !this.flash;
|
||||
}
|
||||
|
||||
|
||||
private pulseLightAnimation(id: string) {
|
||||
let fps = 8;
|
||||
let now;
|
||||
let then = Date.now();
|
||||
let interval = 1000 / fps;
|
||||
let delta;
|
||||
let that = this;
|
||||
function draw() {
|
||||
that.lastLightAnimationId = requestAnimationFrame(draw);
|
||||
now = Date.now();
|
||||
delta = now - then;
|
||||
if (delta > interval) {
|
||||
// update time stuffs
|
||||
then = now - (delta % interval);
|
||||
that.pulseLightAnimationStep(id);
|
||||
}
|
||||
}
|
||||
draw();
|
||||
}
|
||||
|
||||
private pulse: number = 0;
|
||||
private pulseLightAnimationStep(id: string) {
|
||||
switch (this.pulse) {
|
||||
case 0: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 1: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 2: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 3: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 4: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 5: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`)); break;
|
||||
case 6: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`)); break;
|
||||
case 7: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-black`)); break;
|
||||
case 8: this.setStyleFill(this.normalizeId(BrickView.EV3_LIGHT_ID), this.normalizeId(`linear-gradient-${id}`)); break;
|
||||
|
||||
}
|
||||
this.pulse++;
|
||||
if (this.pulse == 9) this.pulse = 0;
|
||||
}
|
||||
|
||||
public attachEvents() {
|
||||
let bpState = ev3board().getBrickNode().buttonState;
|
||||
let stateButtons = bpState.buttons;
|
||||
this.buttons.forEach((btn, index) => {
|
||||
let button = stateButtons[index];
|
||||
|
||||
btn.addEventListener(pointerEvents.down, ev => {
|
||||
button.setPressed(true);
|
||||
svg.fill(this.buttons[index], this.theme.buttonDown);
|
||||
})
|
||||
btn.addEventListener(pointerEvents.leave, ev => {
|
||||
button.setPressed(false);
|
||||
svg.fill(this.buttons[index], this.theme.buttonUps[index]);
|
||||
})
|
||||
btn.addEventListener(pointerEvents.up, ev => {
|
||||
button.setPressed(false);
|
||||
svg.fill(this.buttons[index], this.theme.buttonUps[index]);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public getScreenBBox() {
|
||||
if (!this.content) return undefined;
|
||||
const screen = this.content.getElementById(this.normalizeId(BrickView.EV3_SCREEN_ID));
|
||||
if (!screen) return undefined;
|
||||
return screen.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
}
|
16
sim/visuals/nodes/colorSensorView.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class ColorSensorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private control: ColorGridControl;
|
||||
|
||||
constructor(port: number) {
|
||||
super(COLOR_SENSOR_SVG, "color", NodeType.ColorSensor, port);
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 1 / 8;
|
||||
}
|
||||
}
|
||||
}
|
14
sim/visuals/nodes/gyroSensorView.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class GyroSensorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
constructor(port: number) {
|
||||
super(GYRO_SVG, "gyro", NodeType.GyroSensor, port);
|
||||
}
|
||||
|
||||
public getPaddingRatio() {
|
||||
return 1 / 4;
|
||||
}
|
||||
}
|
||||
}
|
62
sim/visuals/nodes/largeMotorView.ts
Normal file
@ -0,0 +1,62 @@
|
||||
/// <reference path="./staticView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class LargeMotorView extends StaticModuleView implements LayoutElement {
|
||||
|
||||
private static ROTATING_ECLIPSE_ID = "1eb2ae58-2419-47d4-86bf-4f26a7f0cf61";
|
||||
|
||||
private lastMotorAnimationId: any;
|
||||
|
||||
constructor(port: number) {
|
||||
super(LARGE_MOTOR_SVG, "large-motor", NodeType.LargeMotor, port);
|
||||
}
|
||||
|
||||
updateState() {
|
||||
const motorState = ev3board().getMotors()[this.port];
|
||||
if (!motorState) return;
|
||||
const speed = motorState.getSpeed();
|
||||
if (this.lastMotorAnimationId) cancelAnimationFrame(this.lastMotorAnimationId);
|
||||
|
||||
if (!speed) return;
|
||||
this.playMotorAnimation(motorState);
|
||||
}
|
||||
|
||||
private playMotorAnimation(state: MotorNode) {
|
||||
// Max medium motor RPM is 170 according to http://www.cs.scranton.edu/~bi/2015s-html/cs358/EV3-Motor-Guide.docx
|
||||
const rotationsPerMinute = 170; // 170 rpm at speed 100
|
||||
const rotationsPerSecond = rotationsPerMinute / 60;
|
||||
const fps = MOTOR_ROTATION_FPS;
|
||||
const rotationsPerFrame = rotationsPerSecond / fps;
|
||||
let now;
|
||||
let then = Date.now();
|
||||
let interval = 1000 / fps;
|
||||
let delta;
|
||||
let that = this;
|
||||
function draw() {
|
||||
that.lastMotorAnimationId = requestAnimationFrame(draw);
|
||||
now = Date.now();
|
||||
delta = now - then;
|
||||
if (delta > interval) {
|
||||
then = now - (delta % interval);
|
||||
that.playMotorAnimationStep(state.angle);
|
||||
const rotations = state.getSpeed() / 100 * rotationsPerFrame;
|
||||
const angle = rotations * 360;
|
||||
state.angle += angle;
|
||||
}
|
||||
}
|
||||
draw();
|
||||
}
|
||||
|
||||
private playMotorAnimationStep(angle: number) {
|
||||
const holeEl = this.content.getElementById(this.normalizeId(LargeMotorView.ROTATING_ECLIPSE_ID))
|
||||
const width = 34;
|
||||
const height = 34;
|
||||
const transform = `rotate(${angle} ${width / 2} ${height / 2})`;
|
||||
holeEl.setAttribute("transform", transform);
|
||||
}
|
||||
|
||||
getWiringRatio() {
|
||||
return 0.62;
|
||||
}
|
||||
}
|
||||
}
|