Skip to content

Commit

Permalink
- Finished: Algorithm for subdivision surfaces
Browse files Browse the repository at this point in the history
  Note: Creation of polygones is still errnous


git-svn-id: https://svn.php.net/repository/pear/packages/Image_3D/trunk@209875 c90b9560-bf6c-de11-be94-00142212c4b1
  • Loading branch information
kore committed Mar 22, 2006
1 parent 98199c1 commit 66c059f
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 76 deletions.
200 changes: 127 additions & 73 deletions Image/3D/Paintable/Object.php
Expand Up @@ -148,86 +148,140 @@ protected function _buildInzidenzGraph() {
}

public function subdivisionSurfaces($factor = 1) {
$data = $this->_buildInzidenzGraph();

// Additional hash maps
$edge_surfaces = array();
$point_edges = array();

// New calculated points
$face_points = array();
$edge_points = array();
$old_points = array();

// Calculate "face points"
foreach ($data['surfaces'] as $surface => $edges) {
// Get all points
$points = array();
foreach ($edges as $edge) {
$points = array_merge($points, $data['edges'][$edge]);
$edge_surfaces[$edge][] = $surface;
}
$points = array_unique($points);

// Calculate average
$face_point = array(0, 0, 0);
$point_count = count($points);
foreach ($points as $point) {
$face_point[0] += $data['points'][$point]->getX() / $point_count;
$face_point[1] += $data['points'][$point]->getY() / $point_count;
$face_point[2] += $data['points'][$point]->getZ() / $point_count;
for ($i = 0; $i < $factor; ++$i) {
$data = $this->_buildInzidenzGraph();

// Additional hash maps
$edge_surfaces = array();
$edge_middles = array();
$point_edges = array();

// New calculated points
$face_points = array();
$edge_points = array();
$old_points = array();

// Calculate "face points"
foreach ($data['surfaces'] as $surface => $edges) {
// Get all points
$points = array();
foreach ($edges as $edge) {
$points = array_merge($points, $data['edges'][$edge]);
$edge_surfaces[$edge][] = $surface;
}
$points = array_unique($points);

// Calculate average
$face_point = array(0, 0, 0);
$point_count = count($points);
foreach ($points as $point) {
$face_point[0] += $data['points'][$point]->getX() / $point_count;
$face_point[1] += $data['points'][$point]->getY() / $point_count;
$face_point[2] += $data['points'][$point]->getZ() / $point_count;
}

// Create face point
$face_points[$surface] = new Image_3D_Point($face_point[0], $face_point[1], $face_point[2]);
}

// Create face point
$face_points[$surface] = new Image_3D_Point($face_point[0], $face_point[1], $face_point[2]);
}

// Calculate "edge points"
foreach ($data['edges'] as $edge => $points) {
// Calculate middle of edge
$edge_middle = array(0, 0, 0);
$point_count = count($points);
foreach ($points as $point) {
$point_edges[$point][] = $edge;
$edge_middle[0] += $data['points'][$point]->getX() / $point_count;
$edge_middle[1] += $data['points'][$point]->getY() / $point_count;
$edge_middle[2] += $data['points'][$point]->getZ() / $point_count;
// Calculate "edge points"
foreach ($data['edges'] as $edge => $points) {
// Calculate middle of edge
if (isset($edge_middles[$edge])) {
$edge_middle = $edge_middles[$edge];
} else {
$edge_middle = array(0, 0, 0);
$point_count = count($points);
foreach ($points as $point) {
$point_edges[$point][] = $edge;
$edge_middle[0] += $data['points'][$point]->getX() / $point_count;
$edge_middle[1] += $data['points'][$point]->getY() / $point_count;
$edge_middle[2] += $data['points'][$point]->getZ() / $point_count;
}
$edge_middles[$edge] = $edge_middle;
}

// Calculate average of the adjacent faces
$average_face = array(0, 0, 0);
$point_count = count($edge_surfaces[$edge]);
foreach ($edge_surfaces[$edge] as $surface) {
$average_face[0] += $face_points[$surface]->getX() / $point_count;
$average_face[1] += $face_points[$surface]->getY() / $point_count;
$average_face[2] += $face_points[$surface]->getZ() / $point_count;
}

// Create edge point on this base
$edge_points[$edge] = new Image_3D_Point(($average_face[0] + $edge_middle[0]) / 2, ($average_face[1] + $edge_middle[1]) / 2, ($average_face[2] + $edge_middle[2]) / 2);
}

// Calculate average of the adjacent faces
$average_face = array(0, 0, 0);
$point_count = count($edge_surfaces[$edge]);
foreach ($edge_surfaces[$edge] as $surface) {
$average_face[0] += $face_points[$surface]->getX() / $point_count;
$average_face[1] += $face_points[$surface]->getY() / $point_count;
$average_face[2] += $face_points[$surface]->getZ() / $point_count;
// Reposition old vertices
foreach ($data['points'] as $point => $value) {
// Calculate average of midpoints of adjacent edges
$r = array(0, 0, 0);
$surfaces = array();
$point_count = count($point_edges[$point]);
foreach ($point_edges[$point] as $edge) {
$r[0] += $edge_middles[$edge][0] / $point_count;
$r[1] += $edge_middles[$edge][1] / $point_count;
$r[2] += $edge_middles[$edge][2] / $point_count;
$surfaces = array_merge($surfaces, $edge_surfaces[$edge]);
}
$surfaces= array_unique($surfaces);

// Calculate average of surrounding face points
$q = array(0, 0, 0);
$surface_count = count($surfaces);
foreach ($surfaces as $surface) {
$q[0] += $face_points[$surface]->getX() / $surface_count;
$q[1] += $face_points[$surface]->getY() / $surface_count;
$q[2] += $face_points[$surface]->getZ() / $surface_count;
}

// Create new edge point
$n = count($point_edges[$point]);
$old_points[$point] = new Image_3D_Point(
($q[0] / $n) + ((2 * $r[0]) / $n) + (($value->getX() * ($n - 3)) / $n),
($q[1] / $n) + ((2 * $r[1]) / $n) + (($value->getY() * ($n - 3)) / $n),
($q[2] / $n) + ((2 * $r[2]) / $n) + (($value->getZ() * ($n - 3)) / $n)
);
}

// Create edge point on this base
$edge_points[$edge] = new Image_3D_Point(($average_face[0] + $edge_middle[0]) / 2, ($average_face[1] + $edge_middle[1]) / 2, ($average_face[2] + $edge_middle[2]) / 2);
}

// Reposition old vertices
foreach ($data['points'] as $point => $value) {
// Calculate average of surrounding face points
$q = array(0, 0, 0);
// @TODO: implement

// Calculate average of midpoints of adjacent edges
$r = array(0, 0, 0);
// @TODO: implement

// Create new edge point
$n = count($point_edges[$point]);
$old_points[$point] = new Image_3D_Point(
($q[0] / $n) + ((2 * $r[0]) / $n) + (($value->getX() * ($n - 3)) / $n),
($q[1] / $n) + ((2 * $r[1]) / $n) + (($value->getY() * ($n - 3)) / $n),
($q[2] / $n) + ((2 * $r[2]) / $n) + (($value->getZ() * ($n - 3)) / $n)
);
}
// Create polygones on new points
$this->_polygones = array();
foreach ($face_points as $surface => $face_point) {
// Get all points for face
$points = array();
foreach ($data['surfaces'][$surface] as $edge) {
$points = array_merge($points, $data['edges'][$edge]);
}
$points = array_unique($points);

// Create new polygones
foreach ($points as $point) {
$this->_addPolygon(new Image_3D_Polygon(
$old_points[$point],
$edge_points[$point_edges[$point][0]],
$face_point,
$edge_points[$point_edges[$point][1]]
));
}
}

// Debug output
echo "\nFace points:\n";
foreach ($face_points as $point) echo $point, "\n";

echo "\nEdge points:\n";
foreach ($edge_points as $point) echo $point, "\n";

// Create polygones on new points
// @TODO: implement
echo "\nRepositioned points:\n";
foreach ($old_points as $point) echo $point, "\n";

echo "\nCreated polygones:\n";
foreach ($this->_polygones as $polygon) {
echo $polygon;
}
}
}
}

8 changes: 8 additions & 0 deletions Image/3D/Paintable/Polygon.php
Expand Up @@ -173,6 +173,14 @@ public function getMaxZ() {
foreach ($this->_points as $point) $z = max($point->getZ(), $z);
return $z;
}

public function __toString() {
$string = "Polygon:\n";
foreach ($this->_points as $point) {
$string .= "\t" . $point->__toString() . "\n";
}
return $string;
}
}

?>
2 changes: 1 addition & 1 deletion Image/3D/Point.php
Expand Up @@ -128,7 +128,7 @@ public function getColor() {
}

public function __toString() {
return sprintf('Point: %2.f %2.f %2.f', $this->_x, $this->_y, $this->_z);
return sprintf('Point: % 9.4f % 9.4f % 9.4f', $this->_x, $this->_y, $this->_z);
}
}

Expand Down
8 changes: 6 additions & 2 deletions docs/examples/quadcube.php
Expand Up @@ -10,8 +10,12 @@
$light->setColor(new Image_3D_Color(255, 255, 255));

$cube = $world->createObject('quadcube', array(150, 150, 150));
$cube->setColor(new Image_3D_Color(50, 50, 250, 150));
$cube->subdivisionSurfaces(1);
$cube->setColor(new Image_3D_Color(50, 50, 250, 200));

$cube_s = $world->createObject('quadcube', array(150, 150, 150));
$cube_s->subdivisionSurfaces(1);

$cube_s->setColor(new Image_3D_Color(50, 50, 250, 100));

$world->transform($world->createMatrix('Rotation', array(15, 15, 0)));

Expand Down

0 comments on commit 66c059f

Please sign in to comment.