HARMONYOS应用实例244:全等三角形判定器
·
- 全等三角形判定器
- 功能:用户输入三边或两边一角,系统判断是否能判定全等(SSS, SAS, ASA等),并高亮对应边角。
输入界面:提供两个三角形的边长和角度输入字段
自动判定:实时判断两个三角形是否全等
判定方法:支持 SSS、SAS、ASA、AAS、HL 等判定方法
可视化显示:在 Canvas 中绘制两个三角形,并高亮显示判定依据
结果展示:显示判定结果和使用的判定方法
**
* 三角形全等判定工具
* 功能:用户输入三边或两边一角,系统判断是否能判定全等(SSS, SAS, ASA等),并高亮对应边角
*/
// 三角形数据接口
interface TriangleData {
a: number
b: number
c: number
A: number
B: number
C: number
}
@Entry
@Component
struct CongruentTriangles {
// 三角形1的边长
@State sideA1: string = ''
@State sideB1: string = ''
@State sideC1: string = ''
@State angleA1: string = ''
@State angleB1: string = ''
@State angleC1: string = ''
// 三角形2的边长
@State sideA2: string = ''
@State sideB2: string = ''
@State sideC2: string = ''
@State angleA2: string = ''
@State angleB2: string = ''
@State angleC2: string = ''
// 判定结果
@State result: string = ''
@State method: string = ''
@State highlightSides: string[] = []
@State highlightAngles: string[] = []
// 画布配置
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
Scroll() {
Column({ space: 20 }) {
// 标题
Text('三角形全等判定工具')
.fontSize(28)
.fontWeight('Bold')
.textAlign(TextAlign.Center)
// 功能介绍
Text('输入两个三角形的边长或角度,系统将自动判断是否全等,并高亮显示判定依据')
.fontSize(14)
.fontColor('#666')
.textAlign(TextAlign.Center)
.width('90%')
// 三角形1输入区域
Column() {
Text('三角形 1')
.fontSize(18)
.fontWeight('Bold')
.margin({ bottom: 10 })
Grid() {
GridItem() {
Column() {
Text('边长 A')
TextInput({ text: this.sideA1 })
.width(80)
.height(40)
.onChange((val) => {
this.sideA1 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('角度 A')
TextInput({ text: this.angleA1 })
.width(80)
.height(40)
.onChange((val) => {
this.angleA1 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('边长 B')
TextInput({ text: this.sideB1 })
.width(80)
.height(40)
.onChange((val) => {
this.sideB1 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('角度 B')
TextInput({ text: this.angleB1 })
.width(80)
.height(40)
.onChange((val) => {
this.angleB1 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('边长 C')
TextInput({ text: this.sideC1 })
.width(80)
.height(40)
.onChange((val) => {
this.sideC1 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('角度 C')
TextInput({ text: this.angleC1 })
.width(80)
.height(40)
.onChange((val) => {
this.angleC1 = val
this.judgeCongruence()
})
}
}
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
}
.width('90%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(10)
// 三角形2输入区域
Column() {
Text('三角形 2')
.fontSize(18)
.fontWeight('Bold')
.margin({ bottom: 10 })
Grid() {
GridItem() {
Column() {
Text('边长 A')
TextInput({ text: this.sideA2 })
.width(80)
.height(40)
.onChange((val) => {
this.sideA2 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('角度 A')
TextInput({ text: this.angleA2 })
.width(80)
.height(40)
.onChange((val) => {
this.angleA2 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('边长 B')
TextInput({ text: this.sideB2 })
.width(80)
.height(40)
.onChange((val) => {
this.sideB2 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('角度 B')
TextInput({ text: this.angleB2 })
.width(80)
.height(40)
.onChange((val) => {
this.angleB2 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('边长 C')
TextInput({ text: this.sideC2 })
.width(80)
.height(40)
.onChange((val) => {
this.sideC2 = val
this.judgeCongruence()
})
}
}
GridItem() {
Column() {
Text('角度 C')
TextInput({ text: this.angleC2 })
.width(80)
.height(40)
.onChange((val) => {
this.angleC2 = val
this.judgeCongruence()
})
}
}
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(10)
.rowsGap(10)
}
.width('90%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(10)
// 判定结果
Column() {
Text('判定结果')
.fontSize(18)
.fontWeight('Bold')
.margin({ bottom: 10 })
Text(this.result)
.fontSize(16)
.fontColor(this.result.includes('全等') ? '#4CAF50' : '#F44336')
.textAlign(TextAlign.Center)
if (this.method) {
Text(`判定方法:${this.method}`)
.fontSize(14)
.fontColor('#666')
.margin({ top: 5 })
}
}
.width('90%')
.padding(15)
.backgroundColor('#F5F5F5')
.borderRadius(10)
// 三角形可视化
Column() {
Text('三角形可视化')
.fontSize(18)
.fontWeight('Bold')
.margin({ bottom: 10 })
Canvas(this.context)
.width('90%')
.height(300)
.backgroundColor('#FFFFFF')
.borderRadius(10)
.onReady(() => {
this.drawTriangles()
})
}
// 使用说明
Column() {
Text('使用说明')
.fontSize(18)
.fontWeight('Bold')
.margin({ bottom: 10 })
Text('1. 输入两个三角形的边长或角度')
.fontSize(14)
.fontColor('#666')
Text('2. 系统会自动判断是否全等')
.fontSize(14)
.fontColor('#666')
Text('3. 全等的边角会在图中高亮显示')
.fontSize(14)
.fontColor('#666')
Text('4. 支持的判定方法:SSS, SAS, ASA, AAS, HL')
.fontSize(14)
.fontColor('#666')
}
.width('90%')
.padding(15)
.backgroundColor('#F5F5F5')
.borderRadius(10)
}
.width('100%')
.padding(20)
.backgroundColor('#F0F4F8')
}
}
// 判定三角形全等
private judgeCongruence() {
// 清空之前的结果
this.result = ''
this.method = ''
this.highlightSides = []
this.highlightAngles = []
// 解析输入值
const s1: TriangleData = {
a: parseFloat(this.sideA1),
b: parseFloat(this.sideB1),
c: parseFloat(this.sideC1),
A: parseFloat(this.angleA1),
B: parseFloat(this.angleB1),
C: parseFloat(this.angleC1)
}
const s2: TriangleData = {
a: parseFloat(this.sideA2),
b: parseFloat(this.sideB2),
c: parseFloat(this.sideC2),
A: parseFloat(this.angleA2),
B: parseFloat(this.angleB2),
C: parseFloat(this.angleC2)
}
// 检查输入是否足够
const validSides1 = [s1.a, s1.b, s1.c].filter(v => !isNaN(v)).length
const validAngles1 = [s1.A, s1.B, s1.C].filter(v => !isNaN(v)).length
const validSides2 = [s2.a, s2.b, s2.c].filter(v => !isNaN(v)).length
const validAngles2 = [s2.A, s2.B, s2.C].filter(v => !isNaN(v)).length
if (validSides1 < 3 && (validSides1 + validAngles1) < 3) {
this.result = '请输入足够的边长或角度'
this.drawTriangles()
return
}
if (validSides2 < 3 && (validSides2 + validAngles2) < 3) {
this.result = '请输入足够的边长或角度'
this.drawTriangles()
return
}
// SSS 判定
if (!isNaN(s1.a) && !isNaN(s1.b) && !isNaN(s1.c) &&
!isNaN(s2.a) && !isNaN(s2.b) && !isNaN(s2.c)) {
const sides1 = [s1.a, s1.b, s1.c].sort((a, b) => a - b)
const sides2 = [s2.a, s2.b, s2.c].sort((a, b) => a - b)
if (this.isEqual(sides1[0], sides2[0]) &&
this.isEqual(sides1[1], sides2[1]) &&
this.isEqual(sides1[2], sides2[2])) {
this.result = '两个三角形全等'
this.method = 'SSS (边边边)'
this.highlightSides = ['a', 'b', 'c']
this.drawTriangles()
return
}
}
// SAS 判定
if (!isNaN(s1.a) && !isNaN(s1.b) && !isNaN(s1.C) &&
!isNaN(s2.a) && !isNaN(s2.b) && !isNaN(s2.C)) {
if (this.isEqual(s1.a, s2.a) &&
this.isEqual(s1.C, s2.C) &&
this.isEqual(s1.b, s2.b)) {
this.result = '两个三角形全等'
this.method = 'SAS (边角边)'
this.highlightSides = ['a', 'b']
this.highlightAngles = ['C']
this.drawTriangles()
return
}
}
// ASA 判定
if (!isNaN(s1.A) && !isNaN(s1.B) && !isNaN(s1.c) &&
!isNaN(s2.A) && !isNaN(s2.B) && !isNaN(s2.c)) {
if (this.isEqual(s1.A, s2.A) &&
this.isEqual(s1.c, s2.c) &&
this.isEqual(s1.B, s2.B)) {
this.result = '两个三角形全等'
this.method = 'ASA (角边角)'
this.highlightSides = ['c']
this.highlightAngles = ['A', 'B']
this.drawTriangles()
return
}
}
// AAS 判定
if (!isNaN(s1.A) && !isNaN(s1.B) && !isNaN(s1.a) &&
!isNaN(s2.A) && !isNaN(s2.B) && !isNaN(s2.a)) {
if (this.isEqual(s1.A, s2.A) &&
this.isEqual(s1.B, s2.B) &&
this.isEqual(s1.a, s2.a)) {
this.result = '两个三角形全等'
this.method = 'AAS (角角边)'
this.highlightSides = ['a']
this.highlightAngles = ['A', 'B']
this.drawTriangles()
return
}
}
// HL 判定(直角三角形)
if ((!isNaN(s1.C) && this.isEqual(s1.C, 90)) &&
(!isNaN(s2.C) && this.isEqual(s2.C, 90)) &&
!isNaN(s1.a) && !isNaN(s1.b) &&
!isNaN(s2.a) && !isNaN(s2.b)) {
const hyp1 = Math.max(s1.a, s1.b)
const leg1 = Math.min(s1.a, s1.b)
const hyp2 = Math.max(s2.a, s2.b)
const leg2 = Math.min(s2.a, s2.b)
if (this.isEqual(hyp1, hyp2) && this.isEqual(leg1, leg2)) {
this.result = '两个直角三角形全等'
this.method = 'HL (斜边直角边)'
this.highlightSides = ['a', 'b']
this.highlightAngles = ['C']
this.drawTriangles()
return
}
}
// 无法判定全等
this.result = '无法判定全等'
this.drawTriangles()
}
// 绘制三角形
private drawTriangles() {
const ctx = this.context
const width = 360
const height = 300
// 清空画布
ctx.clearRect(0, 0, width, height)
// 绘制三角形1
this.drawTriangle(ctx, 100, 150, 200, 150, 100, 100, '三角形 1', 1)
// 绘制三角形2
this.drawTriangle(ctx, 250, 150, 350, 150, 300, 100, '三角形 2', 2)
}
// 绘制单个三角形
private drawTriangle(ctx: CanvasRenderingContext2D, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, label: string, triangleIndex: number) {
// 绘制三角形
ctx.beginPath()
ctx.moveTo(x1, y1)
ctx.lineTo(x2, y2)
ctx.lineTo(x3, y3)
ctx.closePath()
ctx.strokeStyle = '#333333'
ctx.lineWidth = 2
ctx.stroke()
// 绘制标签
ctx.font = '14px sans-serif'
ctx.fillStyle = '#333333'
ctx.fillText(label, x1 - 30, y1 - 10)
// 绘制边长标签
const sides = ['a', 'b', 'c']
const points = [[x1, y1, x2, y2], [x2, y2, x3, y3], [x3, y3, x1, y1]]
for (let i = 0; i < 3; i++) {
const point = points[i]
const x4 = point[0]
const y4 = point[1]
const x5 = point[2]
const y5 = point[3]
const midX = (x4 + x5) / 2
const midY = (y4 + y5) / 2
// 检查是否需要高亮
const isHighlighted = this.highlightSides.includes(sides[i])
if (isHighlighted) {
// 高亮边
ctx.beginPath()
ctx.moveTo(x4, y4)
ctx.lineTo(x5, y5)
ctx.strokeStyle = '#4CAF50'
ctx.lineWidth = 4
ctx.stroke()
}
// 绘制边长标签
ctx.font = '12px sans-serif'
ctx.fillStyle = isHighlighted ? '#4CAF50' : '#666666'
ctx.fillText(sides[i], midX, midY - 5)
}
// 绘制角度标签
const angles = ['A', 'B', 'C']
const anglePoints = [[x1, y1], [x2, y2], [x3, y3]]
for (let i = 0; i < 3; i++) {
const point = anglePoints[i]
const x = point[0]
const y = point[1]
// 检查是否需要高亮
const isHighlighted = this.highlightAngles.includes(angles[i])
if (isHighlighted) {
// 高亮角
ctx.beginPath()
ctx.arc(x, y, 10, 0, Math.PI * 2)
ctx.strokeStyle = '#2196F3'
ctx.lineWidth = 2
ctx.stroke()
}
// 绘制角度标签
ctx.font = '12px sans-serif'
ctx.fillStyle = isHighlighted ? '#2196F3' : '#666666'
ctx.fillText(angles[i], x - 5, y + 5)
}
}
// 比较两个数值是否相等(考虑浮点数精度)
private isEqual(a: number, b: number): boolean {
return Math.abs(a - b) < 0.001
}
}
更多推荐


所有评论(0)