import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; // 纹理分析结果接口 export interface PatternAnalysisResult { patternRecognition: PatternRecognition; repetitionAnalysis: RepetitionAnalysis; textureClassification: TextureClassification; visualRhythm: VisualRhythm; designRecommendations: string[]; } // 图案识别 export interface PatternRecognition { primaryPatterns: Array<{ type: 'geometric' | 'organic' | 'abstract' | 'floral' | 'striped' | 'checkered' | 'dotted' | 'textured'; confidence: number; // 0-100 coverage: number; // 0-100 characteristics: string[]; }>; patternComplexity: { level: 'simple' | 'moderate' | 'complex' | 'very-complex'; score: number; // 0-100 elements: number; // 图案元素数量 }; patternScale: { size: 'micro' | 'small' | 'medium' | 'large' | 'macro'; uniformity: number; // 0-100 variation: number; // 0-100 }; } // 重复性分析 export interface RepetitionAnalysis { repetitionType: { primary: 'regular' | 'irregular' | 'random' | 'semi-regular'; pattern: 'grid' | 'brick' | 'hexagonal' | 'radial' | 'linear' | 'organic'; consistency: number; // 0-100 }; spacing: { horizontal: number; // 像素或相对单位 vertical: number; uniformity: number; // 0-100 rhythm: 'tight' | 'moderate' | 'loose' | 'varied'; }; symmetry: { type: 'bilateral' | 'radial' | 'translational' | 'rotational' | 'none'; strength: number; // 0-100 axes: number; // 对称轴数量 }; tiling: { seamless: boolean; quality: number; // 0-100 edgeHandling: 'perfect' | 'good' | 'fair' | 'poor'; }; } // 纹理分类 export interface TextureClassification { textureFamily: { primary: 'natural' | 'artificial' | 'hybrid'; subcategory: string; confidence: number; // 0-100 }; surfaceCharacter: { tactileQuality: 'smooth' | 'rough' | 'bumpy' | 'ridged' | 'woven' | 'carved'; visualDepth: number; // 0-100 dimensionality: '2D' | '2.5D' | '3D'; }; materialSuggestion: { likelyMaterials: string[]; fabricationMethod: string[]; applicationSuitability: string[]; }; } // 视觉节奏 export interface VisualRhythm { rhythmType: { primary: 'regular' | 'alternating' | 'flowing' | 'progressive' | 'random'; intensity: number; // 0-100 tempo: 'slow' | 'moderate' | 'fast' | 'varied'; }; movement: { direction: 'horizontal' | 'vertical' | 'diagonal' | 'radial' | 'multi-directional'; flow: number; // 0-100 energy: number; // 0-100 }; emphasis: { focalPoints: number; contrast: number; // 0-100 hierarchy: number; // 0-100 }; harmony: { overall: number; // 0-100 balance: number; // 0-100 unity: number; // 0-100 }; } @Injectable({ providedIn: 'root' }) export class PatternAnalysisService { constructor() { } /** * 分析图片中的纹理图案 * @param imageFile 图片文件 */ analyzeImagePattern(imageFile: File): Observable { return of(this.simulatePatternAnalysis(imageFile)); } /** * 分析URL图片的纹理图案 * @param imageUrl 图片URL */ analyzePatternFromUrl(imageUrl: string): Observable { return of(this.simulatePatternAnalysisFromUrl(imageUrl)); } /** * 模拟纹理图案分析 */ private simulatePatternAnalysis(imageFile: File): PatternAnalysisResult { const fileName = imageFile.name.toLowerCase(); return this.generatePatternAnalysis(fileName); } private simulatePatternAnalysisFromUrl(imageUrl: string): PatternAnalysisResult { const urlLower = imageUrl.toLowerCase(); return this.generatePatternAnalysis(urlLower); } private generatePatternAnalysis(context: string): PatternAnalysisResult { const patternType = this.inferPatternType(context); return { patternRecognition: this.generatePatternRecognition(patternType, context), repetitionAnalysis: this.generateRepetitionAnalysis(patternType, context), textureClassification: this.generateTextureClassification(patternType, context), visualRhythm: this.generateVisualRhythm(patternType, context), designRecommendations: this.generateDesignRecommendations(patternType, context) }; } private inferPatternType(context: string): string { if (context.includes('geometric') || context.includes('grid')) return 'geometric'; if (context.includes('floral') || context.includes('flower')) return 'floral'; if (context.includes('stripe') || context.includes('line')) return 'striped'; if (context.includes('dot') || context.includes('circle')) return 'dotted'; if (context.includes('check') || context.includes('square')) return 'checkered'; if (context.includes('organic') || context.includes('natural')) return 'organic'; if (context.includes('abstract')) return 'abstract'; return 'textured'; // 默认纹理类型 } private generatePatternRecognition(patternType: string, context: string): PatternRecognition { const isComplex = context.includes('complex') || context.includes('detailed'); const isLarge = context.includes('large') || context.includes('big'); const basePattern = this.getBasePatternData(patternType); return { primaryPatterns: [ { type: patternType as any, confidence: 85 + Math.random() * 10, coverage: 70 + Math.random() * 25, characteristics: basePattern.characteristics } ], patternComplexity: { level: isComplex ? 'complex' : basePattern.complexity.level, score: isComplex ? 80 + Math.random() * 15 : basePattern.complexity.score, elements: isComplex ? 15 + Math.floor(Math.random() * 10) : basePattern.complexity.elements }, patternScale: { size: isLarge ? 'large' : basePattern.scale.size, uniformity: basePattern.scale.uniformity, variation: basePattern.scale.variation } }; } private getBasePatternData(patternType: string): any { const patterns: { [key: string]: any } = { geometric: { characteristics: ['规则', '对称', '数学性', '现代'], complexity: { level: 'moderate', score: 60, elements: 8 }, scale: { size: 'medium', uniformity: 85, variation: 20 } }, floral: { characteristics: ['自然', '有机', '装饰性', '传统'], complexity: { level: 'complex', score: 75, elements: 12 }, scale: { size: 'medium', uniformity: 60, variation: 40 } }, striped: { characteristics: ['线性', '方向性', '简洁', '经典'], complexity: { level: 'simple', score: 30, elements: 3 }, scale: { size: 'medium', uniformity: 90, variation: 15 } }, dotted: { characteristics: ['点状', '规律', '轻盈', '现代'], complexity: { level: 'simple', score: 35, elements: 4 }, scale: { size: 'small', uniformity: 80, variation: 25 } }, checkered: { characteristics: ['格子', '对比', '经典', '结构化'], complexity: { level: 'simple', score: 40, elements: 2 }, scale: { size: 'medium', uniformity: 95, variation: 10 } }, organic: { characteristics: ['自然', '流动', '不规则', '和谐'], complexity: { level: 'moderate', score: 65, elements: 10 }, scale: { size: 'varied', uniformity: 45, variation: 60 } }, abstract: { characteristics: ['抽象', '艺术性', '创新', '表现力'], complexity: { level: 'complex', score: 80, elements: 15 }, scale: { size: 'varied', uniformity: 40, variation: 70 } }, textured: { characteristics: ['质感', '触觉', '深度', '材质感'], complexity: { level: 'moderate', score: 55, elements: 6 }, scale: { size: 'small', uniformity: 70, variation: 35 } } }; return patterns[patternType] || patterns['textured']; } private generateRepetitionAnalysis(patternType: string, context: string): RepetitionAnalysis { const isRegular = patternType === 'geometric' || patternType === 'striped' || patternType === 'checkered'; const isSeamless = context.includes('seamless') || context.includes('tile'); return { repetitionType: { primary: isRegular ? 'regular' : 'semi-regular', pattern: this.getRepetitionPattern(patternType), consistency: isRegular ? 85 + Math.random() * 10 : 60 + Math.random() * 25 }, spacing: { horizontal: 50 + Math.random() * 100, vertical: 50 + Math.random() * 100, uniformity: isRegular ? 85 + Math.random() * 10 : 55 + Math.random() * 30, rhythm: this.getSpacingRhythm(patternType) }, symmetry: { type: this.getSymmetryType(patternType), strength: this.getSymmetryStrength(patternType), axes: this.getSymmetryAxes(patternType) }, tiling: { seamless: isSeamless, quality: isSeamless ? 90 + Math.random() * 8 : 60 + Math.random() * 30, edgeHandling: isSeamless ? 'perfect' : 'good' } }; } private generateTextureClassification(patternType: string, context: string): TextureClassification { const isNatural = patternType === 'organic' || patternType === 'floral' || context.includes('natural'); return { textureFamily: { primary: isNatural ? 'natural' : 'artificial', subcategory: this.getTextureSubcategory(patternType), confidence: 80 + Math.random() * 15 }, surfaceCharacter: { tactileQuality: this.getTactileQuality(patternType), visualDepth: this.getVisualDepth(patternType), dimensionality: this.getDimensionality(patternType) }, materialSuggestion: { likelyMaterials: this.getLikelyMaterials(patternType), fabricationMethod: this.getFabricationMethods(patternType), applicationSuitability: this.getApplicationSuitability(patternType) } }; } private generateVisualRhythm(patternType: string, context: string): VisualRhythm { const isDynamic = context.includes('dynamic') || context.includes('movement'); return { rhythmType: { primary: this.getRhythmType(patternType), intensity: this.getRhythmIntensity(patternType, isDynamic), tempo: this.getRhythmTempo(patternType) }, movement: { direction: this.getMovementDirection(patternType), flow: this.getFlowValue(patternType), energy: isDynamic ? 80 + Math.random() * 15 : 50 + Math.random() * 30 }, emphasis: { focalPoints: this.getFocalPoints(patternType), contrast: this.getContrastValue(patternType), hierarchy: this.getHierarchyValue(patternType) }, harmony: { overall: 70 + Math.random() * 25, balance: this.getBalanceValue(patternType), unity: this.getUnityValue(patternType) } }; } private generateDesignRecommendations(patternType: string, context: string): string[] { const recommendations = []; // 基于图案类型的建议 switch (patternType) { case 'geometric': recommendations.push('保持几何图案的精确性和一致性'); recommendations.push('考虑使用对比色增强视觉效果'); break; case 'floral': recommendations.push('平衡花卉图案的复杂度和可读性'); recommendations.push('注意色彩搭配的自然和谐'); break; case 'striped': recommendations.push('控制条纹的宽度比例'); recommendations.push('注意条纹方向对空间感的影响'); break; case 'organic': recommendations.push('保持有机图案的自然流动感'); recommendations.push('避免过度规则化'); break; } // 基于上下文的建议 if (context.includes('interior')) { recommendations.push('考虑图案对室内空间感的影响'); } if (context.includes('fabric')) { recommendations.push('注意图案的可缝制性和耐用性'); } if (context.includes('wallpaper')) { recommendations.push('确保图案的无缝拼接效果'); } return recommendations.length > 0 ? recommendations : ['保持图案设计的整体协调性']; } // 辅助方法 private getRepetitionPattern(patternType: string): 'grid' | 'brick' | 'hexagonal' | 'radial' | 'linear' | 'organic' { const patterns: { [key: string]: 'grid' | 'brick' | 'hexagonal' | 'radial' | 'linear' | 'organic' } = { geometric: 'grid', striped: 'linear', checkered: 'grid', dotted: 'grid', floral: 'organic', organic: 'organic', abstract: 'radial', textured: 'brick' }; return patterns[patternType] || 'grid'; } private getSpacingRhythm(patternType: string): 'tight' | 'moderate' | 'loose' | 'varied' { const rhythms: { [key: string]: 'tight' | 'moderate' | 'loose' | 'varied' } = { geometric: 'moderate', striped: 'tight', checkered: 'moderate', dotted: 'moderate', floral: 'varied', organic: 'varied', abstract: 'varied', textured: 'tight' }; return rhythms[patternType] || 'moderate'; } private getSymmetryType(patternType: string): 'bilateral' | 'radial' | 'translational' | 'rotational' | 'none' { const types: { [key: string]: 'bilateral' | 'radial' | 'translational' | 'rotational' | 'none' } = { geometric: 'bilateral', striped: 'translational', checkered: 'bilateral', dotted: 'translational', floral: 'radial', organic: 'none', abstract: 'rotational', textured: 'translational' }; return types[patternType] || 'bilateral'; } private getSymmetryStrength(patternType: string): number { const strengths: { [key: string]: number } = { geometric: 90, striped: 85, checkered: 95, dotted: 80, floral: 60, organic: 30, abstract: 50, textured: 70 }; return (strengths[patternType] || 70) + Math.random() * 10; } private getSymmetryAxes(patternType: string): number { const axes: { [key: string]: number } = { geometric: 2, striped: 1, checkered: 2, dotted: 4, floral: 4, organic: 0, abstract: 3, textured: 1 }; return axes[patternType] || 2; } private getTextureSubcategory(patternType: string): string { const subcategories: { [key: string]: string } = { geometric: '几何纹理', floral: '植物纹理', striped: '线性纹理', dotted: '点状纹理', checkered: '格子纹理', organic: '有机纹理', abstract: '抽象纹理', textured: '表面纹理' }; return subcategories[patternType] || '混合纹理'; } private getTactileQuality(patternType: string): 'smooth' | 'rough' | 'bumpy' | 'ridged' | 'woven' | 'carved' { const qualities: { [key: string]: 'smooth' | 'rough' | 'bumpy' | 'ridged' | 'woven' | 'carved' } = { geometric: 'smooth', floral: 'carved', striped: 'ridged', dotted: 'bumpy', checkered: 'woven', organic: 'rough', abstract: 'rough', textured: 'rough' }; return qualities[patternType] || 'smooth'; } private getVisualDepth(patternType: string): number { const depths: { [key: string]: number } = { geometric: 40, floral: 70, striped: 30, dotted: 50, checkered: 35, organic: 80, abstract: 85, textured: 90 }; return depths[patternType] || 50; } private getDimensionality(patternType: string): '2D' | '2.5D' | '3D' { const dims: { [key: string]: '2D' | '2.5D' | '3D' } = { geometric: '2D', floral: '2.5D', striped: '2D', dotted: '2D', checkered: '2D', organic: '3D', abstract: '2.5D', textured: '3D' }; return dims[patternType] || '2D'; } private getLikelyMaterials(patternType: string): string[] { const materials: { [key: string]: string[] } = { geometric: ['金属', '塑料', '陶瓷'], floral: ['织物', '壁纸', '陶瓷'], striped: ['织物', '木材', '金属'], dotted: ['织物', '塑料', '纸张'], checkered: ['织物', '瓷砖', '纸张'], organic: ['木材', '石材', '皮革'], abstract: ['画布', '金属', '玻璃'], textured: ['石材', '混凝土', '皮革'] }; return materials[patternType] || ['通用材料']; } private getFabricationMethods(patternType: string): string[] { const methods: { [key: string]: string[] } = { geometric: ['激光切割', '数控加工', '模具成型'], floral: ['印刷', '刺绣', '雕刻'], striped: ['编织', '印刷', '切割'], dotted: ['打孔', '印刷', '压花'], checkered: ['编织', '印刷', '拼接'], organic: ['手工雕刻', '铸造', '3D打印'], abstract: ['手绘', '喷涂', '数字印刷'], textured: ['压花', '喷砂', '化学蚀刻'] }; return methods[patternType] || ['常规加工']; } private getApplicationSuitability(patternType: string): string[] { const applications: { [key: string]: string[] } = { geometric: ['现代室内', '办公空间', '科技产品'], floral: ['家居装饰', '服装设计', '传统空间'], striped: ['服装', '室内装饰', '包装设计'], dotted: ['儿童用品', '休闲服装', '装饰品'], checkered: ['经典服装', '餐厅装饰', '游戏用品'], organic: ['自然风格室内', '艺术品', '高端产品'], abstract: ['艺术空间', '创意产品', '展示设计'], textured: ['建筑外观', '工业设计', '触觉产品'] }; return applications[patternType] || ['通用应用']; } private getRhythmType(patternType: string): 'regular' | 'alternating' | 'flowing' | 'progressive' | 'random' { const types: { [key: string]: 'regular' | 'alternating' | 'flowing' | 'progressive' | 'random' } = { geometric: 'regular', floral: 'flowing', striped: 'alternating', dotted: 'regular', checkered: 'alternating', organic: 'flowing', abstract: 'progressive', textured: 'random' }; return types[patternType] || 'regular'; } private getRhythmIntensity(patternType: string, isDynamic: boolean): number { const base: { [key: string]: number } = { geometric: 60, floral: 70, striped: 80, dotted: 50, checkered: 75, organic: 65, abstract: 85, textured: 55 }; const intensity = base[patternType] || 60; return isDynamic ? Math.min(95, intensity + 20) : intensity; } private getRhythmTempo(patternType: string): 'slow' | 'moderate' | 'fast' | 'varied' { const tempos: { [key: string]: 'slow' | 'moderate' | 'fast' | 'varied' } = { geometric: 'moderate', floral: 'slow', striped: 'fast', dotted: 'moderate', checkered: 'fast', organic: 'varied', abstract: 'varied', textured: 'slow' }; return tempos[patternType] || 'moderate'; } private getMovementDirection(patternType: string): 'horizontal' | 'vertical' | 'diagonal' | 'radial' | 'multi-directional' { const directions: { [key: string]: 'horizontal' | 'vertical' | 'diagonal' | 'radial' | 'multi-directional' } = { geometric: 'multi-directional', floral: 'radial', striped: 'horizontal', dotted: 'multi-directional', checkered: 'multi-directional', organic: 'radial', abstract: 'multi-directional', textured: 'multi-directional' }; return directions[patternType] || 'multi-directional'; } private getFlowValue(patternType: string): number { const flows: { [key: string]: number } = { geometric: 50, floral: 80, striped: 70, dotted: 40, checkered: 45, organic: 90, abstract: 75, textured: 60 }; return (flows[patternType] || 60) + Math.random() * 15; } private getFocalPoints(patternType: string): number { const points: { [key: string]: number } = { geometric: 4, floral: 6, striped: 2, dotted: 8, checkered: 4, organic: 3, abstract: 5, textured: 2 }; return points[patternType] || 4; } private getContrastValue(patternType: string): number { const contrasts: { [key: string]: number } = { geometric: 80, floral: 60, striped: 90, dotted: 70, checkered: 95, organic: 50, abstract: 85, textured: 65 }; return (contrasts[patternType] || 70) + Math.random() * 15; } private getHierarchyValue(patternType: string): number { const hierarchies: { [key: string]: number } = { geometric: 85, floral: 70, striped: 60, dotted: 55, checkered: 75, organic: 65, abstract: 80, textured: 50 }; return (hierarchies[patternType] || 65) + Math.random() * 15; } private getBalanceValue(patternType: string): number { const balances: { [key: string]: number } = { geometric: 90, floral: 75, striped: 85, dotted: 80, checkered: 95, organic: 60, abstract: 70, textured: 65 }; return (balances[patternType] || 75) + Math.random() * 15; } private getUnityValue(patternType: string): number { const unities: { [key: string]: number } = { geometric: 85, floral: 80, striped: 90, dotted: 75, checkered: 90, organic: 70, abstract: 65, textured: 70 }; return (unities[patternType] || 75) + Math.random() * 15; } }