Skip to content

Instantly share code, notes, and snippets.

@zhanghai
Last active September 7, 2023 01:18
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zhanghai/4ae88f5afae4c353c0a30c0c6595efe5 to your computer and use it in GitHub Desktop.
Save zhanghai/4ae88f5afae4c353c0a30c0c6595efe5 to your computer and use it in GitHub Desktop.
A Gjs application for computation in an optical system comprising multiple spherical refracting surfaces
#!/usr/bin/gjs
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
function compute(surfaces, objectDistance, maxObjectAngle, objectHeight) {
const k = surfaces.length;
const r = surfaces.map(function (surface) { return surface.radius });
const n = [surfaces[0].reflectionOrDistanceLeft].concat(surfaces.map(function (surface) { return surface.reflectionRight }));
const d = surfaces.slice(1).map(function (surface) { return surface.reflectionOrDistanceLeft });
const ll = [objectDistance], lr = [];
let u = maxObjectAngle;
let h = objectHeight;
let beta = 1;
for (let i = 0; i < k; ++i) {
const temp = (n[i + 1] - n[i]) / r[i] + n[i] / ll[i];
if (temp == 0) {
return '无穷大';
}
lr[i] = n[i + 1] / ((n[i + 1] - n[i]) / r[i] + n[i] / ll[i]);
ll[i + 1] = lr[i] - d[i];
beta = beta * n[i] * lr[i] / n[i+1] / ll[i];
}
h = beta * h;
u = n[0] * u / beta / n[k];
return '相方倾角 u = ' + u + '\n' +
'横向放大率 β = ' + beta + '\n' +
'最后一面至像的距离 l = ' + lr[k - 1] + '\n' +
'像高 h = ' + h;
}
const OpticalSystem = new Lang.Class({
Name: 'Optical System',
_init: function() {
this.application = new Gtk.Application();
this.application.connect('startup', Lang.bind(this, this._onStartup));
this.application.connect('activate', Lang.bind(this, this._onActivate));
},
_onStartup: function () {
this._buildUi();
},
_onActivate: function() {
this._window.present();
},
_buildUi: function() {
this._window = new Gtk.ApplicationWindow({
application: this.application,
title: '多个折射球面构成光学系统的近轴计算',
default_width: 640,
default_height: 360,
window_position: Gtk.WindowPosition.CENTER
});
const rootGrid = new Gtk.Grid({
expand: true,
orientation: Gtk.Orientation.VERTICAL,
});
const dataWindow = new Gtk.ScrolledWindow();
const dataGrid = new Gtk.Grid({
vexpand: true,
border_width: 16,
orientation: Gtk.Orientation.VERTICAL,
row_spacing: 8
});
const surfaceListLabel = new Gtk.Label({
halign: Gtk.Align.START,
label: '折射球面:'
});
dataGrid.add(surfaceListLabel);
this._surfaceListGrid = new Gtk.Grid({
orientation: Gtk.Orientation.VERTICAL,
row_spacing: 8
});
dataGrid.add(this._surfaceListGrid);
this._onAddSurface();
const addSurfaceButton = new Gtk.Button({
hexpand: true,
label: '+'
});
addSurfaceButton.connect('clicked', Lang.bind(this, this._onAddSurface));
dataGrid.add(addSurfaceButton);
const objectGrid = new Gtk.Grid({
column_homogeneous: true,
column_spacing: 16
});
const objectDistanceGrid = new Gtk.Grid({
column_spacing: 8
});
objectDistanceGrid.add(new Gtk.Label({
label: '物距 -l:'
}));
this._objectDistanceEntry = this._makeNumberEntry('mm');
objectDistanceGrid.add(this._objectDistanceEntry);
objectGrid.add(objectDistanceGrid);
const maxObjectAngleGrid = new Gtk.Grid({
column_spacing: 8
});
maxObjectAngleGrid.add(new Gtk.Label({
label: '最大物方倾角 u:'
}));
this._maxObjectAngleEntry = this._makeNumberEntry('°');
maxObjectAngleGrid.add(this._maxObjectAngleEntry);
objectGrid.add(maxObjectAngleGrid);
const objectHeightGrid = new Gtk.Grid({
column_spacing: 8
});
objectHeightGrid.add(new Gtk.Label({
label: '物高 h:'
}));
this._objectHeightEntry = this._makeNumberEntry('mm');
objectHeightGrid.add(this._objectHeightEntry);
objectGrid.add(objectHeightGrid);
dataGrid.add(objectGrid);
dataWindow.add(dataGrid);
rootGrid.add(dataWindow);
const computeGrid = new Gtk.Grid({
border_width: 16,
orientation: Gtk.Orientation.VERTICAL,
row_spacing: 8
});
const computeButton = new Gtk.Button({
hexpand: true,
label: '计算'
})
computeButton.get_style_context().add_class('suggested-action');
computeButton.connect('clicked', Lang.bind(this, this._onCompute));
computeButton.set_can_default(true);
computeGrid.add(computeButton);
rootGrid.add(computeGrid);
this._window.add(rootGrid);
this._window.show_all();
computeButton.grab_default();
},
_onAddSurface: function() {
const surfaceGrid = new Gtk.Grid({
column_spacing: 8
})
surfaceGrid.add(this._makeNumberEntry(this._surfaceListGrid.get_children().length === 0 ? '左侧折射率 n1' : '间距 d'));
surfaceGrid.add(this._makeNumberEntry('球面半径 r'));
surfaceGrid.add(this._makeNumberEntry('右侧折射率 n2'));
const removeButton = new Gtk.Button({
label: '移除',
sensitive: this._surfaceListGrid.get_children().length !== 0
})
removeButton.connect('clicked', Lang.bind(this, function() {
this._surfaceListGrid.remove(surfaceGrid);
}));
surfaceGrid.add(removeButton);
this._surfaceListGrid.add(surfaceGrid);
surfaceGrid.show_all();
},
_makeNumberEntry: function(placeholder) {
const entry = new Gtk.Entry({
hexpand: true,
input_purpose: Gtk.InputPurpose.NUMBER,
placeholder_text: placeholder,
width_chars: 4
});
entry.connect('activate', Lang.bind(this, this._onCompute));
return entry;
},
_onCompute: function() {
const surfaces = [];
const surfaceListGridChildren = this._surfaceListGrid.get_children();
for (let i = surfaceListGridChildren.length - 1; i >= 0; --i) {
const surfaceGridChildren = surfaceListGridChildren[i].get_children();
const index = surfaceListGridChildren.length - i;
const reflectionOrDistanceLeft = this._getEntryFloat(surfaceGridChildren[3], '第 ' + index + ' 个球面' + (index === 1 ? '左侧折射率' : '间距') + '无效');
if (!reflectionOrDistanceLeft) {
return;
}
const radius = this._getEntryFloat(surfaceGridChildren[2], '第 ' + index + ' 个球面半径无效');
if (!radius) {
return;
}
const reflectionRight = this._getEntryFloat(surfaceGridChildren[1], '第 ' + index + ' 个球面右侧折射率无效');
if (!reflectionRight) {
return;
}
surfaces.push({
reflectionOrDistanceLeft: reflectionOrDistanceLeft,
radius: radius,
reflectionRight: reflectionRight
});
}
const objectDistance = this._getEntryFloat(this._objectDistanceEntry, '物距无效');
if (!objectDistance) {
return;
}
const maxObjectAngle = this._getEntryFloat(this._maxObjectAngleEntry, '最大物方倾角无效');
if (!maxObjectAngle) {
return;
}
const objectHeight = this._getEntryFloat(this._objectHeightEntry, '物高无效');
if (!objectHeight) {
return;
}
this._showResult(null, compute(surfaces, objectDistance, maxObjectAngle, objectHeight));
},
_getEntryFloat: function(entry, error) {
const value = parseFloat(entry.get_text());
if (!value) {
this._showResult(error, null);
entry.grab_focus();
}
return value;
},
_showResult: function(error, result) {
const dialog = new Gtk.MessageDialog({
transient_for: this._window,
modal: true,
message_type: error ? Gtk.MessageType.ERROR : Gtk.MessageType.INFO,
text: error ? '错误' : '计算结果',
secondary_text: error || result,
buttons: Gtk.ButtonsType.OK
})
dialog.run()
dialog.destroy()
}
});
const app = new OpticalSystem();
app.application.run(ARGV);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment