/*
* Copyright 2024 The Ray Optics Simulation authors and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import BaseSceneObj from '../BaseSceneObj.js';
import LineObjMixin from '../LineObjMixin.js';
import i18next from 'i18next';
/**
* The ruler tool
*
* Tools -> Other -> Ruler
* @class
* @extends BaseSceneObj
* @memberof sceneObjs
* @property {Point} p1 - The first endpoint of the line segment.
* @property {Point} p2 - The second endpoint of the line segment.
* @property {number} scaleInterval - The scale interval of the ruler.
*/
class Ruler extends LineObjMixin(BaseSceneObj) {
static type = 'Ruler';
static serializableDefaults = {
p1: null,
p2: null,
scaleInterval: 10
};
populateObjBar(objBar) {
objBar.setTitle(i18next.t('main:tools.Ruler.title'));
objBar.createNumber(i18next.t('simulator:sceneObjs.Ruler.scaleInterval'), 0, 10, 1, this.scaleInterval, function (obj, value) {
obj.scaleInterval = value;
}, i18next.t('simulator:sceneObjs.common.lengthUnitInfo'), true);
}
draw(canvasRenderer, isAboveLight, isHovered) {
if (isAboveLight) return;
const ctx = canvasRenderer.ctx;
const ls = canvasRenderer.lengthScale;
if (this.p1.x == this.p2.x && this.p1.y == this.p2.y) {
ctx.fillStyle = 'rgb(128,128,128)';
ctx.fillRect(this.p1.x - 1.5 * ls, this.p1.y - 1.5 * ls, 3 * ls, 3 * ls);
return;
}
ctx.globalCompositeOperation = 'lighter';
var len = Math.sqrt((this.p2.x - this.p1.x) * (this.p2.x - this.p1.x) + (this.p2.y - this.p1.y) * (this.p2.y - this.p1.y));
var par_x = (this.p2.x - this.p1.x) / len;
var par_y = (this.p2.y - this.p1.y) / len;
var per_x = par_y;
var per_y = -par_x;
var ang = Math.atan2(this.p2.y - this.p1.y, this.p2.x - this.p1.x);
var scale_step = this.scaleInterval;
var scale_step_mid = scale_step * 5;
var scale_step_long = scale_step * 10;
var scale_len = 10 * ls;
var scale_len_mid = 15 * ls;
ctx.strokeStyle = isHovered ? 'cyan' : ('rgb(128,128,128)');
ctx.font = (14 * ls) + 'px Arial';
ctx.fillStyle = 'rgb(128,128,128)';
if (ang > Math.PI * (-0.25) && ang <= Math.PI * 0.25) {
//↘~↗
var scale_direction = -1;
var scale_len_long = 20 * ls;
var text_ang = ang;
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
} else if (ang > Math.PI * (-0.75) && ang <= Math.PI * (-0.25)) {
//↗~↖
var scale_direction = 1;
var scale_len_long = 15 * ls;
var text_ang = ang - Math.PI * (-0.5);
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
} else if (ang > Math.PI * 0.75 || ang <= Math.PI * (-0.75)) {
//↖~↙
var scale_direction = 1;
var scale_len_long = 20 * ls;
var text_ang = ang - Math.PI;
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
} else {
//↙~↘
var scale_direction = -1;
var scale_len_long = 15 * ls;
var text_ang = ang - Math.PI * 0.5;
ctx.textAlign = 'right';
ctx.textBaseline = 'middle';
}
ctx.lineWidth = 1 * ls;
ctx.beginPath();
ctx.moveTo(this.p1.x, this.p1.y);
ctx.lineTo(this.p2.x, this.p2.y);
var x, y;
for (var i = 0; i <= len; i += scale_step) {
ctx.moveTo(this.p1.x + i * par_x, this.p1.y + i * par_y);
if (i % scale_step_long == 0) {
x = this.p1.x + i * par_x + scale_direction * scale_len_long * per_x;
y = this.p1.y + i * par_y + scale_direction * scale_len_long * per_y;
ctx.lineTo(x, y);
if (canvasRenderer.isSVG) ctx.stroke();
ctx.save();
ctx.translate(x, y);
ctx.rotate(text_ang);
ctx.fillText(i, 0, 0);
ctx.restore();
} else if (i % scale_step_mid == 0) {
ctx.lineTo(this.p1.x + i * par_x + scale_direction * scale_len_mid * per_x, this.p1.y + i * par_y + scale_direction * scale_len_mid * per_y);
} else {
ctx.lineTo(this.p1.x + i * par_x + scale_direction * scale_len * per_x, this.p1.y + i * par_y + scale_direction * scale_len * per_y);
}
}
ctx.stroke();
ctx.globalCompositeOperation = 'source-over';
}
};
export default Ruler;