[Git] Fix conflicts

This commit is contained in:
Quentin
2020-03-27 21:16:47 +01:00
22 changed files with 281 additions and 211 deletions

View File

@@ -23,6 +23,7 @@ jobs:
submodules: true
- run: make -j2 MODEL=n0100 epsilon.dfu
- run: make -j2 MODEL=n0100 epsilon.onboarding.dfu
- run: make -j2 MODEL=n0100 epsilon.official.onboarding.dfu
- run: make -j2 MODEL=n0100 epsilon.onboarding.update.dfu
- run: make -j2 MODEL=n0100 epsilon.onboarding.beta.dfu
- run: make -j2 MODEL=n0100 flasher.light.dfu
@@ -42,6 +43,7 @@ jobs:
submodules: true
- run: make -j2 epsilon.dfu
- run: make -j2 epsilon.onboarding.dfu
- run: make -j2 epsilon.official.onboarding.dfu
- run: make -j2 epsilon.onboarding.update.dfu
- run: make -j2 epsilon.onboarding.beta.dfu
- run: make -j2 flasher.light.dfu
@@ -63,10 +65,11 @@ jobs:
with:
submodules: true
- run: make -j2 PLATFORM=simulator TARGET=web
- run: make -j2 PLATFORM=simulator TARGET=web epsilon.official.js
- uses: actions/upload-artifact@master
with:
name: epsilon-simulator-web.zip
path: output/release/simulator/web/simulator.zip
path: output/release/simulator/web/epsilon.zip
- run: make -j2 PLATFORM=simulator TARGET=web test.headless.js
build-simulator-linux:
runs-on: ubuntu-latest

View File

@@ -21,9 +21,6 @@ OMEGA_THEME ?= omega_light
ifndef USE_LIBA
$(error platform.mak should define USE_LIBA)
endif
ifndef EXE
$(error platform.mak should define EXE, the extension for executables)
endif
include build/toolchain.$(TOOLCHAIN).mak
SFLAGS += -DDEBUG=$(DEBUG)

View File

@@ -1,8 +1,10 @@
TOOLCHAIN = android
EXE = so
EPSILON_TELEMETRY ?= 1
ifdef NDK_ABI
BUILD_DIR := $(BUILD_DIR)/$(NDK_ABI)
ARCHS = armeabi-v7a arm64-v8a x86 x86_64
ifdef ARCH
EXE = so
BUILD_DIR := $(BUILD_DIR)/$(ARCH)
endif

View File

@@ -1,8 +1,15 @@
# Define standard compilation rules
.PHONY: official_authorization
ifeq ($(ACCEPT_OFFICIAL_TOS),1)
official_authorization:
@echo "CAUTION: You are about to build an official NumWorks firmware. Distribution of such firmware by a third party is prohibited. Are you sure you want to proceed? Please type "yes" to confirm." && read ans && [ $${ans:-no} = yes ]
else
official_authorization:
@echo "CAUTION: You are trying to build an official NumWorks firmware."
@echo "Distribution of such firmware by a third party is prohibited."
@echo "Please set the ACCEPT_OFFICIAL_TOS environment variable to proceed."
@exit -1
endif
$(eval $(call rule_for, \
AS, %.o, %.s, \
@@ -31,6 +38,12 @@ $(eval $(call rule_for, \
$$(CXX) $$(CXXFLAGS) $$(SFLAGS) -c $$< -o $$@ \
))
$(eval $(call rule_for, \
CPP, %, %.inc, \
$$(CPP) -P $$< $$@ \
))
ifdef EXE
ifeq ($(OS),Windows_NT)
# Work around command-line length limit
# On Msys2 the max command line is 32 000 characters. Our standard LD command
@@ -47,6 +60,7 @@ $(eval $(call rule_for, \
$$(LD) $$^ $$(LDFLAGS) -o $$@ \
))
endif
endif
$(eval $(call rule_for, \
WINDRES, %.o, %.rc, \

View File

@@ -40,18 +40,16 @@ all_official:
$(Q) $(MAKE) MODEL=n0100 epsilon.official.onboarding.dfu
$(Q) cp output/release/device/n0100/epsilon.official.onboarding.dfu output/all_official/epsilon.device.n0100.dfu
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB ZIP"
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web output/release/simulator/web/simulator.official.zip
$(Q) cp output/release/simulator/web/simulator.official.zip output/all_official/simulator.web.zip
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.zip
$(Q) cp output/release/simulator/web/epsilon.official.zip output/all_official/simulator.web.zip
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB JS"
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web epsilon.official.js
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web epsilon.official.js
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.js
$(Q) cp output/release/simulator/web/epsilon.official.js.mem output/all_official/epsilon.js.mem
$(Q) echo "BUILD_FIRMWARE SIMULATOR WEB PYTHON JS"
$(Q) $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) DEBUG=0 PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
$(Q) $(MAKE) PLATFORM=simulator TARGET=web clean
$(Q) $(call source_emsdk); $(MAKE) PLATFORM=simulator TARGET=web EPSILON_GETOPT=1 EPSILON_APPS=code epsilon.official.js
$(Q) cp output/release/simulator/web/epsilon.official.js output/all_official/epsilon.python.js
$(Q) cp output/release/simulator/web/epsilon.official.js.mem output/all_official/epsilon.python.js.mem
$(Q) echo "BUILD_FIRMWARE SIMULATOR ANDROID"
$(Q) $(MAKE) PLATFORM=simulator TARGET=android clean
$(Q) $(MAKE) PLATFORM=simulator TARGET=android epsilon.official.signed.apk

View File

@@ -0,0 +1,3 @@
ifndef ARCH
HANDY_TARGETS_EXTENSIONS += apk
endif

View File

@@ -1,6 +1,3 @@
$(BUILD_DIR)/epsilon%packed.js: EMSCRIPTEN_INIT_FILE = 0
HANDY_TARGETS_EXTENSIONS += zip
$(BUILD_DIR)/test.headless.js: EMSCRIPTEN_MODULARIZE = 0
$(BUILD_DIR)/epsilon.packed.js: $(call object_for,$(epsilon_src))
$(BUILD_DIR)/epsilon.official.packed.js: $(call object_for,$(epsilon_official_src))

View File

@@ -13,16 +13,16 @@ NDK_TOOLCHAIN_PATH = $(NDK_PATH)/toolchains/llvm/prebuilt/$(NDK_HOST_TAG)/bin
# is no toolchain for those archs on those API levels. Let's enforce NDK_VERSION
# at 21 for these archs, and 16 for the others.
ifeq ($(NDK_ABI),armeabi-v7a)
ifeq ($(ARCH),armeabi-v7a)
NDK_TARGET = armv7a-linux-androideabi
NDK_VERSION = 16
else ifeq ($(NDK_ABI),arm64-v8a)
else ifeq ($(ARCH),arm64-v8a)
NDK_TARGET = aarch64-linux-android
NDK_VERSION = 21
else ifeq ($(NDK_ABI),x86)
else ifeq ($(ARCH),x86)
NDK_TARGET = i686-linux-android
NDK_VERSION = 16
else ifeq ($(NDK_ABI),x86_64)
else ifeq ($(ARCH),x86_64)
NDK_TARGET = x86_64-linux-android
NDK_VERSION = 21
endif

View File

@@ -1,6 +1,7 @@
CC = emcc
CXX = emcc
LD = emcc
CPP = cpp
EMSCRIPTEN_ASYNC_SYMBOLS = \
SAFE_HEAP_LOAD \
@@ -120,20 +121,9 @@ endif
# Configure EMFLAGS
EMFLAGS += -s WASM=0
# Since emcc 1.39.5, DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR is defautly
# to 1 which discards old looks up to find DOM elements. However SDL relies on
# the presence of a target "#canvas" that used to return the Module['canvas']
# target but not anymore. It also expects the existence of Module['canvas'].
# Until we fix the DOM of the html calling epsilon module, we use the deprecated
# 'find_event_target'.
# TODO: fix DOM of htmls files that uses epsilon js module
EMFLAGS += -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0
# Configure LDFLAGS
EMSCRIPTEN_MODULARIZE ?= 1
LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"'
EMSCRIPTEN_INIT_FILE ?= 1
LDFLAGS += --memory-init-file $(EMSCRIPTEN_INIT_FILE)
LDFLAGS += -s MODULARIZE=$(EMSCRIPTEN_MODULARIZE) -s 'EXPORT_NAME="Epsilon"' --memory-init-file 0
SFLAGS += $(EMFLAGS)
LDFLAGS += $(EMFLAGS) -Oz -s EXPORTED_FUNCTIONS='["_main", "_IonSimulatorKeyboardKeyDown", "_IonSimulatorKeyboardKeyUp", "_IonSimulatorEventsPushEvent", "_IonSoftwareVersion", "_IonPatchLevel", "_IonDisplayForceRefresh"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='["UTF8ToString"]'

View File

@@ -1,8 +1,5 @@
#include <escher/run_loop.h>
#include <assert.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
RunLoop::RunLoop() :
m_time(0) {

View File

@@ -11,6 +11,12 @@ $(call object_for,ion/src/simulator/shared/main.cpp) : SFLAGS += -DEPSILON_SDL_F
LDFLAGS += -ljnigraphics -llog
# If ARCH is not defined, we will re-trigger a build for each avaialble ARCH.
# This is used to build APKs, which needs to embbed a binary for each ARCH.
ifndef ARCH
# Android resources
# Some android resources needs to be filtered through ImageMagick. Others are
# simply copied over.
@@ -27,56 +33,50 @@ $(BUILD_DIR)/app/res/%.xml: ion/src/simulator/android/src/res/%.xml | $$(@D)/.
$(call rule_label,COPY)
$(Q) cp $< $@
# Cross-ABI libepsilon.so
# This file is loaded is loaded only once, which prevents us from tracking
# dependencies across ABIs. As a shortcut, we simply force a re-make of
# libepsilon.so for each ABI.
# This rule allow us to build any executable (%) for a specified ARCH ($1)
# We depend on a phony target to make sure this rule is always executed
.PHONY: force_remake
define rule_for_libepsilon
$$(BUILD_DIR)/app/libs/%/lib$(1): force_remake $$$$(@D)/.
$(Q) echo "MAKE NDK_ABI=$$*"
$(Q) $$(MAKE) NDK_ABI=$$* $(1)
$(Q) cp $$(BUILD_DIR)/$$*/$(1) $$@
define rule_for_arch_executable
.PRECIOUS: $$(BUILD_DIR)/$(1)/%.so
$$(BUILD_DIR)/$(1)/%.so: force_remake
$(Q) echo "MAKE ARCH=$(1) $$*.so"
$(Q) $$(MAKE) ARCH=$(1) --silent $$*.so
endef
$(eval $(call rule_for_libepsilon,epsilon.so))
$(eval $(call rule_for_libepsilon,epsilon.official.so))
# We need to put the .so files somewhere Gradle can pick them up.
# We decided to use the location "app/libs/$EXECUTABLE/$ARCH/libepsilon.so"
# This way it's easy to import the shared object from Java code (it's always
# named libepsilon.so), and it's easy to make Gradle use a given executable by
# simply using the jniLibs.src directive.
define path_for_arch_jni_lib
$$(BUILD_DIR)/app/libs/%/$(1)/libepsilon.so
endef
# If NDK_ABI is not defined, we will re-trigger a build for each avaialble ABI.
# This is used to build APKs, which needs to embbed a binary for each ABI.
define rule_for_arch_jni_lib
$(call path_for_arch_jni_lib,$(1)): $$(BUILD_DIR)/$(1)/%.so | $$$$(@D)/.
$(Q) cp $$< $$@
endef
ifndef NDK_ABI
$(foreach ARCH,$(ARCHS),$(eval $(call rule_for_arch_executable,$(ARCH))))
$(foreach ARCH,$(ARCHS),$(eval $(call rule_for_arch_jni_lib,$(ARCH))))
NDK_ABIS = armeabi-v7a arm64-v8a x86 x86_64
apk_deps = $(foreach ARCH,$(ARCHS),$(call path_for_arch_jni_lib,$(ARCH)))
apk_deps += $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*))
apk_deps += $(addprefix $(BUILD_DIR)/app/res/,mipmap/ic_launcher.png mipmap-v26/ic_launcher_foreground.png)
epsilon_apk_deps = $(subst ion/src/simulator/android/src/res,$(BUILD_DIR)/app/res,$(wildcard ion/src/simulator/android/src/res/*/*))
epsilon_apk_deps += $(addprefix $(BUILD_DIR)/app/res/,mipmap/ic_launcher.png mipmap-v26/ic_launcher_foreground.png)
.PRECIOUS: $(apk_deps)
define rule_for_gradle
.PHONY: gradle_$1_$2
gradle_$1_$2: $$(epsilon_apk_deps) $$(patsubst %,$$(BUILD_DIR)/app/libs/%/libepsilon$2so,$(NDK_ABIS))
$(BUILD_DIR)/%.apk: $(apk_deps)
@echo "GRADLE ion/src/simulator/android/build.gradle"
$(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle $1
endef
$(eval $(call rule_for_gradle,assembleCodesigned,.))
$(eval $(call rule_for_gradle,assembleRelease,.))
$(eval $(call rule_for_gradle,assembleCodesigned,.official.))
$(eval $(call rule_for_gradle,assembleRelease,.official.))
$(Q) ANDROID_HOME=$(ANDROID_HOME) EPSILON_VERSION=$(EPSILON_VERSION) BUILD_DIR=$(BUILD_DIR) EPSILON_VARIANT=$* ion/src/simulator/android/gradlew -b ion/src/simulator/android/build.gradle assembleRelease
$(Q) cp $(BUILD_DIR)/app/outputs/apk/release/android-release*.apk $@
DEFAULT = epsilon.apk
.PHONY: epsilon%signed.apk
epsilon%signed.apk: gradle_assembleCodesigned_%
$(warning This is a signed build.)
.PHONY: epsilon%apk
epsilon%apk: gradle_assembleRelease_%
$(warning Building without code signing. Build epsilon$*signed.apk to generate a signed version.)
.PHONY: epsilon_run
epsilon_run: gradle_installDebug
.PHONY: %_run
%_run: $(BUILD_DIR)/%.apk
@echo "ADB $*.apk"
$(Q) adb install $<
endif

View File

@@ -53,10 +53,9 @@ android {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt')
}
codesigned {
initWith buildTypes.release
signingConfig signingConfigs.environment
if (projectVariable('SIGNING_STORE_FILE')) {
signingConfig signingConfigs.environment
}
}
}
sourceSets{
@@ -64,12 +63,13 @@ android {
manifest.srcFile 'src/AndroidManifest.xml'
res.srcDir BUILD_DIR + '/res'
java.srcDir 'src'
jniLibs.srcDir BUILD_DIR + '/libs'
jniLibs.srcDir BUILD_DIR + '/libs/' + System.getenv('EPSILON_VARIANT')
assets.srcDir '../assets'
}
}
lintOptions {
abortOnError false
checkReleaseBuilds false
}
}

View File

@@ -10,6 +10,9 @@ SFLAGS += -Iion/src/simulator/web/include
# Only render the screen, not the whole calculator which will be drawn in HTML
SFLAGS += -DEPSILON_SDL_SCREEN_ONLY=1
# Enable to set environment variables for a module
LDFLAGS += --pre-js ion/src/simulator/web/preamble_env.js
ion_src += $(addprefix ion/src/simulator/web/, \
callback.cpp \
helpers.cpp \
@@ -24,14 +27,14 @@ ion_src += ion/src/simulator/shared/dummy/telemetry_init.cpp
ion_src += ion/src/shared/telemetry_console.cpp
endif
DEFAULT = $(BUILD_DIR)/simulator.zip
DEFAULT = epsilon.zip
$(BUILD_DIR)/simulator%zip: $(BUILD_DIR)/epsilon%packed.js
$(BUILD_DIR)/epsilon%zip: $(BUILD_DIR)/epsilon%js $(BUILD_DIR)/ion/src/simulator/web/simulator.html
@rm -rf $(basename $@)
@mkdir -p $(basename $@)
@cp $^ $(basename $@)/epsilon.js
@cp $< $(basename $@)/epsilon.js
@cp ion/src/simulator/assets/background.jpg $(basename $@)/
@cp ion/src/simulator/web/simulator.html $(basename $@)/
@cp $(BUILD_DIR)/ion/src/simulator/web/simulator.html $(basename $@)/
$(call rule_label,ZIP)
@zip -r -9 -j $@ $(basename $@) > /dev/null
@rm -rf $(basename $@)

View File

@@ -0,0 +1,21 @@
/* Use:
*
* var options = {
canvas: ...,
env: {
VARIABLE_NAME: VARIABLE_VALUE
}
};
Epsilon(options);
*
* Cf https://github.com/emscripten-core/emscripten/issues/9827
* */
Module["preRun"] = function () {
if (Module['env'] && typeof Module['env'] === 'object') {
for (var key in Module['env']) {
if (Module['env'].hasOwnProperty(key))
ENV[key] = Module['env'][key];
}
}
}

View File

@@ -0,0 +1,54 @@
<div id="keyboard">
<div class="nav">
<span class="left" data-key="0"></span>
<span class="top" data-key="1"></span>
<span class="bottom" data-key="2"></span>
<span class="right" data-key="3"></span>
<span class="ok" data-key="4"></span>
<span class="back" data-key="5"></span>
<span class="home" data-key="6"></span>
<span class="power" data-key="7"></span>
</div>
<div class="functions">
<span data-key="12"></span>
<span data-key="13"></span>
<span data-key="14"></span>
<span data-key="15"></span>
<span data-key="16"></span>
<span data-key="17"></span>
<span data-key="18"></span>
<span data-key="19"></span>
<span data-key="20"></span>
<span data-key="21"></span>
<span data-key="22"></span>
<span data-key="23"></span>
<span data-key="24"></span>
<span data-key="25"></span>
<span data-key="26"></span>
<span data-key="27"></span>
<span data-key="28"></span>
<span data-key="29"></span>
</div>
<div class="digits">
<span data-key="30"></span>
<span data-key="31"></span>
<span data-key="32"></span>
<span data-key="33"></span>
<span data-key="34"></span>
<span data-key="36"></span>
<span data-key="37"></span>
<span data-key="38"></span>
<span data-key="39"></span>
<span data-key="40"></span>
<span data-key="42"></span>
<span data-key="43"></span>
<span data-key="44"></span>
<span data-key="45"></span>
<span data-key="46"></span>
<span data-key="48"></span>
<span data-key="49"></span>
<span data-key="50"></span>
<span data-key="51"></span>
<span data-key="52"></span>
</div>
</div>

View File

@@ -0,0 +1,65 @@
/* To use this file you should adhere to the following conventions:
* - Main canvas has id #canvas
* - Secondary canvas (fullscreen on the side) has id #secondary-canvas
* - Calculator keyboard has id #keyboard */
var Module;
(function () {
var mainCanvas = document.getElementById('canvas');
var secondaryCanvasContext = document.getElementById('secondary-canvas').getContext('2d');
var epsilonLanguage = document.documentElement.lang || window.navigator.language.split('-')[0];
Module = {
canvas: mainCanvas,
arguments: ['--language', epsilonLanguage],
onDisplayRefresh: function() {
secondaryCanvasContext.drawImage(mainCanvas, 0, 0);
}
}
Epsilon(Module);
document.querySelectorAll('#keyboard span').forEach(function(span){
function eventHandler(keyHandler) {
return function(ev) {
var key = this.getAttribute('data-key');
keyHandler(key);
/* Always prevent default action of event.
* First, this will prevent the browser from delaying that event. Indeed
* the browser would otherwise try to see if that event could have any
* other meaning (e.g. a click) and might delay it as a result.
* Second, this prevents touch events to be handled twice. Indeed, for
* backward compatibility reasons, mobile browsers usually create a fake
* mouse event after each real touch event. This allows desktop websites
* to work unmodified on mobile devices. But here we are explicitly
* handling both touch and mouse events. We therefore need to disable
* the default action of touch events, otherwise the handler would get
* called twice. */
ev.preventDefault();
};
}
/* We decide to hook both to touch and mouse events
* On most mobile browsers, mouse events are generated if addition to touch
* events, so this could seem pointless. But those mouse events are not
* generated in real time: instead, they are buffered and eventually fired
* in a very rapid sequence. This prevents Epsilon from generating an event
* since this quick sequence will trigger the debouncer. */
['touchstart', 'mousedown'].forEach(function(type){
span.addEventListener(type, eventHandler(Module._IonSimulatorKeyboardKeyDown));
});
['touchend', 'mouseup'].forEach(function(type){
span.addEventListener(type, eventHandler(Module._IonSimulatorKeyboardKeyUp));
});
});
}());
function screenshot() {
// toDataURL needs the canvas to be refreshed
Module._IonDisplayForceRefresh();
var canvas = document.getElementById('canvas');
var link = document.createElement('a');
link.download = 'screenshot.png';
link.href = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
link.click();
}

View File

@@ -1,3 +1,5 @@
#define KEYBOARD #keyboard
<!DOCTYPE html>
<html>
<head>
@@ -65,7 +67,7 @@ a.action svg {
max-height: 92.0vh;
max-width: 100%;
display: block; }
.calculator .screen {
.calculator #canvas {
position: absolute;
top: 8.5%;
left: 16.25%;
@@ -84,84 +86,84 @@ a.action svg {
display: inline-block;
margin-right: 10px;
}
.calculator .keyboard {
KEYBOARD {
position: absolute;
top: 38.5%;
left: 10%;
width: 81%;
bottom: 5%; }
.calculator .keyboard span {
KEYBOARD span {
cursor: pointer;
border-radius: 40%;
display: block;
float: left; }
.calculator .keyboard span:hover {
KEYBOARD span:hover {
background-color: rgba(0, 0, 0, 0.1); }
.calculator .keyboard span:active {
KEYBOARD span:active {
background-color: rgba(0, 0, 0, 0.2); }
.calculator .keyboard .nav {
KEYBOARD .nav {
position: absolute;
top: 0;
height: 27%;
width: 100%; }
.calculator .keyboard .nav span {
KEYBOARD .nav span {
position: absolute; }
.calculator .keyboard .nav .left {
KEYBOARD .nav .left {
top: 36%;
left: 2%;
width: 15%;
height: 28%; }
.calculator .keyboard .nav .right {
KEYBOARD .nav .right {
top: 36%;
left: 17%;
width: 15%;
height: 28%; }
.calculator .keyboard .nav .top {
KEYBOARD .nav .top {
top: 7%;
left: 12%;
width: 10%;
height: 40%; }
.calculator .keyboard .nav .bottom {
KEYBOARD .nav .bottom {
top: 53%;
left: 12%;
width: 10%;
height: 40%; }
.calculator .keyboard .nav .home {
KEYBOARD .nav .home {
top: 15%;
left: 41%;
width: 16%;
height: 33%; }
.calculator .keyboard .nav .power {
KEYBOARD .nav .power {
top: 54%;
left: 42%;
width: 16%;
height: 33%; }
.calculator .keyboard .nav .ok {
KEYBOARD .nav .ok {
top: 31%;
left: 67%;
width: 13%;
height: 38%; }
.calculator .keyboard .nav .back {
KEYBOARD .nav .back {
top: 31%;
left: 84%;
width: 13%;
height: 38%; }
.calculator .keyboard .functions {
KEYBOARD .functions {
position: absolute;
top: 26.75%;
left: 0.5%;
width: 98%; }
.calculator .keyboard .functions span {
KEYBOARD .functions span {
margin: 1.7% 1%;
width: 14.65%;
height: 0;
padding-top: 10%; }
.calculator .keyboard .digits {
KEYBOARD .digits {
position: absolute;
top: 56.5%;
left: 0.5%;
width: 98%; }
.calculator .keyboard .digits span {
KEYBOARD .digits span {
margin: 1.8% 2%;
width: 16%;
height: 0;
@@ -173,61 +175,8 @@ a.action svg {
<div class="col-calculator">
<div class="calculator">
<img src="background.jpg" alt="NumWorks Calculator">
<canvas id="screen" class="screen" oncontextmenu="event.preventDefault()"></canvas>
<div class="keyboard">
<div class="nav">
<span class="left" data-key="0"></span>
<span class="top" data-key="1"></span>
<span class="bottom" data-key="2"></span>
<span class="right" data-key="3"></span>
<span class="ok" data-key="4"></span>
<span class="back" data-key="5"></span>
<span class="home" data-key="6"></span>
<span class="power" data-key="7"></span>
</div>
<div class="functions">
<span data-key="12"></span>
<span data-key="13"></span>
<span data-key="14"></span>
<span data-key="15"></span>
<span data-key="16"></span>
<span data-key="17"></span>
<span data-key="18"></span>
<span data-key="19"></span>
<span data-key="20"></span>
<span data-key="21"></span>
<span data-key="22"></span>
<span data-key="23"></span>
<span data-key="24"></span>
<span data-key="25"></span>
<span data-key="26"></span>
<span data-key="27"></span>
<span data-key="28"></span>
<span data-key="29"></span>
</div>
<div class="digits">
<span data-key="30"></span>
<span data-key="31"></span>
<span data-key="32"></span>
<span data-key="33"></span>
<span data-key="34"></span>
<span data-key="36"></span>
<span data-key="37"></span>
<span data-key="38"></span>
<span data-key="39"></span>
<span data-key="40"></span>
<span data-key="42"></span>
<span data-key="43"></span>
<span data-key="44"></span>
<span data-key="45"></span>
<span data-key="46"></span>
<span data-key="48"></span>
<span data-key="49"></span>
<span data-key="50"></span>
<span data-key="51"></span>
<span data-key="52"></span>
</div>
</div>
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
#include "simulator-keyboard.html"
<div class="actions">
<a id="action-fullscreen" class="action">
<svg viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g fill="#434343"><path d="M5.075,6.95 L6.918,5.088 L3.938,2.062 L5.955,0.018 L0.052,0.018 L0.052,6.004 L2.098,3.928 L5.075,6.95 Z" class="si-glyph-fill"></path><path d="M16.0034788,9.916 L13.832,12.013 L10.799,8.96 L8.918,10.841 L11.957,13.897 L9.961,15.9813842 L16.0034788,15.9813842 L16.0034788,9.916 Z"></path></g></g></svg>
@@ -239,46 +188,14 @@ a.action svg {
</div>
</div>
<div class="col-fullscreen">
<canvas class="screen-magnified" width="320" height="240"></canvas>
<canvas id="secondary-canvas" width="320" height="240"></canvas>
</div>
</div>
<script src="epsilon.js"></script>
<script>
var mainCanvas = document.querySelector(".calculator .screen");
var secondaryCanvasContext = document.querySelector(".screen-magnified").getContext("2d");
var Module = {
arguments: ["--language", window.navigator.language.split('-')[0]],
canvas: mainCanvas,
onDisplayRefresh: function() {
secondaryCanvasContext.drawImage(mainCanvas, 0, 0);
}
};
Epsilon(Module);
#include "simulator-setup.js"
</script>
<script>
function screenshot() {
<!--toDataURL needs the canvas to be refreshed-->
Module._IonDisplayForceRefresh();
var canvas = document.querySelector('.screen');
var link = document.createElement('a');
link.download = 'screenshot.png';
link.href = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
link.click();
}
var spans = document.querySelectorAll(".calculator .keyboard span");
for (var i=0; i< spans.length; i++) {
var span = spans[i];
span.addEventListener("mousedown", function(e) {
Module._IonSimulatorKeyboardKeyDown(this.getAttribute("data-key"));
});
span.addEventListener("mouseup", function(e) {
Module._IonSimulatorKeyboardKeyUp(this.getAttribute("data-key"));
});
}
document.getElementById("action-fullscreen").addEventListener("click", function(e){
if (document.body.className == "fullscreen") {
document.body.className = "";

View File

@@ -10,7 +10,7 @@ namespace Poincare {
namespace ApproximationHelper {
template <typename T> int PositiveIntegerApproximationIfPossible(const ExpressionNode * expression, bool * isUndefined, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
template <typename T> std::complex<T> NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2 = 1.0);
template <typename T> std::complex<T> NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2 = 1.0, bool enableNullResult = true);
template <typename T> using ComplexCompute = Complex<T>(*)(const std::complex<T>, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
template<typename T> Evaluation<T> Map(const ExpressionNode * expression, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit, ComplexCompute<T> compute);

View File

@@ -37,7 +37,7 @@ template <typename T> int ApproximationHelper::PositiveIntegerApproximationIfPos
return absInt((int)scalar);
}
template <typename T> std::complex<T> ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2) {
template <typename T> std::complex<T> ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(std::complex<T> result, std::complex<T> input1, std::complex<T> input2, bool enableNullResult) {
/* Cheat: openbsd functions (cos, sin, tan, cosh, acos, pow...) are
* numerical implementation and thus are approximative.
* The error epsilon is ~1E-7 on float and ~1E-15 on double. In order to avoid
@@ -47,6 +47,9 @@ template <typename T> std::complex<T> ApproximationHelper::NeglectRealOrImaginar
* sin(1E-15)=1E-15.
* We can't do that for all evaluation as the user can operate on values as
* small as 1E-308 (in double) and most results still be correct. */
if (!enableNullResult && (result.imag() == 0.0 || result.real() == 0.0)) {
return result;
}
T magnitude1 = minimalNonNullMagnitudeOfParts(input1);
T magnitude2 = minimalNonNullMagnitudeOfParts(input2);
T precision = 10.0*Expression::Epsilon<T>();
@@ -126,8 +129,8 @@ template<typename T> MatrixComplex<T> ApproximationHelper::ElementWiseOnComplexM
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<float>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template int Poincare::ApproximationHelper::PositiveIntegerApproximationIfPossible<double>(Poincare::ExpressionNode const*, bool*, Poincare::Context*, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit);
template std::complex<float> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<float>(std::complex<float>,std::complex<float>,std::complex<float>);
template std::complex<double> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<double>(std::complex<double>,std::complex<double>,std::complex<double>);
template std::complex<float> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<float>(std::complex<float>,std::complex<float>,std::complex<float>,bool);
template std::complex<double> Poincare::ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable<double>(std::complex<double>,std::complex<double>,std::complex<double>,bool);
template Poincare::Evaluation<float> Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute<float> compute);
template Poincare::Evaluation<double> Poincare::ApproximationHelper::Map(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexCompute<double> compute);
template Poincare::Evaluation<float> Poincare::ApproximationHelper::MapReduce(const Poincare::ExpressionNode * expression, Poincare::Context * context, Poincare::Preferences::ComplexFormat, Poincare::Preferences::AngleUnit angleUnit, Poincare::ApproximationHelper::ComplexAndComplexReduction<float> computeOnComplexes, Poincare::ApproximationHelper::ComplexAndMatrixReduction<float> computeOnComplexAndMatrix, Poincare::ApproximationHelper::MatrixAndComplexReduction<float> computeOnMatrixAndComplex, Poincare::ApproximationHelper::MatrixAndMatrixReduction<float> computeOnMatrices);

View File

@@ -321,18 +321,22 @@ void Expression::defaultDeepReduceChildren(ExpressionNode::ReductionContext redu
Expression Expression::defaultShallowReduce() {
Expression result;
const int childrenCount = numberOfChildren();
for (int i = 0; i < childrenCount; i++) {
/* The reduction is shortcut if one child is unreal or undefined:
* - the result is unreal if at least one child is unreal
* - the result is undefined if at least one child is undefined but no child
* is unreal */
ExpressionNode::Type childIType = childAtIndex(i).type();
if (childIType == ExpressionNode::Type::Unreal) {
result = Unreal::Builder();
break;
} else if (childIType == ExpressionNode::Type::Undefined) {
result = Undefined::Builder();
if (sSimplificationHasBeenInterrupted) {
result = Undefined::Builder();
} else {
const int childrenCount = numberOfChildren();
for (int i = 0; i < childrenCount; i++) {
/* The reduction is shortcut if one child is unreal or undefined:
* - the result is unreal if at least one child is unreal
* - the result is undefined if at least one child is undefined but no child
* is unreal */
ExpressionNode::Type childIType = childAtIndex(i).type();
if (childIType == ExpressionNode::Type::Unreal) {
result = Unreal::Builder();
break;
} else if (childIType == ExpressionNode::Type::Undefined) {
result = Undefined::Builder();
}
}
}
if (!result.isUninitialized()) {

View File

@@ -183,7 +183,7 @@ Complex<T> PowerNode::compute(const std::complex<T> c, const std::complex<T> d,
* so arg(c^d) = y*ln(r)+xθ.
* We consider that arg[π] is negligeable if it is negligeable compared to
* norm(d) = sqrt(x^2+y^2) and ln(r) = ln(norm(c)).*/
return Complex<T>::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c, d));
return Complex<T>::Builder(ApproximationHelper::NeglectRealOrImaginaryPartIfNeglectable(result, c, d, false));
}
// Layout

View File

@@ -1317,6 +1317,8 @@ QUIZ_CASE(poincare_simplification_mix) {
//assert_parsed_expression_simplify_to("log(cos(9)^ln(6), 9)", "ln(6)×log(cos(9), 9)"); // TODO: for this to work, we must know the sign of cos(9)
assert_parsed_expression_simplify_to("(((√(6)-√(2))/4)/((√(6)+√(2))/4))+1", "-√(3)+3");
assert_parsed_expression_simplify_to("1/√(𝐢) × (√(2)-𝐢×√(2))", "-2×𝐢"); // TODO: get rid of complex at denominator?
assert_expression_simplifies_approximates_to<double>("abs(√(300000.0003^23))", "9.7027409010183ᴇ62");
}
QUIZ_CASE(poincare_hyperbolic_trigonometry) {