TEORİDEN UYGULAMAYA · PYTHON EŞLİKÇİSİ

Öteleme, Dönme ve Yansıma

Prof. Dr. Zühal Küçükarslan Yüzbaşı · Prof. Dr. Bahadır Yüzbaşı

Bölüm 07 · v1.0 · Türkçe

Bu bölümün laboratuvarı, kitaptaki örnekleri yeniden üretmek ve sayısal sonuçları incelemek için hazırlanmıştır. Matematiksel tanımlar, ispatlar ve sorular kitapta yer alır.

Laboratuvarı indir (.py) Tam Python paketi (.zip)

Laboratuvar kodu

"""Bölüm 7 laboratuvarı: yerel CAD çerçevesinden robot dünyasına geçiş.

Model iki boyutlu ve sentetiktir. Koordinatlar milimetre, açılar sunumda
derecedir. Üç boyutlu poz, mekanik tolerans, kamera modeli, çarpışma ve
güvenlik denetimi içermez.
"""

from __future__ import annotations

import numpy as np

from agbook import (
    canonical_array_sha256,
    compose_rigid_motions,
    coordinates_from_frame,
    coordinates_in_frame,
    inverse_rigid_motion,
    line_from_points,
    pairwise_distances,
    polygon_signed_area,
    reflect_across_line,
    rigid_motion_diagnostics,
    rigid_transform,
    rotation_matrix_2d,
)


def main() -> None:
    part_local = np.array(
        [[0.0, 0.0], [120.0, 0.0], [120.0, 60.0], [0.0, 60.0]]
    )  # mm
    feature_local = np.array([95.0, 45.0])  # mm
    frame_origin = np.array([420.0, 180.0])  # mm, dünya çerçevesinde
    frame_angle_deg = 35.0
    frame_axes = rotation_matrix_2d(np.deg2rad(frame_angle_deg))

    part_world = coordinates_from_frame(part_local, frame_origin, frame_axes)
    feature_world = coordinates_from_frame(feature_local, frame_origin, frame_axes)
    recovered_local = coordinates_in_frame(part_world, frame_origin, frame_axes)
    frame_diagnostics = rigid_motion_diagnostics(
        part_local,
        frame_axes,
        frame_origin,
    )

    local_datum = np.array([0.0, 1.0, -30.0])  # y=30 mm
    reflected_local = reflect_across_line(feature_local, local_datum)
    reflected_world_from_local = coordinates_from_frame(
        reflected_local,
        frame_origin,
        frame_axes,
    )
    datum_world_points = coordinates_from_frame(
        [[0.0, 30.0], [120.0, 30.0]],
        frame_origin,
        frame_axes,
    )
    datum_world = line_from_points(datum_world_points[0], datum_world_points[1])
    reflected_world_direct = reflect_across_line(feature_world, datum_world)

    sensor_rotation = rotation_matrix_2d(np.deg2rad(-12.0))
    sensor_origin_in_part = np.array([35.0, 20.0])  # mm
    sensor_shape = np.array([[0.0, 0.0], [24.0, 0.0], [12.0, 10.0]])  # mm
    composed = compose_rigid_motions(
        frame_axes,
        frame_origin,
        sensor_rotation,
        sensor_origin_in_part,
    )
    sensor_world_direct = rigid_transform(
        sensor_shape,
        composed.matrix,
        composed.translation,
    )
    sensor_world_sequential = coordinates_from_frame(
        rigid_transform(sensor_shape, sensor_rotation, sensor_origin_in_part),
        frame_origin,
        frame_axes,
    )
    inverse = inverse_rigid_motion(composed.matrix, composed.translation)
    sensor_recovered = rigid_transform(
        sensor_world_direct,
        inverse.matrix,
        inverse.translation,
    )

    print("birim: mm")
    print("cerceve_acisi_derece:", f"{frame_angle_deg:.1f}")
    print("cerceve_baslangici:", np.round(frame_origin, 9))
    print("cerceve_determinanti:", f"{np.linalg.det(frame_axes):.12f}")
    print("ortogonallik_artigi:", f"{frame_diagnostics.orthogonality_residual:.3e}")
    print("yerel_ozellik:", np.round(feature_local, 9))
    print("dunya_ozellik:", np.round(feature_world, 9))
    print("cerceve_gidis_donus_artigi_mm:", f"{np.max(np.abs(recovered_local - part_local)):.3e}")
    print("uzaklik_artigi_mm:", f"{np.max(np.abs(pairwise_distances(part_world) - pairwise_distances(part_local))):.3e}")
    print("yerel_yonlu_alan_mm2:", f"{polygon_signed_area(part_local):.6f}")
    print("dunya_yonlu_alan_mm2:", f"{polygon_signed_area(part_world):.6f}")
    print("yansitilmis_yerel_ozellik:", np.round(reflected_local, 9))
    print("yansima_cerceve_uyumu_mm:", f"{np.max(np.abs(reflected_world_direct - reflected_world_from_local)):.3e}")
    print("bilesik_determinant:", f"{composed.determinant:.12f}")
    print("bilesim_artigi_mm:", f"{np.max(np.abs(sensor_world_direct - sensor_world_sequential)):.3e}")
    print("ters_hareket_artigi_mm:", f"{np.max(np.abs(sensor_recovered - sensor_shape)):.3e}")
    signature_values = np.concatenate(
        [
            part_world.ravel(),
            feature_world,
            reflected_world_direct,
            composed.matrix.ravel(),
            composed.translation,
        ]
    )
    print("bilimsel_imza:", canonical_array_sha256(signature_values))


if __name__ == "__main__":
    main()
Doğrulama çalıştırmasının çıktısı
birim: mm
cerceve_acisi_derece: 35.0
cerceve_baslangici: [420. 180.]
cerceve_determinanti: 1.000000000000
ortogonallik_artigi: 1.570e-16
yerel_ozellik: [95. 45.]
dunya_ozellik: [472.00850457 271.35160345]
cerceve_gidis_donus_artigi_mm: 5.684e-14
uzaklik_artigi_mm: 5.684e-14
yerel_yonlu_alan_mm2: 7200.000000
dunya_yonlu_alan_mm2: 7200.000000
yansitilmis_yerel_ozellik: [95. 15.]
yansima_cerceve_uyumu_mm: 5.684e-14
bilesik_determinant: 1.000000000000
bilesim_artigi_mm: 2.842e-14
ters_hareket_artigi_mm: 5.684e-14
bilimsel_imza: f9569f7376364a0d502180e57b2a5184658a08fe3c698061f8f5bc8277a74062
Metindeki Python kodları

Kod dosyasını indir

# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. Bölüm 7: yerel CAD çerçevesinden dünyaya geçiş ---
import numpy as np
from agbook import (
    coordinates_from_frame,
    coordinates_in_frame,
    pairwise_distances,
    polygon_signed_area,
    reflect_across_line,
    rigid_motion_diagnostics,
    rotation_matrix_2d,
)

part_local = np.array([
    [0.0, 0.0], [120.0, 0.0],
    [120.0, 60.0], [0.0, 60.0],
])  # mm
feature_local = np.array([95.0, 45.0])  # mm
origin = np.array([420.0, 180.0])  # mm
axes = rotation_matrix_2d(np.deg2rad(35.0))

part_world = coordinates_from_frame(part_local, origin, axes)
feature_world = coordinates_from_frame(feature_local, origin, axes)
recovered = coordinates_in_frame(part_world, origin, axes)
diagnostics = rigid_motion_diagnostics(part_local, axes, origin)
reflected = reflect_across_line(feature_local, [0.0, 1.0, -30.0])

distance_residual = np.max(np.abs(
    pairwise_distances(part_world) - pairwise_distances(part_local)
))
print("dunya_ozellik:", np.round(feature_world, 8))
print("yansitilmis_yerel_ozellik:", reflected)
print("ortogonallik_artigi:", f"{diagnostics.orthogonality_residual:.3e}")
print("gidis_donus_artigi_mm:", f"{np.max(np.abs(recovered-part_local)):.3e}")
print("uzaklik_artigi_mm:", f"{distance_residual:.3e}")
print("alanlar_mm2:", polygon_signed_area(part_local),
      polygon_signed_area(part_world))

Kaydedilen çıktı

1. Bölüm 7: yerel CAD çerçevesinden dünyaya geçiş
dunya_ozellik: [472.00850457 271.35160345]
yansitilmis_yerel_ozellik: [95. 15.]
ortogonallik_artigi: 1.570e-16
gidis_donus_artigi_mm: 5.684e-14
uzaklik_artigi_mm: 5.684e-14
alanlar_mm2: 7200.0 7199.999999999996
Çözümlerdeki Python kodları

Kod dosyasını indir

# Kitaptaki kod blokları; bu dosya içinde sırayla çalıştırılır.
# --- 1. Dört noktanın yansıma koşullarını sınama ---
import numpy as np
from agbook import canonical_line_coefficients, reflect_across_line

points = np.array([[0., 0.], [2., -1.], [4., 3.], [-2., 5.]])
line = canonical_line_coefficients([2., -1., 3.])
images = reflect_across_line(points, line)
midpoints = 0.5 * (points + images)
tangent = np.array([-line[1], line[0]])

line_residuals = midpoints @ line[:2] + line[2]
perpendicularity = (images - points) @ tangent
print(np.max(np.abs(line_residuals)))
print(np.max(np.abs(perpendicularity)))
assert np.allclose(line_residuals, 0.0, atol=1e-12, rtol=0.0)
assert np.allclose(perpendicularity, 0.0, atol=1e-12, rtol=0.0)

# --- 2. Ardışık ve birleşik rijit hareket ---
import numpy as np
from agbook import (
    compose_rigid_motions, rigid_transform, rotation_matrix_2d,
)

points = np.array([[0., 0.], [2., 1.], [-1., 3.]])
q1, t1 = rotation_matrix_2d(0.4), np.array([2., -1.])
q2, t2 = np.diag([1., -1.]), np.array([-3., 4.])
sequential = rigid_transform(rigid_transform(points, q1, t1), q2, t2)
motion = compose_rigid_motions(q2, t2, q1, t1)
direct = rigid_transform(points, motion.matrix, motion.translation)

print("bilesim_artigi:", np.max(np.abs(direct - sequential)))
print("ortogonallik_artigi:",
      np.linalg.norm(motion.matrix.T @ motion.matrix - np.eye(2)))
print("determinant:", motion.determinant)
assert np.allclose(direct, sequential, atol=1e-12, rtol=0.0)

# --- 3. Çerçeve gidiş-dönüş ve uzaklık denetimi ---
import numpy as np
from agbook import (
    coordinates_from_frame, coordinates_in_frame,
    pairwise_distances, rotation_matrix_2d,
)

local = np.array([[0., 0.], [2., 0.], [2., 3.], [-1., 4.], [5., -2.]])
origin = np.array([100., -40.])
axes = rotation_matrix_2d(np.deg2rad(27.0))
world = coordinates_from_frame(local, origin, axes)
recovered = coordinates_in_frame(world, origin, axes)
roundtrip = np.max(np.abs(recovered - local))
distance = np.max(np.abs(
    pairwise_distances(world) - pairwise_distances(local)
))
print(roundtrip, distance)
assert roundtrip <= 1e-12
assert distance <= 1e-12

# --- 4. Geçersiz eksen ve çerçeve testleri ---
import numpy as np
import pytest
from agbook import coordinates_from_frame, reflection_matrix_2d

with pytest.raises(ValueError, match="Yansıma ekseni"):
    reflection_matrix_2d([0.0, 0.0])

non_orthonormal = np.array([[1.0, 0.4], [0.0, 1.0]])
with pytest.raises(ValueError, match="ortogonal"):
    coordinates_from_frame([2.0, 3.0], [0.0, 0.0], non_orthonormal)

Kaydedilen çıktı

1. Dört noktanın yansıma koşullarını sınama
6.661338147750939e-16
4.440892098500626e-16

2. Ardışık ve birleşik rijit hareket
bilesim_artigi: 2.220446049250313e-16
ortogonallik_artigi: 3.0102202242079384e-17
determinant: -1.0

3. Çerçeve gidiş-dönüş ve uzaklık denetimi
1.4210854715202004e-14 8.43769498715119e-15

4. Geçersiz eksen ve çerçeve testleri

Çalıştırma rehberi

Önce tam Python paketini indirin ve arşivi açın. Aşağıdaki komutları arşivin üst klasöründen başlatın. İlk kurulum internet bağlantısı ve Python 3.12 veya 3.13 gerektirir. Bağımlılıklar sabittir; sistem Python'unu değiştirmemek için ayrı sanal ortam kullanılır.

macOS / Linux
cd analitik-geometri-python-v1.0
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
python labs/bolum_07_oteleme_donme_yansima.py
python -m pytest
Windows PowerShell
cd analitik-geometri-python-v1.0
py -3.13 -m venv .venv
.venv\Scripts\python.exe -m pip install -e ".[dev]"
.venv\Scripts\python.exe labs/bolum_07_oteleme_donme_yansima.py
.venv\Scripts\python.exe -m pytest

Laboratuvar dosyaları agbook yardımcı paketini kullanır; tek bir dosyayı indirmek paketi kurmanın yerini tutmaz. Metin/çözüm kodları kendi dosyaları içinde sırayla çalıştırılır; gizli bir notebook oturumu gerekmez. Son ondalık basamaklar platforma göre değişebilir.