Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Ground-based stations not placed on flat land #7

Closed
Brianetta opened this Issue · 14 comments

6 participants

@Brianetta
Owner

Original subject: Bentley Starport (Canqu [-2,-4]) is in wrong position.

Bentley Starport (Canqu [-2,-4]) is in wrong position. There is no possible to land in bay 2 due to collision with the planet surface. Alpha 9.01.

Logged by Mysibrat on SpaceSimCentral

@robn
Owner

The problem comes from the spaceports being placed at the desired latitude/longitude at the height of the terrain at that point. On a steep slope you end up with station embedded in the side of the hill. I think collision detection is disabled once the player is in the docking animation (ie when the pad is lowering), but it most certainly is not during the descent. If the pad is inside the mountain, the ship will crash.

A nasty hack solution would be to disable collision detection during the final descent, but that's rather game-breaking. A better solution would be to only place the entire station on flat ground, and walk outwards from the desired location until some is found. It does mean checking the entire base of the station though, not just a single point.

A further extension to this would be to have the station placement code instruct the terrain engine to force some flat terrain at that point - excavation works, if you will.

I have no idea how to make all these things happen sanely but as the terrains get more complicated it will need to be addressed in some fashion.

@s20dan

To further your idea rob, it may be possible to check the slope value of a specific point, in this case the center of the spaceport, which means you only need that small section to appear flat.
There may be a way of using the slope calculations from the colour fractals for this.....

@robn
Owner

A couple of screenshots to demonstrate the problem. The first is a station partially embedded in the terrain. This doesn't stop docking from happening (though its weird to pass through the terrain inside the dock with collisions disabled.

This shows the other side of the problem - stations can stick out of the terrain, making it possible to fly under them.

@Philbywhizz

I've had a look at this and it might be a little tricky to do.
Currently there is a Planet member function called GetTerrainHeight(vector3d) which returns the height at a certain point in space. What would be great would be a similar FlatTerrain (vector3d, radiusMin, radiusMax) which flattens the terrain at a given point with a random radius (so it isn't just a circle). I tried to do it, but got lost in Geosphere and Geospherestyles on how to do it. Perhaps someone else has an idea on this one.

@robn
Owner

The interface sounds right. I imagine its trickier around the edges as you don't want it to make a vertical cliff, but rather a gradual incline or something, so it needs to be hooked up to the terrain gen in some way. Or maybe you do want a cliff for a suitably cliffy terrain. Hmm.

It also occurs to me that you wouldn't necessarily want to level out a height-mapped body much/at all, and also completely flat might not always be the right thing - some amount of gentle slope might be acceptable.

Ping @s20dan. He's probably the only one that can tell you where the right places to hook are.

@s20dan

Hey I've been thinking about it somewhat, The best way might actually be to directly change the Noise settings (FracDef) based on proximity to a city. One way is to create a value that is always 1.0 unless near to a city, then it scales down to 0 the closer you get. You can multiply the lucanarity and frequency settings for all the main noise with that.

A function like the craters or volcanoes could do it too, but it would probbaly need this proximity valuie (0-1) to multiply the frequency with, otherwise your whole planet would be flat :)

Is starport information already present when we run GetTerrainHeight(vector3d) ? If it is then its no big deal to scale terrain by starport proximity.

@robn
Owner

Yes, starports are position when the system is created.

If I'm understanding correctly, this approach will still give some variation in the terrain at lower scaling values but it'll be more like "rolling hills" than "epic mountain ranges". I expect that would look quite natural, making this an excellent approach.

I assume then that we'd give GetTerrainHeight a second argument for the scaling factor?

Is there any risk that we'd still hard edges for canyons etc? ie can we guarantee that the land under the station/city will be "flat" with this approach?

@s20dan

Yeah you got it.. We would just scale the high frequency noise with this value, leaving the larger 'rolling hills' noise un-changed, so the area would appear flatter around the starport but not totally flat, it might be enough for it to work.

But you picked up on a valid point, it will remove canyons from the immediate vicinity in most cases. I say most cases, because there are several methods currently in-use for creating different styles of canyons and some would be un-affected unless we specifically wanted them to be.

I assume then that we'd give GetTerrainHeight a second argument for the scaling factor?

I don't think so, provided we can get the value 'distance from starport' then we can just multiply the numbers.
EDIT:// Actually your right, giving GetTerrainHeight another argument seems the best way.

EG:
case TERRAIN_MOUNTAINS_NORMAL:
{
SetFracDef(&m_fracdef[0], m_maxHeightInMeters, rand.Double(1e6, 1e7), rand, 10);
SetFracDef(&m_fracdef[1], m_maxHeightInMeters * 0.00000000001, 100.0, rand, 10);

Just add: m_maxHeightInMeters * m_starportDistance,

Or further down:

n += n * 1.25 * ridged_octavenoise(m_fracdef[6],
Clamp(h * 0.00002, 0.3, 0.7) *
ridged_octavenoise(m_fracdef[5], 0.5, p), p);

Change: Clamp(h * 0.00002 * m_starportDistance, 0.3, 0.7)

That will give flat land under the starport, but could give other unwanted features like too many cliffs, but I think its worth a try.
If you want to do it, create this distance to starport value and I can do the rest if you like.

@robn
Owner

So it seems we want to pass the distance through Planet::GetTerrainHeight to GeoSpherStyle::GetHeight. It can't be a member since its different for every point.

By the looks of it you want the distance to be 0.0-1.0 since its being used as a scaling factor? In that case I guess we want to define a maximum flattening area that can safely cover the starport and surrounding city. CityOnPlanet has the max radius as 5000m (via a define) so I guess we can say distance == 0 -> scaling == 0.0, distance >= 5000 -> scaling 1.0. Does that sound right>

I think to do this right we have to loop over all the surface starports on the planet and pass through the minimum of the distances from the wanted position to each starport. I can't see a better way since we don't really know where the starports are from just the height point. I don't think it has to be expensive.

@s20dan

That sounds great. Thats basically:
m_distance /= 5000.0;
m_distance = Clamp(m_distance, 0.0, 1.0);
Is that right?

It should work rather well, we can combine it with some forced flattening too if we really need to, but Im not sure the best way to work out the distance from multiple starports for a specific point.
Ae actually had some code he had wrote for region based patterns and colours which might possibly be adapted for this.... It was able to take a point on the surface and calculate its distance from any other point.

@robn
Owner

I think this:

scale = Clamp(distance, 0.0, 5000.0) / 5000.0

Clamp to the acceptable distance first, then divide down to get it to 0.0-1.0.

I'll go and learn some maths to see of there's a way to quickly find a useful midpoint of multiple vectors. Otherwise its just looping.

@robn robn was assigned
@jaj22 jaj22 referenced this issue from a commit in jaj22/pioneer
Ziusudra make attacker a per ship value (issue #7) 3b007e4
@jaj22 jaj22 referenced this issue from a commit in jaj22/pioneer
Ziusudra prevent traders from keeping each other at cowering status (issue #7) a218c83
@robn robn was assigned
@robn
Owner

Some stuff from Ae_ that I don't have brain to digest right now:

//starsystems.h
 pointers, vector of doubles called position on each body..std::vector is preffered as it ensures contiguous memory, regionType {double inner,double outer, int shape,blendtype,etc, double targetheight, bool valid} (a vector of structs), an int posIDX containing the parent position/region vector index for that starport

//starsystems.cpp



/*
 * Position a surface starport anywhere. Space.cpp::MakeFrameFor() ensures it
 * is on dry land (discarding this position if necessary)
 */
static void position_settlement_on_planet(SBody *b)
{
    MTRand r(b->seed);
    // used for orientation on planet surface
    double r2 = r.Double();     // function parameter evaluation order is implementation-dependent
    double r1 = r.Double();     // can't put two rands in the same expression
    b->orbit.rotMatrix = matrix4x4d::RotateZMatrix(2*M_PI*r1) *
            matrix4x4d::RotateYMatrix(2*M_PI*r2);


    vector3d p = b.orbit.rotMatrix*..see space cpp..(0,1,0);
    b->parent->positions.push_back(p); // add position to parents list
    regionTypes r; r.valid = 0; // set valid to 0
    b->parent->regionTypes.push_back(r);
    b->posIDX = b->parent->positions.size()-1; // position is at end of vector
}

//------------------------------------------------------------------------
//space.cpp

static Frame *MakeFrameFor(SBody *sbody, Body *b, Frame *f)
{

...


if (sbody->type == SBody::TYPE_SURFACE_STARPORT) {
...
if (planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius() <= 0.0) {
            MTRand r(sbody->seed);
            // position is under water. try some random ones
            for (tries=0; tries<100; tries++) {
                // used for orientation on planet surface
                double r2 = r.Double();     // function parameter evaluation order is implementation-dependent
                double r1 = r.Double();     // can't put two rands in the same expression
                rot = matrix4x4d::RotateZMatrix(2*M_PI*r1)
                    * matrix4x4d::RotateYMatrix(2*M_PI*r2);
                pos = rot * vector3d(0,1,0);
                height = planet->GetTerrainHeight(pos) - planet->GetSBody()->GetRadius();
                // don't want to be under water
                if (height > 0.0) break;
            }
        }
        b->SetPosition(pos * planet->GetTerrainHeight(pos));
        b->SetRotMatrix(rot);

        b->parent->regionTypes[b->posIDX].height = height;
        // the following should be moved elsewhere/done in more detail
        size = cos(citySize_m/(2*PI*b->parent->GetRadius()); // angle between city center/boundary = city size/(perimeter great circle = 2pi r)
        b->parent->regionTypes[b->posIDX].outer = size; // city center pos and current point will be dotted, and compared against size
        b->parent->regionTypes[b->posIDX].inner = 0.8*size;
        b->parent->regionTypes[b->posIDX].valid = true;

        return frame;
}
...


}

//------------------------------------------------------------------------
//geospherestyle.cpp


double GeoSphereStyle::GetHeight(const vector3d &p)
{

//std::vector <vector3d>::iterator i; 
//std::vector regionType::iterator r; // two vectors addressed so index is used instead
    for (int i = 0;i != m_Body.position.size(); i++)[ 
        if inside inner area return after checking region type is valid 
    } 

...

    case TERRAIN_HILLS_CRATERS:
    {


        ..
        old code inc return if zero
..


        for(int ii = 0; ii < m_Body->position.size();ii++){ //used for 2 vecs
        if inside outer area do a transition
        checking is just (*i).Dot(p) <= (*r).outer or element addressing in this case m_Body->position[ii]...

            if(..regionTypes[ii].valid){
                const double inner = m_Body->regionTypes[ii].inner;
                const double outer = m_Body->regionTypes[ii].outer;
                n = blend(m_Body->regionTypes[ii].height, n, m_Body->position[ii].Dot(p)/(outer-inner)); break; // blends from target height-terrain height as pos goes inner to outer
            }
        }


...
    n=(n>0.0)?:n:0.0;
    return n;
}

/* complex example
if inside region{
    if valid{
                       if r.type == 1 
                                 city flat terrain
        else if r.type == 2
            city terraced terrain..n = floor(n*40*planet radius)/planet radius //steps every 40m, needs building placement to run after setting regiontype
        else if r.type == 3 outdoor colony type setting n = log (n)/log (2)/colonywealth ;  //reduced contrast
        else if r.type == 4 crater using pos dot p as a type of radius (effects could be summed if using a separate height variable and not breaking)

        }
}         
*/


}
@gernot66

i can only congratulate to this decision,

usually i just worked around that issue (basements), but yes it's better to have a flattened terrain, even if i will miss the strange places then....

"chasch nüd beides ha, z'füferli und's weggli"

(you can't have everything)

@s20dan

#924 will solve this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.