友图自动排料引擎 V1.0 开发指南
完整版本 :
https://download.csdn.net/download/nestingChina/12156799
价格
永久加密狗 15000元 两年内免费升级; 推广期八折; 可申请一个月试用RMB 200 + 加密狗100(试用期后不满意可以加密狗换回加密狗硬件费用)
联系 18917360310 (官网建设中, 2020年4月后可访问 www.yotutech.com获取更多信息)
Benchmark
CPU: AMD 2700
OS : Windows 10 64bit
NestFab(Ultra) 八线程 YotuNester(极致版) 四线程
Pieces |
NestFab |
YotuNester |
|||
R0 |
R0/R180 |
R0 |
R0/R180 |
||
Shape0 |
43 |
67.63% |
74.12% |
68.79% |
76.73% |
swim |
48 |
74.32% |
78.18% |
74.09% |
78.19% |
shirt |
99 |
86.01% |
88.63% |
87.79% |
89.62% |
trouser |
64 |
86.12% |
91.51% |
87.46% |
92.28% |
Average |
78.52% |
83.11% |
79.53 |
84.205% |
|
Improved |
+1.01% |
+1.095% |
附 Nestfab 参考价格
Nestfab是英国顶级排料软件,利用率与shapeshifter/autonester/Gemini在同一级别
对应人民币 永久 约 34879元; 年付费 约 8719元/年
----------------- 正文 -----------------------
友图自动排料引擎 V1.0 YotuNester Engine V1.0 开发指南 上海友图科技有限公司2020.01发布 |
免责声明
我们力求使本文档准确、完善,但无法保证其绝对完美。如果我们发现了不清晰、疏漏甚至错误,我们将尽力在产品的后续版本中将其更正。对于因为本文档内容的不准确或疏漏造成的任何直接或间接损害或业务损失,上海友图科技有限公司不负责任。
2020年1月
版权所有 © 2020 上海友图科技有限公司 保留所有权利
开发套件详单:
头文件 yotu_global.h yotu.h
链接库 yotu.dll 默认使用微软VS编译器编译(可选 Mingw/Gcc版本)
使用VS编译器将采用win32线程,
使用Mingw/Gcc编译器将采用pthread线程
加密狗
默认工作平台 windows7/10 (Linux可选)
本文所用术语解释
样片 待排放的形状,衣片或零件统称为样片
材料 样片放入其中的容器,对应于服装行业的面料,钣金行业的板材,当前版本材料形状为矩形
材料高度 对应于服装行业的面料宽度或钣金行业的材料宽度
材料长度 可以指定材料长度为固定值,不指定时材料长度为无限长
样片间距 排放入材料后样片之间的最小间距
材料间距 排放入材料和样片与材料边缘的距离
自动排料引擎简介
排料是指以节省材料为主要目标,把若干样片不重叠地放置进材料的平面空间。评估自动排料引擎最直接的指标就是材料利用率(以下简称利用率)。
自动排料引擎通常是指自动排料的核心算法,封装成可调用库形式,供CAD软件商二次开发使用.
目前世界上最顶级的自动排料引擎分别有AutoNester,Gemini,ShapeShifter,NestFab. 中国本土的自动排料引擎在商业应用上尚未出现或距离以上几家指标相差甚远。上海友图科技有限公司开发的友图自动排料引擎(YotuNester Engine)是唯一能在利用率指标上比肩世界顶级自动排料引擎的厂商。并在小规模排料上对比目前顶级排料引擎有较明显优势。
友图自动排料引擎主创人员拥有十六年几何图形算法以及CAD/EDA行业开发经验,经过近十年的技术积累与探索,友图自动排料引擎于2020年1月正式发布。
YotuNester采用C++编程语言实现,为方便不同语言调用,接口采用C风格。
目录
第一部分 基本数据结构
第二部分 调用流程
- 数据准备
- 启动搜索
- 获取结果
- 终止运行
附录 Benchmark;接口头文件清单
第一部分 基本数据结构
Point2F 点结构,记录浮点数2D坐标
struct Point2F
{
double X;
double Y;
};
数据精度: 小数点后3位有效.
例如
Point2F (123.4567, 987.65432) 会被截断为 Point2F (123.456, 987.654)。
数据范围: -640000.000 ~ 640000.000
在数据范围允许的情况下,可以通过放大源数据以提高数据精度。
例如 上述点可以乘以 100 (需要对所有坐标做相同转换)成为:
Point2F(12345.67, 98765.432)
然后输入引擎计算,得到的结果除以100,将会是没有误差(重叠)的结果.
如果源数据小数点后没有超过3位,就不需要考虑精度问题.
Polygon2F 多边形结构,记录多边形的所有点,首尾点无需重合
struct Polygon2F
{
Point2F* pts;
unsigned size;
};
多边形必须为简单多边形,简单多边形指多边形的任意两条非相邻边不相交。
UserShape 样片数据及排料信息
struct UserShape
{
unsigned idType;
unsigned tran;
unsigned flipX;
unsigned flipY;
unsigned quantity;
Polygon2F ring;
};
每种样片都需要一个唯一标识的idType,建议从0开始递增。tran标识允许的变换角度。允许变换的角度有四类,分别是:
YT_TR_KIND_0
YT_TR_KIND_180
YT_TR_KIND_90
YT_TR_KIND_ANY
当前版本 YT_TR_KIND_ANY 不可用,如想获得接近任意角度的效果,请使用
YT_TR_KIND_90.
前三类变换角度下可以使用的旋转角度分别为
YT_TR_KIND_0 (YT_R0)
YT_TR_KIND_180 (YT_R0, YT_R180)
YT_TR_KIND_90 (YT_R0, YT_R90, YT_180, YT_270)
flipX标识是否可以沿X轴翻转,1为允许,0为不允许
flipY标识是否可以沿Y轴翻转,1为允许,0为不允许
以下表格为不同变换角度和翻转条件下的具体变换:
(请注意区分变换角度YT_TR_KIND_XXX与具体变换YT_Rxxx/YT_Fxxx)
不同变换角度和翻转条件下的具体变换 |
flipX == 0 flipY == 0 |
flipX == 1 flipY == 0 |
flipX == 0 flipY == 1 |
flipX == 1 flipY == 1 |
YT_TR_KIND_0 |
YT_R0 |
YT_R0 YT_FX |
YT_R0 YT_FY |
YT_R0 YT_FX YT_FY YT_180 |
YT_TR_KIND_180 |
YT_R0 YT_R180 |
YT_R0 YT_FX YT_FY YT_R180 |
YT_R0 YT_FX YT_FY YT_R180 |
YT_R0 YT_FX YT_FY YT_R180 |
YT_TR_KIND_90 |
YT_R0 YT_R90 YT_R180 YT_R270 |
YT_R0 YT_R90 YT_R180 YT_R270 YT_FX YT_FY YT_R90_FX YT_R90_FY |
YT_R0 YT_R90 YT_R180 YT_R270 YT_FX YT_FY YT_R90_FX YT_R90_FY |
YT_R0 YT_R90 YT_R180 YT_R270 YT_FX YT_FY YT_R90_FX YT_R90_FY |
quantity 标识该类样片的数量。
相同形状的样片请按idType归类。样片是否相同需要参考可变换角度。
例如形状A与B不相同,在A和B都使用YT_TR_KIND_180变换角度时,如果A旋转180度和B形状相同,那么A和B可视为同类样片。其余角度类推。
ring标识样片多边形数据。
UserSources 存放所有的源样片信息
struct UserSources
{
UserShape* shapes;
unsigned size;
};
shapes所有的源样片种类集合,size为样片种类的个数。
*** 需要注意的是:源数据的内存分配 shapes以及Polygon2F中的pts都需要调用者自行管理,在调用前分配,运行结束后释放。
UserPlacement保存每个样片的排样结果
struct UserPlacement
{
unsigned idType;
unsigned idGrp;
unsigned idTran;
unsigned idSheet;
Point2F pos;
};
排样结果不会包含任何源样片形状数据,只包含该样片放置的位置和对应的具体变换。
idType为源样片类型的标识,idGrp为源样片的序号即源样片的第几个实例。例如源样片3:idType的quantity为5,那么idGrp为0~4. 如下图所示
idType 为2的形状共8个,这八个分别对应下图标号 2-0, 2-1, 2-2, … , 2-7
idTran 样片的具体变换, 取YT_R0, … YT_R90_FX,…
idSheet标识所在的材料序号中,即在第几块材料中
pos 标识样片(外包矩形)的中心所在的位置
UserSolution保存完整排料结果
struct UserSolution
{
unsigned shapeSize;
unsigned sheetSize;
UserPlacement* placements;
Point2F lbOfMat;
double widthOfMat;
double lengthOfMat;
double lastLengthOfMat;
double utilization;
};
shapeSize 所有的样片个数
sheetSize 存放所需材料的个数,在不固定材料长度的情况始终为1
placements 存放所有的样片排料结果
lbOfMat 材料的左下角坐标
widthOfMat 材料的宽度(高度)
lengthOfMat 材料的长度,如果最终只需要一块材料(即sheetSize为1),请使用lastLengthOfMat
lastLengthOfMat 对于固定材料长度的情况,有可能最终排料结果使用多块材料,它保存最后一块材料的长度
utilization 材料(总)利用率.对于多块材料的情况下单块材料的利用率,请使用材料尺寸自行计算
由于每个样片的排样结果(UserPlacement)中包含idSheet信息,所以可以每
个样片按照idSheet分类,以便计算和显示每个材料的具体排料结果信息。
第二部分 调用流程
- 数据准备
以shape0为例
UserSources usrc;
unsigned id_counts = 0;
usrc.size = 4;
usrc.shapes = new UserShape[usrc.size];
usrc.shapes[0].idType = id_counts++;
usrc.shapes[0].tran = YT_TR_KIND_180;
usrc.shapes[0].flipX = 0;
usrc.shapes[0].flipY = 0;
usrc.shapes[0].quantity = 7;
usrc.shapes[0].ring.size = 4;
usrc.shapes[0].ring.pts = new Point2F[4];
usrc.shapes[0].ring.pts[0].X = …
usrc.shapes[0].ring.pts[0].Y = …
…
usrc.shapes[1].idType = id_counts++;
…
usrc.shapes[1].ring.pts = new Point2F[12];
…
调用yt_init初始化
yt_init声明解释如下
extern "C" LIBYOTU_EXPORT unsigned
yt_init(const UserSources* source,
double height, //材料宽度(高度)
double length, //材料长度(不限长则传入-1)
double space_piece, //样片间距
double space_mat); //材料间距
调用代码:
unsigned rt = yt_init(&usrc, 40, -1, 0, 0);
返回值错误判断与处理
if (YT_NONE_ERROR != rt)
{
if(YT_IN_PROCESS_ERROR == rt)
cout << "In Process!" << endl; //已经在进程中,只允许一个进程
else if(YT_WIDTH_ERROR == rt)
cout << "Width Error!" << endl;//指定的材料宽度小于样片的宽度(高度)
else if(YT_DOG_ERROR == rt)
cout << "Dog Error!" << endl; //没有检测到加密狗或已过有效期
else if(YT_IN_PROGRESS_ERROR == rt)
cout << "In Progress!" << endl;//当前正在运行
else
cout << "Unknown Error!" << endl;//未知错误
return false;
}
如果调用yt_init正常返回之后未调用yt_close关闭引擎(无论是否运行yt_run),再次调用yt_init将会返回YT_IN_PROGRESS_ERROR. 需调用yt_close关闭引擎(提前终止运行则需要先调用yt_stop,再使用yt_close关闭引擎),才能再次调用yt_init初始化.
当前版本只允许一个进程运行,同时运行多个进程将返回YT_IN_PROCESS_ERROR.
yt_init是阻塞调用,必须等到yt_init返回才能调用其它接口函数.
yt_init耗费时间与样片种类和样片形状的复杂度直接相关,通常情况下,1百种(不是100个)样片,支持180度旋转,样片平均顶点数约100时,函数耗时在1~2秒(4核).
这种情况下如果支持90度旋转,yt_init耗时将会呈指数增长,所以不建议同时使用数百种样片、使用90度变换角度,并且顶点数最好控制在100以内。但是引擎并不会限制样片顶点数和样片种类个数。
大量实验表明(不仅限于YotuNester,对于其它的排料引擎也是如此),在有限时间(几个小时)内,把几百个样片按100-150个分组分别运行,得到的结果比几百个样片同时计算的结果更好。 理论上几百个样片同时排放会比分组排放利用率更好,但是代价是需要耗费不成比例的时间。
- 启动搜索
yt_run声明与解释
extern "C" LIBYOTU_EXPORT void
yt_run(unsigned threads_number, //启动线程数量
unsigned run_seconds, //运行时间
unsigned random_base = 0);
由于绝大多数优化算法都会使用随机数,本引擎也不例外. 每个线程都会使用不同的随机数进行计算,正常情况下每次计算的结果都是可以复现的. 大部分情况下并不需要参数random_base,
调用示例:
yt_run(4, 600); //启动4线程,运行时间为600秒
如果对结果不满意,可以尝试使用random_base更换随机数种子.
random_base 为0的情况下每个线程的随机数种子分别是 0, 1, … threads_number -1.
设定了random_base后每个线程的随机数种子为:
random_base, random_base+1, … random_base + threads_number – 1
更换随机数种子并不能保证一定带来利用率提升,只是提供提升利用率的可能.
正常情况下,传入相同的random_base,运行的结果也是可以复现的,所以如果使用该参数,请在排料结果中记录该值,以便可以复现。
当前版本下,各线程的计算是相互独立的,也就是说多线程并不会让程序运行更快,只是因为不同线程的利用率不同,获得更高利用率的可能性更高。
该函数是非阻塞式,调用之后立即返回,耗时可以忽略.
为提高性能,后续版本中多线程独立运算的方式可能会进行改进.
- 获取结果
extern "C" LIBYOTU_EXPORT bool
yt_query_solution(UserSolution* sln);
该函数需要传入UserSolution的实例指针,在调用该函数前需要按样片个数预先分配好空间,并设置UserSolution.utilization为0。
以shape0为例
Shape0有四种样片
第一种 7个; 第二种 12个; 第三种 9 个; 第四种 15个
总计 43个
因此需要为UserSolution.placements指针分配43个UserPlacement结构的大小空间
调用示例:
UserSolution usln;
usln.utilization = 0;
usln.placements = new UserPlacement[43];
bool result = yt_query_solution(&usln);
yt_query_solution函数会通过UserSolution.utilization和引擎计算的利用率对比,如果引擎计算的利用率更高,则会把最新的结果写入usln,否则不会修改usln. 返回值为true时说明结果更新了。保持usln在其它的情况下只读是最好的选择。
usln中保存了每个样片的类型信息和排放位置以及具体变换,调用方可以根据这些信息生成用户可理解的文件或者图形界面信息。
建议定时调用yt_query_solution以查看是否结果更新,更新频率不宜大于1次/秒,频繁查询结果对性能影响微乎其微,但是却并非必要。
- 终止运行
无论程序运行是由于时间限制自然结束还是提前终止都需要调用yt_close来清理资源
调用yt_close只是清理资源,并不会提前终止引擎。
extern "C" LIBYOTU_EXPORT int
yt_close();
yt_close采用安全设计,无论何时调用都不会有负面效应。
当返回值为0时,表示引擎运行已经终止并且资源已经清理,如果返回1则表示当前正在运行.
需要提前终止运行需要调用yt_stop
extern "C" LIBYOTU_EXPORT void
yt_stop();
该函数会发出终止信号,调用yt_stop之后需调用yt_close以确认引擎是否结束并且资源已经清理。一般情况下引擎在收到终止信号后会很快终止运行,但是当样片种类和数量很多时,引擎终止可能会需要数秒时间,所以安全的确认引擎终止的方式是一直调用yt_close直到它返回0为止(这也是运行新的排料计算的前提)。
示例:
yt_stop(); //按照运行时间限制自然结束的不必调用yt_stop
while(yt_close())
{
//sleep or do anything else
}
cout << “engine closed”<< endl;
引擎非正常结束除了调用yt_stop主动终止外,还有一种可能是加密狗在运行过程中被拔出,引擎在启动和运行时会随机检测加密狗是否存在和有效,一旦检测到加密狗不存在或者无效会立即终止。 所以最好在查询结果前调用yt_close确认引擎是否结束。
附录
测试数据使用YotuNester V1.0版本
Benchmark
CPU: AMD 2700
OS : Windows 10 64bit
NestFab 八线程 YotuNester 四线程
Pieces |
NestFab |
YotuNester |
|||
R0 |
R0/R180 |
R0 |
R0/R180 |
||
Shape0 |
43 |
67.63% |
74.12% |
68.79% |
76.73% |
swim |
48 |
74.32% |
78.18% |
74.09% |
78.19% |
shirt |
99 |
86.01% |
88.63% |
87.79% |
89.62% |
trouser |
64 |
86.12% |
91.51% |
87.46% |
92.28% |
Average |
78.52% |
83.11% |
79.53 |
84.205% |
|
Improved |
+1.01% |
+1.095% |
头文件清单
yotu_global.h
/****************************************************************************
**
** Copyright (C) 2020 The YotuTech Company Ltd.
** Contact: 18917360310
**
** yotu_global.h: basic data structure of yotu-nester.
** Date: 2020-01-31
** Author: Youlin
** Version: 1.0
****************************************************************************/
#ifndef LIBYOTU_GLOBAL_H
#define LIBYOTU_GLOBAL_H
// Return Code
const unsigned YT_NONE_ERROR = 0;
const unsigned YT_DOG_ERROR = 1;
const unsigned YT_WIDTH_ERROR = 2;
const unsigned YT_IN_PROCESS_ERROR = 4;
const unsigned YT_IN_PROGRESS_ERROR = 5;
const unsigned YT_UNKNOW_ERROR = 9;
// Transform Detail
const unsigned YT_R0 = 0;
const unsigned YT_R180 = 1;
const unsigned YT_FX = 2;
const unsigned YT_FY = 3;
const unsigned YT_R90 = 4;
const unsigned YT_R270 = 5;
const unsigned YT_R90_FX = 6;
const unsigned YT_R90_FY = 7;
// Transform Setting
const unsigned YT_TR_KIND_0 = 0;
const unsigned YT_TR_KIND_180 = 1;
const unsigned YT_TR_KIND_90 = 2;
const unsigned YT_TR_KIND_ANY = 3;
struct Point2F
{
double X;
double Y;
};
struct Polygon2F
{
Point2F* pts;
unsigned size;
};
struct Line2F
{
Point2F start;
Point2F end;
};
struct Box2F
{
double left;
double right;
double bottom;
double top;
};
struct UserShape
{
unsigned idType;
unsigned tran;
unsigned flipX;
unsigned flipY;
unsigned quantity;
Polygon2F ring;
};
struct UserSources
{
UserShape* shapes;
unsigned size;
};
struct UserPlacement
{
unsigned idType;
unsigned idGrp;
unsigned idTran;
unsigned idSheet;
Point2F pos;
};
struct UserSolution
{
unsigned shapeSize;
unsigned sheetSize;
UserPlacement* placements;
Point2F lbOfMat;
double widthOfMat;
double lengthOfMat;
double lastLengthOfMat;
double utilization;
};
#endif // LIBYOTU_GLOBAL_H
.
yotu.h
/****************************************************************************
**
** Copyright (C) 2020 The YotuTech Company Ltd.
** Contact: 18917360310
**
** yotu.h: interface of yotu-nester.
** Date: 2020-01-31
** Author: Youlin
** Version: 1.0
****************************************************************************/
#ifndef LIBYOTU_H
#define LIBYOTU_H
#include "yotu_global.h"
#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
#else
# define Q_DECL_EXPORT __attribute__((visibility("default")))
# define Q_DECL_IMPORT __attribute__((visibility("default")))
#endif
#if defined(YOTU_LIBRARY)
# define LIBYOTU_EXPORT Q_DECL_EXPORT
#else
# define LIBYOTU_EXPORT Q_DECL_IMPORT
#endif
extern "C" LIBYOTU_EXPORT bool
yt_query_solution(UserSolution* sln);
extern "C" LIBYOTU_EXPORT unsigned
yt_init(const UserSources* source, double height, double length, double space_piece, double space_mat);
extern "C" LIBYOTU_EXPORT void
yt_run(unsigned threads_number, unsigned run_seconds, unsigned random_base = 0);
extern "C" LIBYOTU_EXPORT void
yt_stop();
extern "C" LIBYOTU_EXPORT int
yt_close();
#endif // LIBYOTU_H
友图自动排料引擎 V1.0 开发指南相关推荐
- 【Unity 框架】QFramework v1.0 使用指南 介绍篇:01. 简介 | Unity 游戏框架 | Unity 游戏开发 | Unity 独立游戏
01. 简介 大家好,我是 QFramework 的作者 凉鞋,QFramework 从第一次代码提交到现在快 7 年了(2015 年 12 月 ~ 2022 年 10 月)了,而经过了 7 年时间的 ...
- SteamVR2.0开发指南(Yanlz+Unity+SteamVR+Plugin+OpenVR+InputSystem+Kunckles+VIVE+Oculus+OpenXR+立钻哥哥++ok++)
<SteamVR2.0开发指南> 版本 作者 参与者 完成日期 备注 SteamVR2.0_Guide_V01_1.0 严立钻 2019.01.23 ++++SteamVR2.0开发指南: ...
- SteamVR2.0开发指南
2019年02月14日 22:21:19 VRunSoftYanlz 阅读数:562 <SteamVR2.0开发指南> 版本 作者 参与者 完成日期 备注 SteamVR2.0_Guide ...
- 按键游侠脚本引擎 v1.0 免费下载--IT man
Csdn-Blog <script language="javascript" src="http://www.023rcsc.com/count/count2.a ...
- OAuth2.0学习(2-1)Spring Security OAuth2.0 开发指南
开发指南:http://www.cnblogs.com/xingxueliao/p/5911292.html Spring OAuth2.0 提供者实现原理: Spring OAuth2.0提供者实际 ...
- Web项目实战 | 购物系统v1.0 | 开发记录(一) | 大学生闲置物品交易系统 | 选择页面模板(附资源),使用 JQuery AJAX实现注册、登陆
文章目录 运行环境 1. 前言 2. 挑选模板 2.1 前端模板 2.2 后端模板 2.3 总结 3. 实现注册与登陆 3.1 项目结构 3.2 注册 3.2.1 JDBC连接池连接 3.2.2 da ...
- 魔众图床系统 v1.0.0 简单的私有化图床系统
魔众图床系统可以快速帮助可以搭建一个私有化图床系统,支持阿里云.腾讯云等各大云存储平台 魔众图床系统发布v1.0.0版本,新功能和Bug修复累计1项,简单的私有化图床系统. 2022年02月08日魔众 ...
- 【Unity 框架】QFramework v1.0 使用指南 工具篇:06. UIKit 界面管理快速开发解决方案 | Unity 游戏框架 | Unity 游戏开发 | Unity 独立游戏
UI Kit 简介 UI Kit 是一套界面管理&快速开发解决方案 UI Kit 的特性如下: 界面管理 层级管理 代码生成及组件自动绑定(底层用的 ViewController) UI Ki ...
- 【Unity 框架】QFramework v1.0 使用指南 架构篇:11. 光速实现 EditorCounterApp 和 给主程看的开发模式 | Unity 游戏框架 | Unity 游戏开发
首先,我们来实现一个好玩的事情,就是在前边已经实现好的 CounterApp 的基础上,光速实现一个编辑器版本的 CounterApp. 代码非常简单,如下: #if UNITY_EDITOR usi ...
- apollo local 模式_Java客户端使用指南 - 五、本地开发模式 - 《携程 Apollo v1.4 开发指南》 - 书栈网 · BookStack...
五.本地开发模式 Apollo客户端还支持本地开发模式,这个主要用于当开发环境无法连接Apollo服务器的时候,比如在邮轮.飞机上做相关功能开发. 在本地开发模式下,Apollo只会从本地文件读取配置 ...
最新文章
- JavaScript 异步编程--Generator函数、async、await
- 当自动驾驶汽车撞过来的时候,你希望它如何判断?
- Py之requests:python的requests包的简介、安装、使用方法详细攻略
- 如何正确理解近似点梯度下降算法
- 利用Android Studio快速搭建App
- List,Map,实体类,字符串相互转换
- 连 CEO 都不香了?这些互联网大佬接连辞任
- LINUX中,有的软件编译时configure的prefix参数无效
- x61 linux 驱动下载,ThinkPad T61/X61换XP系统及驱动下载
- 20款知名PHP集成环境推荐与优缺点分析、php环境大全推荐(PHP环境搭建包)
- [J2SE]JTree使用DefaultTreeModel,对节点进行增删、拖拽和展开操作,以及跨平台文件拖拽的方法详细介绍
- 家庭服务器搭建,NAS存储
- json数组排序,深拷贝,浅拷贝,删除,增加,筛选,
- Web前端开发(一)--html基本结构,基本标签
- Python 二维码生成工具
- 起码我们曾经爱过,不是吗
- 锂电池电量百分比计算_锂离子电池容量计算之电压法
- 鹏业软件入选住建部第一批智能建造新技术新产品创新服务典型案例
- 计算机微机原理与接口技术课程设计课题,微机原理与接口技术课程设计报告
- 关于vue的冒号,@的含义
热门文章
- 学校新机房装系统——联想机房网络同传
- c语言中学生信息管理系统中删除学生信息,学生信息管理系统C语言编程
- 怎么用便签在手机上记事?
- .bat脚本基本命令合集
- 计算机二级java和c哪个难,计算机二级最好考哪个 考试难度怎么样
- keepalived,虚拟ip(vip)实践。
- IPsec的NAT穿越详解
- dism++封装系统使用教程_win7系统部署工具Dism的操作方法
- php嗅探链接,教你如何利用php来嗅探劫持服务器数据
- 2500亿规模,20%年增长,猎头平台化时代,谁的赢面最大? | 一点财经